1

我的应用程序有自己的脚本语言,我无法摆脱它(编写了大量客户特定的脚本)。现在我的客户询问是否可以从该脚本语言中调用 SOAP 服务。当然,每个客户需要调用的 SOAP 服务会有所不同。这给我留下了几个选择:

  • 使用 WSDL 实用程序生成特定于客户的 SOAP 客户端代理并将特定于客户的逻辑放入我的应用程序中
  • 使用 WSDL 实用程序生成特定于客户的 SOAP 客户端代理,将特定于客户的逻辑放入特定于客户的 DLL 中,并预见一个插件系统,应用程序可以在其中以通用方式调用插件
  • 编写一个动态生成 SOAP 调用的通用模块

在我的情况下,前两个选项不是真正的选择,因为我不希望应用程序中有任何客户特定的逻辑或客户特定的 DLL。

对我来说,从长远来看,第 3 个选项是最好的,因为它允许我的顾问同事通过我的脚本语言调用 SOAP 服务,而无需进行任何客户特定的开发。向我的脚本语言动态添加函数不是问题,生成动态 SOAP 调用是问题。

我首先查看了 WSDL 实用程序的输出。然后我开始删除东西,直到它不再起作用。以下代码仍然有效:

[System::CodeDom::Compiler::GeneratedCodeAttribute(L"wsdl", L"4.0.30319.1"), 
System::Diagnostics::DebuggerStepThroughAttribute, 
System::ComponentModel::DesignerCategoryAttribute(L"code"),
System::Web::Services::WebServiceBindingAttribute(Name=L"MyOwnScriptingSoapClient", Namespace=L"http://microsoft.com/webservices/")]
public ref class MyWebService : public System::Web::Services::Protocols::SoapHttpClientProtocol
   {
    public:
      MyWebService() {}

    public:
      [System::Web::Services::Protocols::SoapDocumentMethodAttribute(L"http://microsoft.com/webservices/GetPrimeNumbers", RequestNamespace=L"http://microsoft.com/webservices/", 
       ResponseNamespace=L"http://microsoft.com/webservices/", Use=System::Web::Services::Description::SoapBindingUse::Literal, ParameterStyle=System::Web::Services::Protocols::SoapParameterStyle::Wrapped)]
      System::String^  GetPrimeNumbers(System::Int32 max);
  };

inline System::String^  MyWebService::GetPrimeNumbers(System::Int32 max) {
    cli::array< System::Object^  >^  results = this->Invoke(L"GetPrimeNumbers", gcnew cli::array< System::Object^  >(1) {max});
    return (cli::safe_cast<System::String^  >(results[0]));
}

通过设置 Url 属性可以动态地设置 Web 服务的 URL,但是我找不到使方法名称动态的方法。

添加这样的通用方法似乎仍然有效:

...
[System::Web::Services::Protocols::SoapDocumentMethodAttribute(L"http://microsoft.com/webservices/GetPrimeNumbers", RequestNamespace=L"http://microsoft.com/webservices/", 
 ResponseNamespace=L"http://microsoft.com/webservices/", Use=System::Web::Services::Description::SoapBindingUse::Literal, ParameterStyle=System::Web::Services::Protocols::SoapParameterStyle::Wrapped)]
cli::array< System::Object^  >^  CallWs(cli::array< System::Object^  >^ args);
...

inline cli::array< System::Object^  >^  MyWebService::CallWs(cli::array< System::Object^  >^ args) {
    cli::array< System::Object^  >^  results = this->Invoke(L"GetPrimeNumbers", args);
    return results;

但是一旦我删除 GetPrimeNumbers 方法,调用就不再起作用并报告以下错误:

Unhandled Exception: System.ArgumentException: GetPrimeNumbers Web Service method name is not valid.
   at System.Web.Services.Protocols.SoapHttpClientProtocol.BeforeSerialize(WebRequest request, String methodName, Object[] parameters)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at MyWebService.CallWs(Object[] args)
   at main(Int32 argc, SByte** argv)
   at _mainCRTStartup()

此外,更改 SoapDocumentMethodAttribute 属性中的 Web 服务名称(例如,更改为 GetPrimo)也会产生同样的错误。

因此,我的问题:

  • 继续走这条路是否有意义,即查看 WSDL 生成的逻辑试图“概括”对(任何)SOAP 服务的调用,或者这根本不会起作用?
  • 还有其他以动态方式(使用.Net)生成 SOAP 调用的好方法吗?
  • 或者是自己创建 XML(Soap Envelope)以进行 SOAP 调用的唯一方法?
  • 有没有机会找到一些我可以继续工作的示例代码?

在此先感谢,帕特里克

4

3 回答 3

1

您可以在脚本语言中提供一种机制来调用外部 .NET 程序集。您可以使用反射来查找函数并调用它们。类似于插件在许多应用程序中的工作方式。

这不仅允许客户调用外部 Web 服务,还可以用于许多其他增强功能。

或者,如果您不想依赖客户编写 .NET 程序集,您可以通过询问用户 SOAP 消息名称、参数名称、它们的类型和值、服务 URL 等来自己生成 SOAP 请求。但我认为不是这将是一条简单的道路,我承认我自己从来没有做过。

于 2010-08-11T07:59:03.950 回答
1

您可以尝试使用内置编译器动态生成动态代码。
直接来自代码(使用像http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx这样的代码提供程序)或直接构建类(参见 http://msdn.microsoft. com/en-us/library/system.codedom.compiler.codedomprovider.aspx为例)

可以通过多种方式生成代码:

  • 手动生成代码(在 C++ 中)
  • 环绕wsdl.exe。可能会很棘手,因为我认为您不允许分发 exe,您的客户必须下载 SDK。
  • 像这个人那样实现一些类似 WSDL 的功能:http ://www.west-wind.com/Weblog/posts/625014.aspx
  • 使用为您做同样事情的库:http ://www.wcfstorm.com/wcf/home.aspx (商业)
于 2010-08-11T08:46:57.777 回答
0

如果不知道您的脚本语言的功能,这很难回答。

一个想法可能是用另一种语言创建更强大的服务,该服务具有工厂模式来调用相关的客户服务并以非客户特定的格式返回到您的脚本信息。

当然,这是假设您可以首先从您的域特定脚本语言调用另一个程序。

也许像Managed Extensibility Framework(或简称 MEF)这样的东西也可以为您工作。

于 2010-08-11T08:01:50.000 回答