Универсальная клиентская библиотека WebService (SOAP) для C ++ - PullRequest
14 голосов
/ 26 ноября 2010

Я ищу простую клиентскую библиотеку C ++ WebService, которую можно легко связать с моим приложением.

Предпочтительно эта библиотека:

  • может использоваться для доступа к любому SOAP WebService (поэтому я могу передать URL, имя WebService, метод WebService и все аргументы в качестве аргументов для вызова функции)
  • может быть статически связано в приложении C ++ (поэтому нет DLL)
  • бесплатен или доступен по низкой цене
  • можно использовать без лицензионных платежей в моем приложении
  • может запросить у Web-сервиса его WSDL и вернуть мне доступные имена методов, аргументы методов и их типы данных

Прежде чем кто-либо из вас ответит .NET: был там, попробовал. Мои основные возражения против .NET:

  • вы можете сгенерировать прокси, но потом невозможно изменить имя WebService в сгенерированном коде прокси, поскольку .NET использует отражение для проверки имени WebService (см. Динамический вызов службы SOAP из собственного языка сценариев для мой вопрос по этой проблеме)
  • генерация прокси-класса на лету не всегда работает правильно

Я уже использовал Google для поиска этой информации, но не смог ее найти.

Спасибо

EDIT: Чтобы пояснить это далее, я действительно хочу что-то, где я мог бы написать код, подобный этому (или что-то в этом стиле):

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);

Нет динамической генерации кода.

Ответы [ 3 ]

6 голосов
/ 26 ноября 2010

Вы смотрели на gSOAP? Я думаю, что это подойдет для ваших нужд.

http://gsoap2.sourceforge.net/

4 голосов
/ 29 ноября 2010

Я нашел решение с использованием сборок на лету (которые я не мог заставить работать в прошлый раз).Начальная точка: http://refact.blogspot.com/2007_05_01_archive.html.

Например, это код для использования веб-службы 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);
            }
        }
    }
}

В этом коде я явно использую methods[0] и methods[1], но на самом деле выбудет проверять имена методов, конечно.В этом примере я получаю имена всех элементов в периодической таблице, затем получаю атомный вес кислорода.

В этом примере еще нет логики для поддержки прокси.Мне все еще нужно добавить это, но на данный момент это решает мою самую большую проблему, а именно, имеет общий клиент SOAP.

РЕДАКТИРОВАТЬ:

Я знаю этот кодэто C #, и я изначально запрашивал решение C ++, но этот код доказывает, что он может работать в среде .NET (которую я все еще могу использовать в ограниченных частях моего приложения), и я, вероятно, переписываю этот код в C ++ /.NET, который решает мою проблему.

1 голос
/ 26 ноября 2010

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

Axis2C отмечает большинство из вышеперечисленных, пожалуйста, проверьте статическое связывание. .

РЕДАКТИРОВАТЬ: Согласно последним нескольким сообщениям в списке, статическое связывание является неполным. Ниже все еще имеет место:

Возможно, я не правильно понял вопрос. Любой веб-сервис, которому вы звоните, должен указывать URL-адрес конечной точки, а также операции и параметры.

Вы имеете в виду динамическое «обнаружение» услуг и предоставление возможности их вызова ...? Если так, то я сомневаюсь, что это возможно.

Если вы имеете в виду универсальную платформу, сообщения SOAP в любом случае являются ответственностью клиента. У вас не должно быть проблем с обертыванием их в некоторые API инструментария. Генерация кода WSDL не является обязательной. Я написал несколько сервисов с нуля, то есть вы можете настроить конечную точку, обслуживать и создавать SOAP-сообщение, параметры, заголовки и т. Д. По своему усмотрению.

ура!

...