2010-11-26 39 views
12

Je suis à la recherche d'une simple bibliothèque client WebService C++ qui peut être facilement liée à mon application.Bibliothèque client générique WebService (SOAP) pour C++

De préférence, cette bibliothèque:

  • peut être utilisé pour accéder à tous les WebService SOAP (donc je peux passer l'URL, le nom WebService, la méthode WebService et tous les arguments comme arguments à un appel de fonction)
  • peuvent être liés statiquement dans une application C++ (donc pas de DLL)
  • est un logiciel gratuit ou disponible à un faible coût
  • peut être utilisé sans droits dans mon application
  • peut interroger le servic Web e pour son WSDL et me renvoyer les noms de méthodes disponibles, les arguments des méthodes et leurs types de données

Avant que quelqu'un d'entre vous répond .NET: été là, essayé. Mes principales objections contre .NET sont:

  • vous pouvez générer le proxy, mais il est impossible de changer le nom WebService dans le code proxy généré par la suite, étant donné que .NET utilise la réflexion pour vérifier le nom WebService (voir Dynamically call SOAP service from own scripting language pour ma question en ce qui concerne ce problème)
  • générer la classe proxy à la volée ne semble pas toujours fonctionner correctement

Je l'ai déjà utilisé Google pour rechercher cette information, mais je ne pouvais pas trouver un.

Merci

EDIT: Pour clarifier plus loin, je veux vraiment quelque chose où je peux écrire du code comme celui-ci (ou quelque chose dans ce style):

SoapClient mySoapClient; 
mySoapClient.setURL("http://someserver/somewebservice"); 
mySoapClient.setMethod("DoSomething"); 
mySoapClient.setParameter(1,"Hello"); 
mySoapClient.setParameter(2,12345); 
mySoapClient.sendRequest(); 
string result; 
mySoapClient.getResult(result); 

Aucune génération de code dynamique.

Répondre

4

J'ai trouvé une solution utilisant des assemblages générés à la volée (que je ne pouvais pas utiliser la fois précédente). Le point de départ est http://refact.blogspot.com/2007_05_01_archive.html.

E.g. Voici le code à utiliser le service Web PeriodicTable:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Web; 
using System.Web.Services; 
using System.Web.Services.Description; 
using System.CodeDom; 
using System.CodeDom.Compiler; 
using System.Xml.Serialization; 
using System.IO; 
using System.Reflection; 

namespace GenericSoapClient 
{ 
class Program 
    { 
    static void method1() 
     { 
     Uri uri = new Uri("http://www.webservicex.net/periodictable.asmx?WSDL"); 
     WebRequest webRequest = WebRequest.Create(uri); 
     System.IO.Stream requestStream = webRequest.GetResponse().GetResponseStream(); 

     // Get a WSDL 
     ServiceDescription sd = ServiceDescription.Read(requestStream); 
     string sdName = sd.Services[0].Name; 

     // Initialize a service description servImport 
     ServiceDescriptionImporter servImport = new ServiceDescriptionImporter(); 
     servImport.AddServiceDescription(sd, String.Empty, String.Empty); 
     servImport.ProtocolName = "Soap"; 
     servImport.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties; 

     CodeNamespace nameSpace = new CodeNamespace(); 
     CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); 
     codeCompileUnit.Namespaces.Add(nameSpace); 

     // Set Warnings 

     ServiceDescriptionImportWarnings warnings = servImport.Import(nameSpace, codeCompileUnit); 

     if (warnings == 0) 
      { 
      StringWriter stringWriter = 
       new StringWriter(System.Globalization.CultureInfo.CurrentCulture); 

      Microsoft.CSharp.CSharpCodeProvider prov = 
       new Microsoft.CSharp.CSharpCodeProvider(); 

      prov.GenerateCodeFromNamespace(nameSpace, 
       stringWriter, 
       new CodeGeneratorOptions()); 

      string[] assemblyReferences = 
       new string[2] { "System.Web.Services.dll", "System.Xml.dll" }; 

      CompilerParameters param = new CompilerParameters(assemblyReferences); 

      param.GenerateExecutable = false; 
      param.GenerateInMemory = true; 
      param.TreatWarningsAsErrors = false; 

      param.WarningLevel = 4; 

      CompilerResults results = new CompilerResults(new TempFileCollection()); 
      results = prov.CompileAssemblyFromDom(param, codeCompileUnit); 
      Assembly assembly = results.CompiledAssembly; 
      Type service = assembly.GetType(sdName); 

      //MethodInfo[] methodInfo = service.GetMethods(); 

      List<string> methods = new List<string>(); 

      // only find methods of this object type (the one we generated) 
      // we don't want inherited members (this type inherited from SoapHttpClientProtocol) 
      foreach (MethodInfo minfo in service.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) 
       { 
       methods.Add(minfo.Name); 
       Console.WriteLine (minfo.Name + " returns " + minfo.ReturnType.ToString()); 
       ParameterInfo[] parameters = minfo.GetParameters(); 
       foreach (ParameterInfo pinfo in parameters) 
        { 
         Console.WriteLine(" " + pinfo.Name + " " + pinfo.ParameterType.ToString()); 
        } 
       } 

      // Create instance of created web service client proxy 
      object obj = assembly.CreateInstance(sdName); 

      Type type = obj.GetType(); 

      object[] args0 = new object[] { }; 
      string result0 = (string)type.InvokeMember(methods[0], BindingFlags.InvokeMethod, null, obj, args0); 
      Console.WriteLine(result0); 

      object[] args1 = new object[] { "Oxygen" }; 
      string result1 = (string)type.InvokeMember(methods[1], BindingFlags.InvokeMethod, null, obj, args1); 
      Console.WriteLine(result1); 
      } 
     } 
    } 
} 

