在运行时使用和调用SOAP WebServices – 来自WSDL文件的动态Web服务客户端

需求:

  1. 客户在运行时提供SOAP Web服务的WSDL,即从文件共享位置选择WSDL文件。
  2. 使用WSDL,并在UI上调用Customer选择的Method并处理响应。

我无法使用MetadataExchangeClient,因为不会托管WSDL。

执行:

var serviceDescription = ServiceDescription.Read(@"C:\Contacts.WSDL"); var metadataSection = new MetadataSection { Dialect = MetadataSection.ServiceDescriptionDialect, Identifier = serviceDescription.TargetNamespace, Metadata = serviceDescription }; var metadataSections = new List {metadataSection}; var metadatSet = new MetadataSet(metadataSections); var wsdlImporter = new WsdlImporter(metadatSet); var services = wsdlImporter.ImportAllEndpoints(); 

路障:

  1. 上面的代码根本无法提取服务端点。 所以,我不得不手动创建一个服务端点。
  2. 我无法在步骤中列出上述WSDL中包含的所有方法及其关联的输入/输出(将在下面的变量operationName和operationParameters中使用)
 object retVal = instance.GetType().GetMethod(operationName) .Invoke(instance, operationParameters); // Invoke 

我尝试通过硬编码操作名称,手动从WSDL解析,但随后它在参数上失败了。 它期望包含层次结构的复杂类型如下:

ContactInput – > ListOfContacts – > Contact – > FirstName,LastName

下一步:

如果有人可以帮我解决障碍,那么我可以继续上述方法。

否则,我必须开始研究在运行时使用svcutil.exe

谢谢,开发

有一个解决方案可以执行本文中描述的操作:

动态生成Web服务的代理代码

虽然您可以打开该链接并阅读它,但我在此处包含代码,以防链接在任何时候死亡:

此方法返回Web服务公开的操作列表。 我已经使用ServiceDescription实现了这一点,因为我无法仅反映生成的Web方法名称。 使用可用的操作名称,剩下的就是找出每种方法的输入和返回参数。

 public string[] GenerateProxyAssembly() { //create a WebRequest object and fetch the WSDL file for the web service HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(this.uri); request.Credentials = CredentialCache.DefaultCredentials; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); System.IO.Stream stream = response.GetResponseStream(); //read the downloaded WSDL file ServiceDescription desc = ServiceDescription.Read(stream); //find out the number of operations exposed by the web service //store the name of the operations inside the string array //iterating only through the first binding exposed as //the rest of the bindings will have the same number int i = 0; Binding binding = desc.Bindings[0]; OperationBindingCollection opColl = binding.Operations; foreach (OperationBinding operation in opColl) { listOfOperations[i++] = operation.Name; } //initializing a ServiceDescriptionImporter object ServiceDescriptionImporter importer = new ServiceDescriptionImporter(); //set the protocol to SOAP 1.1 importer.ProtocolName = "Soap12"; //setting the Style to Client in order to generate client proxy code importer.Style = ServiceDescriptionImportStyle.Client; //adding the ServiceDescription to the Importer object importer.AddServiceDescription(desc, null, null); importer.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync; //Initialize the CODE DOM tree in which we will import the //ServiceDescriptionImporter CodeNamespace nm = new CodeNamespace(); CodeCompileUnit unit = new CodeCompileUnit(); unit.Namespaces.Add(nm); //generating the client proxy code ServiceDescriptionImportWarnings warnings = importer.Import(nm, unit); if (warnings == 0) { //set the CodeDOMProvider to C# to generate the code in C# System.IO.StringWriter sw = new System.IO.StringWriter(); CodeDomProvider provider = CodeDomProvider.CreateProvider("C#"); provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions()); //creating TempFileCollection //the path of the temp folder is hardcoded TempFileCollection coll = new TempFileCollection(@"C:\wmpub\tempFiles"); coll.KeepFiles = false; //setting the CompilerParameters for the temporary assembly string[] refAssembly = { "System.dll", "System.Data.dll", "System.Web.Services.dll", "System.Xml.dll" }; CompilerParameters param = new CompilerParameters(refAssembly); param.GenerateInMemory = true; param.TreatWarningsAsErrors = false; param.OutputAssembly = "WebServiceReflector.dll"; param.TempFiles = coll; //compile the generated code into an assembly //CompilerResults results = provider.CompileAssemblyFromDom(param, unitArr); CompilerResults results = provider.CompileAssemblyFromSource(param, sw.ToString()); this.assem = results.CompiledAssembly; } //return the list of operations exposed by the web service return listOfOperations; } 

此方法返回ParameterInfo []列表中的输入参数。 要获取输出参数,只需使用ReturnParameter属性替换对MethodInfo类的GetParamters()的调用,并将其放入新方法中。 将这3个方法放在dll中,并从任何客户端应用程序添加对它的引用。 就这样。 只需提供URL并使用Web服务,任何Web服务。 每次要使用新的Web服务时,都不必执行创建代理文件的过程。

 public ParameterInfo[] ReturnInputParameters(string methodName) { //create an instance of the web service type //////////////to do///////////////////////// //get the name of the web service dynamically from the wsdl Object o = this.assem.CreateInstance("Service"); Type service = o.GetType(); ParameterInfo[] paramArr = null; //get the list of all public methods available in the generated //assembly MethodInfo[] infoArr = service.GetMethods(); foreach (MethodInfo info in infoArr) { //get the input parameter information for the //required web method if (methodName.Equals(info.Name)) { paramArr = info.GetParameters(); } } return paramArr; }