我的应用程序有自己的脚本语言,我无法摆脱(大量客户特定的脚本)。现在我的客户问是否可以从该脚本语言中调用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调用的唯一方法?
- 有没有机会找到一些我可以继续使用的示例代码?
由于提前, 帕特里克
我也想过这个想法,但我不想这有几个原因:我不想将我的顾问与另一种客户特定事务的语言混淆,我想阻止我的顾问做很多花哨的事情,但是一旦他们可以使用C#就会产生不必要的事情(这将成为一场噩梦为了支持)。我真的想限制它从我的脚本语言到Web服务的呼叫。 – Patrick 2010-08-11 08:04:46
Hemant,我再次给你的想法一个想法,并给予所有与Microsoft调用Webservices的方式有关的问题(他们甚至依赖于你的类的方法与Web服务方法相同的事实,yuck),我认为这仍然是一个好主意,它甚至可能会打开其他的可能性。现在我决定阻止我的顾问在C#中编写客户特定的代码,并且仅限于客户提供的.Net程序集和WSDL生成的WebService代理。谢谢。 – Patrick 2010-08-11 13:10:35