在运行时使用和调用

在运行时使用和调用

本文介绍了在运行时使用和调用 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)

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 :

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:

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;
}
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 服务客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 00:21