消费,并在运行时调用SOAP Web服务 - 从WSDL文件中的动态Web服务客户端 [英] Consume and Invoke SOAP WebServices at Runtime - Dynamic Web Service client from WSDL file

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

问题描述

要求:


  1. 客户给SOAP的Web服务的WSDL在运行时即挑选从文件共享位置的WSDL文件。

  2. 消费WSDL,并调用由客户在用户界面上选择的方法和处理响应。

我不能使用MetadataExchangeClient作为WSDL将不会被托管。

实施

  VAR serviceDescription = ServiceDescription.Read(@C:\\ Contacts.WSDL);
VAR metadataSection =新MetadataSection
{
方言= MetadataSection.ServiceDescriptionDialect,
标识符= serviceDescription.TargetNamespace,
元数据= serviceDescription
};VAR metadataSections =新的List< MetadataSection> {} metadataSection;
VAR metadatSet =新MetadataSet(metadataSections);
VAR wsdlImporter =新WsdlImporter(metadatSet);
VAR的服务= wsdlImporter.ImportAllEndpoints();

路障:


  1. 上面code都无法提取服务端点。所以,我不得不手动创建一个服务端点。

  2. 我无法列出包含在以上WSDL中的所有方法和其相关的输入/输出在步骤(将在变量operationName及以下operationParameters使用)


 对象retVal的= instance.GetType()。实现getMethod(operationName)
                        .Invoke(例如,operationParameters); //调用


我试图通过硬编码的操作名称,从WSDL手动解析,但随后未能在参​​数。该公司预计,包含如下层次的复杂类型:


  

ContactInput - > ListOfContacts - >联系人 - >名字,姓氏


下一步:

如果有人可以帮助我解决了路障,那么我可以用上面的办法进行。

否则,我开始研究如何使用svcutil.exe的在运行时

谢谢,
开发


解决方案

有是这样做的这篇文章中描述的解决方案:

生成代理code为Web服务动态

虽然您可以打开该链接,阅读它,我包括code在这里,以防万一链接随时死亡:


  

此方法返回Web服务公开操作的列表。我已经使用ServiceDescription来实现,由于我不能只反映从生成assmebly Web方法的名称。与保持可用的操作名,全部是找出输入和每个方法返回参数


 公共字符串[] GenerateProxyAssembly()
{
  //创建一个WebRequest对象并获取WSDL文件的Web服务
  HttpWebRequest的要求=(HttpWebRequest的)HttpWebRequest.Create(this.uri);
  request.Credentials = CredentialCache.DefaultCredentials;
  HttpWebResponse响应=(HttpWebResponse)request.GetResponse();
  的System.IO.Stream流= response.GetResponseStream();  //读取下载的WSDL文件
  ServiceDescription DESC = ServiceDescription.Read(流);  //找出由Web服务公开的操作数
  //存储操作的名称的字符串数组内
  //迭代仅通过第一结合暴露为
  //绑定的其余部分将具有相同数量的
  INT I = 0;
  约束力181 = desc.Bindings [0];
  OperationBindingCollection opColl = binding.Operations;
  的foreach(在opColl OperationBinding操作)
  {
    listOfOperations [我++] = operation.Name;
  }  //初始化ServiceDescriptionImporter对象
  ServiceDescriptionImporter进口商=新ServiceDescriptionImporter();  //设置协议SOAP 1.1
  importer.ProtocolName =SOAP12;  //样式设置为客户端,以生成客户端代理code
  importer.Style = ServiceDescriptionImportStyle.Client;  //添加和serviceDescription的进口商对象
  importer.AddServiceDescription(DESC,NULL,NULL);
  进口商codeGenerationOptions = codeGenerationOptions.GenerateNewAsync。  //初始化code DOM树中,我们将导入
  // ServiceDescriptionImporter
  codeNamespace纳米=新的codeNamespace();
  codeCompileUnit单位=新的codeCompileUnit();
  unit.Namespaces.Add(NM);  //生成客户端代理code
  ServiceDescriptionImportWarnings警告= importer.Import(NM,股吧);  如果(警告== 0)
  {
    //设置codeDOMProvider到C#生成C#中的code
    System.IO.StringWriter SW =新System.IO.StringWriter();
    codeDomProvider提供商= codeDomProvider.CreateProvider(C#);
    provider.Generate codeFromCompileUnit(单位,SW,新的codeGeneratorOptions());    //创建TempFileCollection
    // temp文件夹的路径是硬codeD
    TempFileCollection科尔=新TempFileCollection(@C:\\ wmpub \\临时文件);
    coll.KeepFiles = FALSE;    //设置临时组装CompilerParameters
    字符串[] = refAssembly {System.dll中,System.Data.dll中
      System.Web.Services.dll,system.xml.dll的};
    CompilerParameters参数=新CompilerParameters(refAssembly);
    param.GenerateInMemory = TRUE;
    param.TreatWarningsAsErrors = FALSE;
    param.OutputAssembly =WebServiceReflector.dll;
    param.TempFiles =科尔;    //编译生成的code到装配体
    // CompilerResults结果= provider.CompileAssemblyFromDom(参数,unitArr);
    CompilerResults结果
       = provider.CompileAssemblyFromSource(参数,sw.ToString());
    this.assem = results.CompiledAssembly;
  }  //返回由Web服务公开操作的列表
  返回listOfOperations;
}


  

这个方法返回的ParameterInfo []列表中的输入参数。为了得到输出参数,只需更换与ReturnParameter属性MethodInfo的类调用GetParamters(),把一个新的方法中。把这些3种方法一个dll内,从任何客户端应用程序,将其添加引用。就这样。只需提供网址和使用Web服务,任何Web服务。你不必去通过要消耗一个新的Web服务,每次创建代理文件的过程。


 公共信息参数[] ReturnInputParameters(字符串methodName中)
{
  //创建Web服务类型的一个实例
  //////////////去做/////////////////////////
  //从WSDL获得的Web服务的名称动态
  对象o = this.assem.CreateInstance(服务);
  服务类型= o.GetType();
  的ParameterInfo [] paramArr = NULL;  //获取的所有公共方法生成的装配//可用列表
  MethodInfo的[] infoArr = service.GetMethods();  的foreach(在infoArr MethodInfo的信息)
  {
  //获取该输入参数信息
  //所需的Web方法
    如果(methodName.Equals(info.Name))
    {
      paramArr = info.GetParameters();
    }
  }  返回paramArr;
}

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

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 Web服务 - 从WSDL文件中的动态Web服务客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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