在运行时使用和调用 SOAP WebServices - 来自 WSDL 文件的动态 Web 服务客户端 [英] Consume and Invoke SOAP WebServices at Runtime - Dynamic Web Service client from WSDL file

查看:17
本文介绍了在运行时使用和调用 SOAP WebServices - 来自 WSDL 文件的动态 Web 服务客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要求:

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

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

实施:

var serviceDescription = ServiceDescription.Read(@"C:Contacts.WSDL");var metadataSection = 新的 MetadataSection{方言 = MetadataSection.ServiceDescriptionDialect,标识符 = serviceDescription.TargetNamespace,元数据 = 服务描述};var metadataSections = new List{元数据部分};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);//调用

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

<块引用>

ContactInput --> ListOfContacts --> Contact --> FirstName, LastName

后续步骤:

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

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

谢谢,开发

解决方案

本文描述了一个解决方案:

动态生成网络服务的代理代码

尽管您可以打开该链接并阅读它,但我在此处包含了代码,以防该链接随时失效:

<块引用>

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

public string[] GenerateProxyAssembly(){//创建一个 WebRequest 对象并获取 Web 服务的 WSDL 文件HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(this.uri);request.Credentials = CredentialCache.DefaultCredentials;HttpWebResponse 响应 = (HttpWebResponse)request.GetResponse();System.IO.Stream 流 = response.GetResponseStream();//读取下载的WSDL文件ServiceDescription desc = ServiceDescription.Read(stream);//找出web服务暴露的操作数//将操作的名称存储在字符串数组中//仅迭代暴露为的第一个绑定//其余的绑定将具有相同的编号int i = 0;绑定绑定 = desc.Bindings[0];OperationBindingCollection opColl = binding.Operations;foreach(opColl 中的操作绑定操作){listOfOperations[i++] = operation.Name;}//初始化一个ServiceDescriptionImporter对象ServiceDescriptionImporter importer = new ServiceDescriptionImporter();//设置协议为SOAP 1.1importer.ProtocolName = "Soap12";//将Style设置为Client以生成客户端代理代码importer.Style = ServiceDescriptionImportStyle.Client;//将ServiceDescription添加到Importer对象importer.AddServiceDescription(desc, null, null);importer.CodeGenerationOptions = CodeGenerationOptions.GenerateNewAsync;//初始化 CODE DOM 树,我们将在其中导入//服务描述导入器代码命名空间 nm = 新代码命名空间();CodeCompileUnit unit = new CodeCompileUnit();unit.Namespaces.Add(nm);//生成客户端代理代码ServiceDescriptionImportWarnings 警告 = importer.Import(nm, unit);如果(警告== 0){//将CodeDOMProvider设置为C#以生成C#中的代码System.IO.StringWriter sw = new System.IO.StringWriter();CodeDomProvider provider = CodeDomProvider.CreateProvider(C#");provider.GenerateCodeFromCompileUnit(unit, sw, new CodeGeneratorOptions());//创建临时文件集合//临时文件夹的路径是硬编码的TempFileCollection coll = new TempFileCollection(@"C:wmpub	empFiles");coll.KeepFiles = false;//设置临时程序集的CompilerParametersstring[] 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;//将生成的代码编译成程序集//CompilerResults results = provider.CompileAssemblyFromDom(param, unitArr);CompilerResults 结果= provider.CompileAssemblyFromSource(param, sw.ToString());this.assem = results.CompiledAssembly;}//返回Web服务公开的操作列表返回列表操作;}

<块引用>

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

public ParameterInfo[] ReturnInputParameters(string methodName){//创建Web服务类型的实例//////////////去做///////////////////////////从wsdl动态获取web服务的名称Object o = this.assem.CreateInstance(服务");类型服务 = o.GetType();参数信息[] paramArr = null;//获取生成的//程序集中所有可用公共方法的列表MethodInfo[] infoArr = service.GetMethods();foreach(infoArr 中的 MethodInfo 信息){//获取输入参数信息//需要的网络方法if (methodName.Equals(info.Name)){paramArr = info.GetParameters();}}返回参数Arr;}

Requirement:

  1. Customer to give the SOAP Web-service's WSDL at runtime i.e pick the WSDL file from a file share location.
  2. Consume the WSDL, and call the Method chosen by the Customer on the UI and handle the response.

I cannot use the MetadataExchangeClient as the WSDL will not be hosted.

Implementation:

var serviceDescription = ServiceDescription.Read(@"C:Contacts.WSDL");
var metadataSection = new MetadataSection
{
Dialect = MetadataSection.ServiceDescriptionDialect,
Identifier = serviceDescription.TargetNamespace,
Metadata = serviceDescription
};

var metadataSections = new List<MetadataSection> {metadataSection};
var metadatSet = new MetadataSet(metadataSections);
var wsdlImporter = new WsdlImporter(metadatSet);
var services = wsdlImporter.ImportAllEndpoints();

Road Blocks:

  1. The above code could not extract the service endpoints at all. So, I had to manually create an service endpoint.
  2. I could not list out all the methods contained in the above WSDL and its associated Inputs/Outputs in the step (to be used in the variable operationName and operationParameters below)

object retVal = instance.GetType().GetMethod(operationName)
                        .Invoke(instance, operationParameters);   // Invoke

I tried by hard coding the operation name, manually parsed from the WSDL, but then it failed at the parameters. It's expecting a complex type containing the hierarchy as below :

ContactInput --> ListOfContacts --> Contact --> FirstName, LastName

Next Steps:

If someone could help me fix the roadblocks, then I can proceed with the above approach.

Else, I have to start researching on using the svcutil.exe at runtime

Thanks, Dev

解决方案

There is a solution for doing this described in this article:

Generate proxy code for a web service dynamically

Although you can open that link and read it, I include the code here, just in case that link dies anytime:

This method returns the list of operations exposed by the web service. I have used ServiceDescription to achieve that as I was not able to reflect only the web method names from the generated assmebly. With the operation names available, all that remains is to find out the input and return parameters for each method.

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	empFiles");
    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;
}

This method returns the input parameters in ParameterInfo[] list. To get the output parameter, just replace the call to GetParamters() on MethodInfo class with ReturnParameter property and put that inside a new method. Put these 3 methods inside a dll and add a reference to it from any client application. That's all. Just provide the URL and consume the web service, any web service. You don't have to go through the procedure of creating a proxy file every time you want to consume a new web service.

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;
}

这篇关于在运行时使用和调用 SOAP WebServices - 来自 WSDL 文件的动态 Web 服务客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