在运行时使用和调用 SOAP Web 服务 - 从 WSDL 文件使用和调用动态 Web 服务客户端

本文关键字:调用 服务 Web 文件 客户端 WSDL 动态 SOAP 运行时 | 更新日期: 2023-09-27 18:32:14

要求:

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

我无法使用 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> {metadataSection};
var metadatSet = new MetadataSet(metadataSections);
var wsdlImporter = new WsdlImporter(metadatSet);
var services = wsdlImporter.ImportAllEndpoints();

路障:

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

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

联系人输入 -->联系人列表 -->联系人 -->名字、姓氏

后续步骤:

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

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

谢谢开发

在运行时使用和调用 SOAP Web 服务 - 从 WSDL 文件使用和调用动态 Web 服务客户端

本文中描述了执行此操作的解决方案:

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

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

此方法返回 Web 服务公开的操作列表。我使用服务描述来实现这一点,因为我无法仅反映生成的 assmeb 中的 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;
}

此方法返回参数信息[] 列表中的输入参数。要获取输出参数,只需将 MethodInfo 类上对 GetParamters() 的调用替换为 ReturnParameter 属性,并将其放入新方法中。将这 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;
}