Dans ce code, j'utilise explicitement methods[0] et methods[1] mais en réalité vous vérifierais les noms des méthodes bien sûr. Dans cet exemple, j'obtiens les noms de tous les éléments du tableau périodique, puis le poids atomique de l'oxygène.

Cet exemple ne contient pas encore de logique pour prendre en charge un proxy. Je dois encore ajouter ceci, mais pour l'instant, cela résout mon plus gros problème, à savoir, avoir un client SOAP générique.

EDIT:

Je sais que ce code est C# et je demande à l'origine d'une solution C++, mais ce code prouve que cela peut fonctionner dans un environnement .NET (que je peux encore utiliser dans des zones limitées de mon application), et je vais probablement réécrire ce code en C++ /. NET, ce qui résout mon problème.

+0

C'est un bon point! Pensez-vous qu'il peut être porté vers l'environnement C++ Builder? Ou est-ce dépendant de .NET et de Reflection? – bluish

+0

@bluish, cela dépend vraiment de .Net. Le code utilise .Net pour générer la classe client, puis utilise le compilateur .Net C# pour le compiler et utilise la réflexion .Net pour appeler la classe. – Patrick

+3

Bien que je suis heureux que le problème de l'OP est résolu, je crois que cette réponse ne peut simplement pas être la réponse acceptée de cette question, car il est en C# alors que la question est spécifiquement sur C++ ... – zgyarmati

5

Avez-vous regardé gSOAP? Je pense que ce sera adapté à vos besoins.

http://gsoap2.sourceforge.net/

+1

Il semble que gSOAP génère du code CPP. Cela nécessite encore que je génère un code CPP spécifique au client. Ce que je veux, c'est une simple classe C++ (ou un ensemble de classes), où je peux simplement spécifier l'URL, le nom du service web, la méthode du service web et les arguments. – Patrick

+0

J'ai fait beaucoup de recherches sur les interfaces SOAP C++, et gSOAP est le meilleur. * soupir * Bonne chance! – Starkey

+1

Probablement gSOAP est le meilleur si vous connaissez le WSDL à l'avance. Mais que se passe-t-il si le nom, les méthodes et les arguments du service Web peuvent différer chez chaque client, et que je souhaite lire ces informations à partir d'un fichier de configuration et effectuer les appels en fonction du contenu du fichier de configuration? – Patrick

0

Axis2C: http://axis.apache.org/axis2/c/core/index.html

Axis2C tiques plus de ce qui précède, s'il vous plaît vérifier la liaison statique. .

EDIT: Selon les derniers messages de la liste, la liaison statique est incomplète. Ce qui suit est toujours valable:

Peut-être que je ne comprends pas la question correctement. Tout service Web que vous appelez doit spécifier l'URL du point de terminaison et les paramètres de l'opération &.

Faites-vous référence à la "découverte" dynamique des services & présentant l'option de les appeler ...? Si c'est le cas, je doute que cela soit possible.

Si vous faites référence à un framework générique, les messages SOAP sont la responsabilité finale du client de toute façon ...Vous ne devriez pas avoir de problème à les placer sous certaines API du kit d'outils. La génération de code WSDL n'est pas obligatoire. J'ai écrit quelques services à partir de zéro, c'est-à-dire que vous pouvez définir le point de terminaison, le service et créer le message SOAP, les paramètres, les en-têtes, etc.

À la votre!

+1

Pourriez-vous s'il vous plaît poster un exemple (ou des liens vers celui-ci)? – bluish