2010-08-11 45 views
1

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

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

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

对我而言,从长远来看,第三种选择是最好的,因为它允许我的顾问同事通过我的脚本语言调用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])); 
} 

Web服务的URL可以通过设置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属性(例如GetPrimo)中的Web服务名称也会导致相同的错误。

因此,我的问题:

  • 是否有意义继续这条道路,即在看WSDL生成逻辑试图“推广”调用一个(有)SOAP服务或将这种简单从不工作?
  • 是否有任何其他好方法以动态方式生成SOAP调用(使用.Net)?
  • 或者是您自己创建XML(SOAP信封)来执行SOAP调用的唯一方法?
  • 有没有机会找到一些我可以继续使用的示例代码?

由于提前, 帕特里克

回答

1

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

这不仅允许客户拨打外部网络服务,还可以用于许多其他增强功能。如果你不想依赖你的客户编写.NET程序集,你可以通过询问用户的SOAP消息名称,参数名称,它们的类型和值,服务URL等来自己生成SOAP请求。但是我认为这不是一条容易的道路,我承认我从来没有做过。

+0

我也想过这个想法,但我不想这有几个原因:我不想将我的顾问与另一种客户特定事务的语言混淆,我想阻止我的顾问做很多花哨的事情,但是一旦他们可以使用C#就会产生不必要的事情(这将成为一场噩梦为了支持)。我真的想限制它从我的脚本语言到Web服务的呼叫。 – Patrick 2010-08-11 08:04:46

+0

Hemant,我再次给你的想法一个想法,并给予所有与Microsoft调用Webservices的方式有关的问题(他们甚至依赖于你的类的方法与Web服务方法相同的事实,yuck),我认为这仍然是一个好主意,它甚至可能会打开其他的可能性。现在我决定阻止我的顾问在C#中编写客户特定的代码,并且仅限于客户提供的.Net程序集和WSDL生成的WebService代理。谢谢。 – Patrick 2010-08-11 13:10:35

0

不知道脚本语言的功能很难回答。

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

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

也许类似Managed Extensibility Framework (or MEF for short)也可以为你工作。

1

您可以尝试使用编译器中的内置版即时生成动态代码。
无论是从直接代码(使用代码提供商等http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider.aspx)或通过直接构建类(参见 http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider.aspx的示例)

生成的代码可以以几种方式来完成:

+0

好主意。你如何建议编写代理类?通过C++自己生成,使用WSDL实用程序在客户中生成它,还是可以使用基于我的应用程序中的WSDL URL的.Net类生成? – Patrick 2010-08-11 08:57:45

+0

查看我的更新答案 – eli 2010-08-11 09:26:17