zoukankan      html  css  js  c++  java
  • C# 动态调用WebService

    Reference from : http://blog.csdn.net/chuxiamuxiang/article/details/5731988

    在C#程序中,若要调用WebService,一般是采用"添加Web引用"的方式来实现的。但如果此WebService的URL是在程序运行过程中才能获得的,那怎么办呢?那就必须是"动态"调用这个WebService了。

    网上有不少关于这方面的例子,总结了一下,主要有两种:(1)每次都动态调用,(2)将WebService生成为一个本地的DLL,生成客户端的实例。

    第一种方法:

    我把它放到一个叫WebServiceHelper.cs的类里面了。

    [c-sharp] view plaincopy
    1. /// <summary>   
    2.         /// 动态调用WebService   
    3.         /// </summary>   
    4.         /// <param name="url">WebService地址</param>   
    5.         /// <param name="classname">类名</param>   
    6.         /// <param name="methodname">方法名(模块名)</param>   
    7.         /// <param name="args">参数列表</param>   
    8.         /// <returns>object</returns>   
    9.         public static object InvokeWebService(string url, string classname, string methodname, object[] args)  
    10.         {  
    11.             string @namespace = "ServiceBase.WebService.DynamicWebLoad";  
    12.             if (classname == null || classname == "")  
    13.             {  
    14.                 classname = WebServiceHelper.GetClassName(url);  
    15.             }  
    16.             //获取服务描述语言(WSDL)   
    17.             WebClient wc = new WebClient();  
    18.             Stream stream = wc.OpenRead(url + "?WSDL");  
    19.             ServiceDescription sd = ServiceDescription.Read(stream);  
    20.             ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();  
    21.             sdi.AddServiceDescription(sd, "", "");  
    22.             CodeNamespace cn = new CodeNamespace(@namespace);  
    23.             //生成客户端代理类代码   
    24.             CodeCompileUnit ccu = new CodeCompileUnit();  
    25.             ccu.Namespaces.Add(cn);  
    26.             sdi.Import(cn, ccu);  
    27.             CSharpCodeProvider csc = new CSharpCodeProvider();  
    28.             ICodeCompiler icc = csc.CreateCompiler();  
    29.             //设定编译器的参数   
    30.             CompilerParameters cplist = new CompilerParameters();  
    31.             cplist.GenerateExecutable = false;  
    32.             cplist.GenerateInMemory = true;  
    33.             cplist.ReferencedAssemblies.Add("System.dll");  
    34.             cplist.ReferencedAssemblies.Add("System.XML.dll");  
    35.             cplist.ReferencedAssemblies.Add("System.Web.Services.dll");  
    36.             cplist.ReferencedAssemblies.Add("System.Data.dll");  
    37.             //编译代理类   
    38.             CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);  
    39.             if (true == cr.Errors.HasErrors)  
    40.             {  
    41.                 System.Text.StringBuilder sb = new StringBuilder();  
    42.                 foreach (CompilerError ce in cr.Errors)  
    43.                 {  
    44.                     sb.Append(ce.ToString());  
    45.                     sb.Append(System.Environment.NewLine);  
    46.                 }  
    47.                 throw new Exception(sb.ToString());  
    48.             }  
    49.             //生成代理实例,并调用方法   
    50.             System.Reflection.Assembly assembly = cr.CompiledAssembly;  
    51.             Type t = assembly.GetType(@namespace + "." + classname, true, true);  
    52.             object obj = Activator.CreateInstance(t);  
    53.             System.Reflection.MethodInfo mi = t.GetMethod(methodname);  
    54.             return mi.Invoke(obj, args);  
    55.         }  
    56.   
    57.         private static string GetClassName(string url)  
    58.         {  
    59.             string[] parts = url.Split('/');  
    60.             string[] pps = parts[parts.Length - 1].Split('.');  
    61.             return pps[0];  
    62.         }  

    举个使用它的例子:

    [c-sharp] view plaincopy
    1. object[] args = new object[1];  
    2.             args.SetValue("cyy_JS", 0);  
    3.             DataTable dt = WebServiceHelper.InvokeWebService("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx", "GetUserTreeListData", args) as DataTable;  

    恩~有点麻烦,这意味着每次我都要把想调用的函数的参数组织成一个object[]才行,且每次调用InvokeWebService都是在内存中创建动态程序集,效率极低。则次种方法绝对没有直接用“实例名.方法名(参数列表)”来的舒服。

    第二种方法:

    为了提高效率,希望不要每次都创建这么一个动态程序集,那么就要把这个程序集保存在本地,使用的时候调用这个本地的DLL即可。

    首先要调用:WebServiceHelper.CreateWebServiceDLL(); 用来在Debug目录下生成dll。这个函数的代码如下:

    [c-sharp] view plaincopy
    1. public static void CreateWebServiceDLL()  
    2.         {  
    3.             // 1. 使用 WebClient 下载 WSDL 信息。  
    4.             WebClient web = new WebClient();  
    5.             Stream stream = web.OpenRead("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx?WSDL");  
    6.             // 2. 创建和格式化 WSDL 文档。  
    7.             ServiceDescription description = ServiceDescription.Read(stream);  
    8.             // 3. 创建客户端代理代理类。  
    9.             ServiceDescriptionImporter importer = new ServiceDescriptionImporter();  
    10.             importer.ProtocolName = "Soap"; // 指定访问协议。  
    11.             importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。  
    12.             importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  
    13.             importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。  
    14.             // 4. 使用 CodeDom 编译客户端代理类。  
    15.             CodeNamespace nmspace = new CodeNamespace();        // 为代理类添加命名空间,缺省为全局空间。  
    16.             CodeCompileUnit unit = new CodeCompileUnit();  
    17.             unit.Namespaces.Add(nmspace);  
    18.             ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);  
    19.             CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");  
    20.             CompilerParameters parameter = new CompilerParameters();  
    21.             parameter.GenerateExecutable = false;  
    22.             parameter.OutputAssembly = "DBMS_Service.dll";  // 可以指定你所需的任何文件名。  
    23.             parameter.ReferencedAssemblies.Add("System.dll");  
    24.             parameter.ReferencedAssemblies.Add("System.XML.dll");  
    25.             parameter.ReferencedAssemblies.Add("System.Web.Services.dll");  
    26.             parameter.ReferencedAssemblies.Add("System.Data.dll");  
    27.             CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);  
    28.             if (result.Errors.HasErrors)  
    29.             {  
    30.                 // 显示编译错误信息  
    31.                 System.Text.StringBuilder sb = new StringBuilder();  
    32.                 foreach (CompilerError ce in result.Errors)  
    33.                 {  
    34.                     sb.Append(ce.ToString());  
    35.                     sb.Append(System.Environment.NewLine);  
    36.                 }  
    37.                 throw new Exception(sb.ToString());  
    38.             }  
    39.         }  

    下面举个使用的例子:

    [c-sharp] view plaincopy
    1. Assembly asm = Assembly.LoadFrom("DBMS_Service.dll");  
    2.             Type t = asm.GetType("DBMS_Service");  
    3.             object o = Activator.CreateInstance(t);  
    4.             MethodInfo method = t.GetMethod("GetUserTreeListData");  
    5.             object[] args = new object[1];  
    6.             args.SetValue("cyy_JS", 0);  
    7.             DataTable dt = method.Invoke(o, args) as DataTable;  

    这种方法的好处就是只用创建一次程序集,但缺点仍是调用函数的方式比较麻烦。

    第二种方法升级版:

    哈哈,这个是我自创的。目的就是为了解决:只创建一次DLL;以类似“实例名.方法名(参数列表)”的方式来调用函数;以这个DLL为模板,若WebService的内容有更新时,可同时更新这个本地的DLL。

    代码如下:

    [c-sharp] view plaincopy
    1. /// <summary>  
    2.         /// 根据WebService的URL,生成一个本地的dll,放在C盘下面,例如:C:|DBMS_WebService.dll  
    3.         /// 创建人:程媛媛 创建时间:2010-6-21  
    4.         /// </summary>  
    5.         /// <param name="url">WebService的UR</param>  
    6.         /// <returns></returns>  
    7.         public static void CreateWebServiceDLL(string url)  
    8.         {  
    9.             string @namespace = "ServiceBase.WebService.DynamicWebLoad";  
    10.             string classname = WebServiceHelper.GetClassName(url);  
    11.             // 1. 使用 WebClient 下载 WSDL 信息。  
    12.             WebClient web = new WebClient();  
    13.             Stream stream = web.OpenRead(url + "?WSDL");  
    14.             // 2. 创建和格式化 WSDL 文档。  
    15.             ServiceDescription description = ServiceDescription.Read(stream);  
    16.             // 3. 创建客户端代理代理类。  
    17.             ServiceDescriptionImporter importer = new ServiceDescriptionImporter();  
    18.             importer.ProtocolName = "Soap"; // 指定访问协议。  
    19.             importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。  
    20.             importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  
    21.             importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。  
    22.             // 4. 使用 CodeDom 编译客户端代理类。  
    23.             CodeNamespace nmspace = new CodeNamespace(@namespace); // 为代理类添加命名空间,缺省为全局空间。  
    24.             CodeCompileUnit unit = new CodeCompileUnit();  
    25.             unit.Namespaces.Add(nmspace);  
    26.             ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);  
    27.             CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");  
    28.             CompilerParameters parameter = new CompilerParameters();  
    29.             parameter.GenerateExecutable = false;  
    30.             parameter.OutputAssembly = "C://DBMS_Service.dll";  // 可以指定你所需的任何文件名。  
    31.             parameter.ReferencedAssemblies.Add("System.dll");  
    32.             parameter.ReferencedAssemblies.Add("System.XML.dll");  
    33.             parameter.ReferencedAssemblies.Add("System.Web.Services.dll");  
    34.             parameter.ReferencedAssemblies.Add("System.Data.dll");  
    35.             CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);  
    36.             if (result.Errors.HasErrors)  
    37.             {  
    38.                 // 显示编译错误信息  
    39.                 System.Text.StringBuilder sb = new StringBuilder();  
    40.                 foreach (CompilerError ce in result.Errors)  
    41.                 {  
    42.                     sb.Append(ce.ToString());  
    43.                     sb.Append(System.Environment.NewLine);  
    44.                 }  
    45.                 throw new Exception(sb.ToString());  
    46.             }  
    47.         }  

    首先调用CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")来生成“C:/DBMS_WebService.dll”;

    接着,把这个DLL添加到工程的“引用”当中。

    也许你会问,为什么不直接把DBMS_WebService.dll放在debug下?答案是,当把DBMS_WebService.dll添加为 引用时,若在程序运行过程中要更新(包括删了重新创建)它,则会报错。尝试了几次,被我发现,是不能放在Debug下的,其他的任何路径都可以,例如 bin目录下都可以,具体原因我不知道...

    既然都把DBMS_WebService.dll添加为引用了,那么便可以先声明它了:

    [c-sharp] view plaincopy
    1. public static ServiceBase.WebService.DynamicWebLoad.DBMS_Service pDBMS_Service;  

    注意:“public static ServiceBase.WebService.DynamicWebLoad.DBMS_Service”是我们调用 CreateWebServiceDLL("http://192.168.0.10/DBMS_CYY/DBMS_Service.asmx")的过程 中自定的表空间名。

    接下来的事就是,需要一个函数,用来以此DBMS_WebService.dll为模板,用传入的URL来重新生成并覆盖这个DLL,并且,为了省 事,直接返回一个ServiceBase.WebService.DynamicWebLoad.DBMS_Service的实例。

    代码如下:

    [c-sharp] view plaincopy
    1. /// <summary>  
    2.         /// 根据WebService的URL,生成一个本地的dll,并返回WebService的实例  
    3.         /// 创建人:程媛媛 创建时间:2010-6-21  
    4.         /// </summary>  
    5.         /// <param name="url">WebService的UR</param>  
    6.         /// <returns></returns>  
    7.         public static object GetWebServiceInstance(string url)  
    8.         {  
    9.             string @namespace = "ServiceBase.WebService.DynamicWebLoad";  
    10.             string classname = WebServiceHelper.GetClassName(url);  
    11.             // 1. 使用 WebClient 下载 WSDL 信息。  
    12.             WebClient web = new WebClient();  
    13.             Stream stream = web.OpenRead(url + "?WSDL");  
    14.             // 2. 创建和格式化 WSDL 文档。  
    15.             ServiceDescription description = ServiceDescription.Read(stream);  
    16.             // 3. 创建客户端代理代理类。  
    17.             ServiceDescriptionImporter importer = new ServiceDescriptionImporter();  
    18.             importer.ProtocolName = "Soap"; // 指定访问协议。  
    19.             importer.Style = ServiceDescriptionImportStyle.Client; // 生成客户端代理。  
    20.             importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;  
    21.             importer.AddServiceDescription(description, null, null); // 添加 WSDL 文档。  
    22.             // 4. 使用 CodeDom 编译客户端代理类。  
    23.             CodeNamespace nmspace = new CodeNamespace(@namespace); // 为代理类添加命名空间,缺省为全局空间。  
    24.             CodeCompileUnit unit = new CodeCompileUnit();  
    25.             unit.Namespaces.Add(nmspace);  
    26.             ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);  
    27.             CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");  
    28.             CompilerParameters parameter = new CompilerParameters();  
    29.             parameter.GenerateExecutable = false;  
    30.             parameter.OutputAssembly = "C://DBMS_Service.dll"; // 可以指定你所需的任何文件名。  
    31.               
    32.             parameter.ReferencedAssemblies.Add("System.dll");  
    33.             parameter.ReferencedAssemblies.Add("System.XML.dll");  
    34.             parameter.ReferencedAssemblies.Add("System.Web.Services.dll");  
    35.             parameter.ReferencedAssemblies.Add("System.Data.dll");  
    36.             CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);  
    37.             if (result.Errors.HasErrors)  
    38.             {  
    39.                 // 显示编译错误信息  
    40.                 System.Text.StringBuilder sb = new StringBuilder();  
    41.                 foreach (CompilerError ce in result.Errors)  
    42.                 {  
    43.                     sb.Append(ce.ToString());  
    44.                     sb.Append(System.Environment.NewLine);  
    45.                 }  
    46.                 throw new Exception(sb.ToString());  
    47.             }  
    48.             //生成代理实例  
    49.             System.Reflection.Assembly assembly = Assembly.Load("DBMS_Service");  
    50.             Type t = assembly.GetType(@namespace + "." + classname, true, true);  
    51.             object obj = Activator.CreateInstance(t);  
    52.             return obj;  
    53.         }  

    一切准备就绪,在主程序中这样使用它:

    [c-sharp] view plaincopy
    1. object o = WebServiceHelper.GetWebServiceInstance(this.WebServiceURL);  
    2. pDBMS_Service = o as ServiceBase.WebService.DynamicWebLoad.DBMS_Service;  
    3. DataTable dt = pDBMS_Service.GetUserTreeListData(this.UserName); 
  • 相关阅读:
    c#读取Excel并显示出来
    异步编程模型。
    细分线程的等待(WaitAny,WaitAll),区别于Thread.Join
    waitany,waitall在线程池中的使用。from msdn
    SQL SET NOCOUNT ON的含义和作用
    MS ゴシック与MS UI Gothic的区别
    线程的管理1
    HDU 1203 I NEED A OFFER!(背包)
    hdu 1232 畅通工程
    POJ 1088 滑雪
  • 原文地址:https://www.cnblogs.com/zhangchenliang/p/4322436.html
Copyright © 2011-2022 走看看