用于 C++ 的通用 WebService (SOAP) 客户端库
我正在寻找一个可以轻松链接到我的应用程序的简单 C++ WebService 客户端库.
I'm looking for a simple C++ WebService Client Library that can be easily linked into my application.
最好是这个库:
- 可用于访问任何 SOAP WebService(因此我可以将 URL、WebService 名称、WebService 方法和所有参数作为参数传递给函数调用)
- 可以在 C++ 应用程序中静态链接(因此没有 DLL)
- 是免费软件或以低成本获得
- 可以在我的应用程序中免版税使用
- 可以查询 Web 服务的 WSDL 并向我返回可用的方法名称、方法的参数及其数据类型
在你们中的任何人回答 .NET 之前:去过那里,尝试一下.我对 .NET 的主要反对意见是:
Before anyone of you answers .NET: been there, tried it. My major objections against .NET are:
- 您可以生成代理,但之后无法在生成的代理代码中更改 WebService 名称,因为 .NET 使用反射来检查 WebService 名称(请参阅 从自己的脚本语言动态调用 SOAP 服务 对于我关于该问题的问题)
- 动态生成代理类似乎并不总是正常工作
- you can generate the proxy but it's impossible to change the WebService name in the generated proxy code afterwards, since .NET uses reflection to check the WebService name (see Dynamically call SOAP service from own scripting language for my question regarding that problem)
- generating the proxy class on the fly doesn't always seem to work correctly
我已经使用 Google 查找过此信息,但找不到.
I already used Google to look up this information, but I couldn't find one.
谢谢
为了进一步澄清这一点,我真的想要一些可以编写这样的代码(或类似风格的代码):
To clarify this further, I really want something where I can write code like this (or something in this 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);
没有动态代码生成.
推荐答案
我找到了一个使用动态生成的程序集的解决方案(我之前无法使用).起点是 http://refact.blogspot.com/2007_05_01_archive.html.
I found a solution using on-the-fly-generated assemblies (which I couldn't get working the previous time). Starting point is http://refact.blogspot.com/2007_05_01_archive.html.
例如这是使用 PeriodicTable 网络服务的代码:
E.g. This is the code to use the PeriodicTable web service:
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]
但实际上你当然会检查方法名称.在这个例子中,我得到了元素周期表中所有元素的名称,然后得到了氧的原子量.
In this code I explicitly use methods[0]
and methods[1]
but in reality you would check the method names of course. In this example I get the names of all elements in the periodic table, then get the atomic weight of oxygen.
此示例尚不包含支持代理的逻辑.我仍然需要添加这个,但目前,它解决了我最大的问题,即拥有一个通用的 SOAP 客户端.
This example does not yet contain logic to support a proxy. I still need to add this, but for the moment, it solves my biggest problem, namely, having a generic SOAP client.
我知道这段代码是 C# 并且我最初想要一个 C++ 解决方案,但是这段代码证明它可以在 .NET 环境中工作(我仍然可以在我的应用程序的有限部分中使用),我可能会将此代码改写为 C++/.NET,解决了我的问题.
I know this code is C# and I was originally asking for a C++ solution, but this code proves that it can work in a .NET environment (which I can still use in limited parts of my application), and I will probably rewrite this code into C++/.NET, which solves my problem.
相关文章