Web Service学习笔记:动态调用WebService

时间:2023-02-24 19:35:05

多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我们可能需要在程序运行期间动态调用一个未知的服务。在 .NET Framework 的 System.Web.Services.Description 命名空间中有我们需要的东西。

具体步骤:

1. 从目标 URL 下载 WSDL 数据。
2. 使用 ServiceDescription 创建和格式化 WSDL 文档文件。
3. 使用 ServiceDescriptionImporter 创建客户端代理类。
4. 使用 CodeDom 动态创建客户端代理类程序集。
5. 利用反射调用相关 WebService 方法。

OK,看看具体的例子。

我们要调用的目标 WebService,其 URL 是 http://localhost:60436/Learn.WEB/WebService.asmx

 

 

Web Service学习笔记:动态调用WebServiceHelloWorld.asmx [WebService(Namespace  =   " http://www.rainsts.net/ " , Description = " 我的Web服务 " )]
Web Service学习笔记:动态调用WebService[WebServiceBinding(ConformsTo 
=  WsiProfiles.BasicProfile1_1)]
Web Service学习笔记:动态调用WebServiceWeb Service学习笔记:动态调用WebService
public   class  WebService : System.Web.Services.WebService  {
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceWeb Service学习笔记:动态调用WebService
public WebService () {
Web Service学习笔记:动态调用WebService}

Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService  [WebMethod]
Web Service学习笔记:动态调用WebService  
public string HelloWorld()
Web Service学习笔记:动态调用WebServiceWeb Service学习笔记:动态调用WebService  
{
Web Service学习笔记:动态调用WebService    
return "Hello Wolrd!";
Web Service学习笔记:动态调用WebService  }

Web Service学习笔记:动态调用WebService}

Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
1 . 动态调用 WebService
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService客户端动态调用代码
Web Service学习笔记:动态调用WebService
using  System.IO;
Web Service学习笔记:动态调用WebService
using  System.Net;
Web Service学习笔记:动态调用WebService
using  System.Reflection;
Web Service学习笔记:动态调用WebService
using  System.CodeDom;
Web Service学习笔记:动态调用WebService
using  System.CodeDom.Compiler;
Web Service学习笔记:动态调用WebService
using  System.Web.Services;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Description;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Protocols;
Web Service学习笔记:动态调用WebService
using  System.Xml.Serialization;
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  1. 使用 WebClient 下载 WSDL 信息。
Web Service学习笔记:动态调用WebService
WebClient web  =   new  WebClient();
Web Service学习笔记:动态调用WebServiceStream stream 
=  web.OpenRead( " http://localhost:60436/Learn.WEB/WebService.asmx?WSDL " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  2. 创建和格式化 WSDL 文档。
Web Service学习笔记:动态调用WebService
ServiceDescription description  =  ServiceDescription.Read(stream);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  3. 创建客户端代理代理类。
Web Service学习笔记:动态调用WebService
ServiceDescriptionImporter importer  =   new  ServiceDescriptionImporter();
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.ProtocolName 
=   " Soap " //  指定访问协议。
Web Service学习笔记:动态调用WebService
importer.Style  =  ServiceDescriptionImportStyle.Client;  //  生成客户端代理。
Web Service学习笔记:动态调用WebService
importer.CodeGenerationOptions  =  CodeGenerationOptions.GenerateProperties  |  CodeGenerationOptions.GenerateNewAsync; 
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.AddServiceDescription(description, 
null null );  //  添加 WSDL 文档。
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  4. 使用 CodeDom 编译客户端代理类。
Web Service学习笔记:动态调用WebService
CodeNamespace nmspace  =   new  CodeNamespace();  //  为代理类添加命名空间,缺省为全局空间。
Web Service学习笔记:动态调用WebService
CodeCompileUnit unit  =   new  CodeCompileUnit();
Web Service学习笔记:动态调用WebServiceunit.Namespaces.Add(nmspace);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceServiceDescriptionImportWarnings warning 
=  importer.Import(nmspace, unit); 
Web Service学习笔记:动态调用WebServiceCodeDomProvider provider 
=  CodeDomProvider.CreateProvider( " CSharp " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceCompilerParameters parameter 
=   new  CompilerParameters();
Web Service学习笔记:动态调用WebServiceparameter.GenerateExecutable 
=   false ;
Web Service学习笔记:动态调用WebServiceparameter.GenerateInMemory 
=   true ;
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.XML.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.Web.Services.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.Data.dll " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceCompilerResults result 
=  provider.CompileAssemblyFromDom(parameter, unit);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  5. 使用 Reflection 调用 WebService。
Web Service学习笔记:动态调用WebService
if  ( ! result.Errors.HasErrors)
Web Service学习笔记:动态调用WebServiceWeb Service学习笔记:动态调用WebService
{
Web Service学习笔记:动态调用WebService  Assembly asm 
= result.CompiledAssembly;
Web Service学习笔记:动态调用WebService  Type t 
= asm.GetType("WebService"); // 如果在前面为代理类添加了命名空间,此处需要将命名空间添加到类型前面。
Web Service学习笔记:动态调用WebService

Web Service学习笔记:动态调用WebService  
object o = Activator.CreateInstance(t);
Web Service学习笔记:动态调用WebService  MethodInfo method 
= t.GetMethod("HelloWorld");
Web Service学习笔记:动态调用WebService  Console.WriteLine(method.Invoke(o, 
null));
Web Service学习笔记:动态调用WebService}

Web Service学习笔记:动态调用WebService

 

 

2. 生成客户端代理程序集文件

上面的代码通过在内存中创建动态程序集的方式完成了动态调用过程。如果我们希望将客户端代理类生成程序集文件保存到硬盘,则可以进行如下修改。生成程序集文件后,我们可以通过 Assembly.LoadFrom() 载入并进行反射调用。对于需要多次调用的系统,要比每次生成动态程序集效率高出很多。

 

 

Web Service学习笔记:动态调用WebServiceusing  System.IO;
Web Service学习笔记:动态调用WebService
using  System.Net;
Web Service学习笔记:动态调用WebService
using  System.CodeDom;
Web Service学习笔记:动态调用WebService
using  System.CodeDom.Compiler;
Web Service学习笔记:动态调用WebService
using  System.Web.Services;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Description;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Protocols;
Web Service学习笔记:动态调用WebService
using  System.Xml.Serialization;
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  1. 使用 WebClient 下载 WSDL 信息。
Web Service学习笔记:动态调用WebService
WebClient web  =   new  WebClient();
Web Service学习笔记:动态调用WebServiceStream stream 
=  web.OpenRead( " http://localhost:60436/Learn.WEB/WebService.asmx?WSDL " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  2. 创建和格式化 WSDL 文档。
Web Service学习笔记:动态调用WebService
ServiceDescription description  =  ServiceDescription.Read(stream);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  3. 创建客户端代理代理类。
Web Service学习笔记:动态调用WebService
ServiceDescriptionImporter importer  =   new  ServiceDescriptionImporter();
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.ProtocolName 
=   " Soap " //  指定访问协议。
Web Service学习笔记:动态调用WebService
importer.Style  =  ServiceDescriptionImportStyle.Client;  //  生成客户端代理。
Web Service学习笔记:动态调用WebService
importer.CodeGenerationOptions  =  CodeGenerationOptions.GenerateProperties  |  CodeGenerationOptions.GenerateNewAsync; 
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.AddServiceDescription(description, 
null null );  //  添加 WSDL 文档。
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  4. 使用 CodeDom 编译客户端代理类。
Web Service学习笔记:动态调用WebService
CodeNamespace nmspace  =   new  CodeNamespace();  //  为代理类添加命名空间,缺省为全局空间。
Web Service学习笔记:动态调用WebService
CodeCompileUnit unit  =   new  CodeCompileUnit();
Web Service学习笔记:动态调用WebServiceunit.Namespaces.Add(nmspace);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceServiceDescriptionImportWarnings warning 
=  importer.Import(nmspace, unit); 
Web Service学习笔记:动态调用WebServiceCodeDomProvider provider 
=  CodeDomProvider.CreateProvider( " CSharp " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceCompilerParameters parameter 
=   new  CompilerParameters();
Web Service学习笔记:动态调用WebServiceparameter.GenerateExecutable 
=   false ;
Web Service学习笔记:动态调用WebServiceparameter.OutputAssembly 
=   " test.dll " //  可以指定你所需的任何文件名。
Web Service学习笔记:动态调用WebService
parameter.ReferencedAssemblies.Add( " System.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.XML.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.Web.Services.dll " );
Web Service学习笔记:动态调用WebServiceparameter.ReferencedAssemblies.Add(
" System.Data.dll " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceCompilerResults result 
=  provider.CompileAssemblyFromDom(parameter, unit);
Web Service学习笔记:动态调用WebService
if  (result.Errors.HasErrors)
Web Service学习笔记:动态调用WebServiceWeb Service学习笔记:动态调用WebService
{
Web Service学习笔记:动态调用WebService  
// 显示编译错误信息
Web Service学习笔记:动态调用WebService
}

Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService调用程序集文件演示
Web Service学习笔记:动态调用WebServiceAssembly asm 
=  Assembly.LoadFrom( " test.dll " );
Web Service学习笔记:动态调用WebServiceType t 
=  asm.GetType( " WebService " ); 
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
object  o  =  Activator.CreateInstance(t);
Web Service学习笔记:动态调用WebServiceMethodInfo method 
=  t.GetMethod( " HelloWorld " );
Web Service学习笔记:动态调用WebServiceConsole.WriteLine(method.Invoke(o, 
null ));
Web Service学习笔记:动态调用WebService

 

 

3. 获取客户端代理类源代码

还有一种情形,就是我们需要获得客户端代理类的 C# 源代码。

 

 

Web Service学习笔记:动态调用WebServiceusing  System.IO;
Web Service学习笔记:动态调用WebService
using  System.Net;
Web Service学习笔记:动态调用WebService
using  System.CodeDom;
Web Service学习笔记:动态调用WebService
using  System.CodeDom.Compiler;
Web Service学习笔记:动态调用WebService
using  System.Web.Services;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Description;
Web Service学习笔记:动态调用WebService
using  System.Web.Services.Protocols;
Web Service学习笔记:动态调用WebService
using  System.Xml.Serialization;
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  1. 使用 WebClient 下载 WSDL 信息。
Web Service学习笔记:动态调用WebService
WebClient web  =   new  WebClient();
Web Service学习笔记:动态调用WebServiceStream stream 
=  web.OpenRead( " http://localhost:60436/Learn.WEB/WebService.asmx?WSDL " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  2. 创建和格式化 WSDL 文档。
Web Service学习笔记:动态调用WebService
ServiceDescription description  =  ServiceDescription.Read(stream);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  3. 创建客户端代理代理类。
Web Service学习笔记:动态调用WebService
ServiceDescriptionImporter importer  =   new  ServiceDescriptionImporter();
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.ProtocolName 
=   " Soap " //  指定访问协议。
Web Service学习笔记:动态调用WebService
importer.Style  =  ServiceDescriptionImportStyle.Client;  //  生成客户端代理。
Web Service学习笔记:动态调用WebService
importer.CodeGenerationOptions  =  CodeGenerationOptions.GenerateProperties  |  CodeGenerationOptions.GenerateNewAsync; 
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceimporter.AddServiceDescription(description, 
null null );  //  添加 WSDL 文档。
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  4. 使用 CodeDom 编译客户端代理类。
Web Service学习笔记:动态调用WebService
CodeNamespace nmspace  =   new  CodeNamespace();  //  为代理类添加命名空间,缺省为全局空间。
Web Service学习笔记:动态调用WebService
CodeCompileUnit unit  =   new  CodeCompileUnit();
Web Service学习笔记:动态调用WebServiceunit.Namespaces.Add(nmspace);
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebServiceServiceDescriptionImportWarnings warning 
=  importer.Import(nmspace, unit); 
Web Service学习笔记:动态调用WebServiceCodeDomProvider provider 
=  CodeDomProvider.CreateProvider( " CSharp " );
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService
//  5. 保存源代码到文件。当然,你也可以直接保存到内存字符串中。
Web Service学习笔记:动态调用WebService
TextWriter writer  =  File.CreateText( " test.cs " );  //  指定你所需的源代码文件名。
Web Service学习笔记:动态调用WebService
provider.GenerateCodeFromCompileUnit(unit, writer,  null );
Web Service学习笔记:动态调用WebServicewriter.Flush();
Web Service学习笔记:动态调用WebServicewriter.Close();
Web Service学习笔记:动态调用WebService
Web Service学习笔记:动态调用WebService

 

如果你调用时触发 "WebException: 请求因 HTTP 状态 415 失败: Unsupported Media Type。" 这样的异常,那么恭喜你和我一样郁闷,赶紧把服务器端的 WSE 关掉吧。在必须使用 WSE 的情况下,需要对客户端进行调整.