加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

动态调用WebService(C#)

发布时间:2020-12-16 22:31:36 所属栏目:安全 来源:网络整理
导读:?? 通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却和提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。
?? 通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务。这样是使工作简单了,但是却和提供Web服务的URL、方法名、参数绑定在一起了,这是VS.NET自动为我们生成Web服务代理的限制。如果哪一天发布Web服务的URL改变了,则我们需要重新让VS.NET生成代理,并重新编译。在某些情况下,这可能是不能忍受的,我们需要动态调用WebService的能力。比如我们可以把Web服务的URL保存在配置文件中,这样,当服务URL改变时,只需要修改配置文件就可以了。
???? 说了这么多,实际上我们要实现这样的功能:
?
[csharp]? view plain copy print ?
  1. public?static?object?InvokeWebService(string?url,??string?methodname,?object[]?args)??


? 其中,url是Web服务的地址,methodname是要调用服务方法名,args是要调用Web服务所需的参数,返回值就是web服务返回的结果了。

? 要实现这样的功能,你需要这几个方面的技能:反射、CodeDom、编程使用C#编译器、WebService。在了解这些知识后,就可以容易的实现web服务的动态调用了:

?
    #region?InvokeWebService??
  1. ??????//动态调用web服务??
  2. ??????object[]?args)??
  3. ???????{??
  4. ??????????return?WebServiceHelper.InvokeWebService(url?,null?,methodname?,args)?;??
  5. ???????}??
  6. ??
  7. ??????string?classname,153); font-weight:bold; background-color:inherit">object[]?args)??
  8. ???????{??
  9. ??????????string?@namespace?=?"EnterpriseServerBase.WebService.DynamicWebCalling"?;??
  10. if((classname?==?null)?||(classname?==?""))??
  11. ???????????{??
  12. ???????????????classname?=?WebServiceHelper.GetWsClassName(url)?;??
  13. ???????????}??
  14. try??
  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. //生成客户端代理类代码??
  25. ???????????????CodeCompileUnit?ccu?????????????=?new?CodeCompileUnit();??
  26. ???????????????ccu.Namespaces.Add(cn);??
  27. ???????????????sdi.Import(cn?,ccu);???
  28. ???????????????CSharpCodeProvider?csc??????????=?new?CSharpCodeProvider();??
  29. ???????????????ICodeCompiler?icc???????????????=?csc.CreateCompiler();??
  30. ????????????????
  31. ??????????????//设定编译参数??
  32. ???????????????CompilerParameters?cplist???????=?new?CompilerParameters();??
  33. ???????????????cplist.GenerateExecutable???????=?false;??
  34. ???????????????cplist.GenerateInMemory?????????=?true;??
  35. ???????????????cplist.ReferencedAssemblies.Add("System.dll");??
  36. ???????????????cplist.ReferencedAssemblies.Add("System.XML.dll");??
  37. ???????????????cplist.ReferencedAssemblies.Add("System.Web.Services.dll");??
  38. ???????????????cplist.ReferencedAssemblies.Add("System.Data.dll");??
  39. //编译代理类??
  40. ???????????????CompilerResults?cr?=?icc.CompileAssemblyFromDom(cplist,?ccu);??
  41. ??????????????if(true?==?cr.Errors.HasErrors)??
  42. ???????????????{??
  43. ???????????????????System.Text.StringBuilder?sb?=?new?System.Text.StringBuilder();??
  44. ??????????????????foreach(System.CodeDom.Compiler.CompilerError?ce?in?cr.Errors)??
  45. ???????????????????{??
  46. ???????????????????????sb.Append(ce.ToString());??
  47. ???????????????????????sb.Append(System.Environment.NewLine);??
  48. ???????????????????}??
  49. ??????????????????throw?new?Exception(sb.ToString());??
  50. ???????????????}??
  51. ??
  52. //生成代理实例,并调用方法??
  53. ???????????????System.Reflection.Assembly?assembly?=?cr.CompiledAssembly;??
  54. ???????????????Type?t?=?assembly.GetType(@namespace+"."+classname,153); font-weight:bold; background-color:inherit">true,153); font-weight:bold; background-color:inherit">true);??
  55. object?obj?=?Activator.CreateInstance(t);??
  56. ???????????????System.Reflection.MethodInfo?mi?=?t.GetMethod(methodname);??
  57. ??????????????return?mi.Invoke(obj,args);??
  58. catch(Exception?ex)??
  59. new?Exception(ex.InnerException.Message,153); font-weight:bold; background-color:inherit">new?Exception(ex.InnerException.StackTrace));??
  60. ???????}??
  61. private?string?GetWsClassName(string?wsUrl)??
  62. string[]?parts?=?wsUrl.Split('/')?;??
  63. string[]?pps???=?parts[parts.Length-1].Split('.')?;??
  64. return?pps[0]?;??
  65. ??????#endregion??


? 上面的注释已经很好的说明了各代码段的功能,下面给个例子看看,这个例子是通过访问http://www.webservicex.net/globalweather.asmx?服务来获取各大城市的天气状况。

?
    string?url?=?"http://www.webservicex.net/globalweather.asmx"?;??
  1. ???????string[]?args?=?new?string[2]?;??
  2. ????????args[0]?=?this.textBox_CityName.Text?;??
  3. ????????args[1]?=?"China"?;??
  4. ???????object?result?=?WebServiceHelper.InvokeWebService(url?,"GetWeather"?,153); font-weight:bold; background-color:inherit">this.label_Result.Text?=?result.ToString()?;??


??? 上述的例子中,调用web服务使用了两个参数,第一个是城市的名字,第二个是国家的名字,Web服务返回的是XML文档,可以从其中解析出温度、风力等天气情况。
????
???? 最后说一下,C#虽然仍属于静态语言之列,但是其动态能力也是很强大的,不信,你可以看看Spring.net的AOP实现,这种“无侵入”的AOP实现比通常的.NET声明式AOP实现(一般是通过AOP Attribute)要漂亮的多。

c#动态调用WebService

?
    using?System;??
  1. using?System.Collections.Generic;??
  2. using?System.Text;??
  3. using?System.Xml;??
  4. using?System.Net;??
  5. using?System.Web.Services.Description;??
  6. using?System.CodeDom;??
  7. using?System.CodeDom.Compiler;??
  8. using?System.Reflection;??
  9. namespace?WindowsServiceWebDefaultHotCity??
  10. {??
  11. ????///?<summary<??
  12. ????///?WebService代理类??
  13. ///?</summary<??
  14. ????class?WebServiceAgent??
  15. ????{??
  16. ????????object?agent;??
  17. ????????private?Type?agentType;??
  18. const?string?CODE_NAMESPACE?=?"Beyondbit.WebServiceAgent.Dynamic";??
  19. ???????? ????????///?构造函数??
  20. ///?<param?name="url"<</param<??
  21. public?WebServiceAgent(string?url)??
  22. ????????{??
  23. ????????????XmlTextReader?reader?=?new?XmlTextReader(url?+?"?wsdl");??
  24. ????????????//创建和格式化?WSDL?文档??
  25. ????????????ServiceDescription?sd?=?ServiceDescription.Read(reader);??
  26. ????????????//创建客户端代理代理类??
  27. ????????????ServiceDescriptionImporter?sdi?=? ????????????sdi.AddServiceDescription(sd,?null,153); font-weight:bold; background-color:inherit">null);??
  28. //使用?CodeDom?编译客户端代理类??
  29. ????????????CodeNamespace?cn?=?new?CodeNamespace(CODE_NAMESPACE);??
  30. ????????????CodeCompileUnit?ccu?=? ????????????ccu.Namespaces.Add(cn);??
  31. ????????????sdi.Import(cn,108); list-style:decimal-leading-zero outside; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ????????????Microsoft.CSharp.CSharpCodeProvider?icc?=?new?Microsoft.CSharp.CSharpCodeProvider();??
  32. ????????????CompilerParameters?cp?=?new?CompilerParameters();??
  33. ????????????CompilerResults?cr?=?icc.CompileAssemblyFromDom(cp,?ccu);??
  34. ????????????agentType?=?cr.CompiledAssembly.GetTypes()[0];??
  35. ????????????agent?=?Activator.CreateInstance(agentType);??
  36. ????????}??
  37. ///<summary<??
  38. ///调用指定的方法??
  39. ///</summary<??
  40. ///<param?name="methodName"<方法名,大小写敏感</param<??
  41. ///<param?name="args"<参数,按照参数顺序赋值</param<??
  42. ///<returns<Web服务的返回值</returns<??
  43. object?Invoke(string?methodName,153); font-weight:bold; background-color:inherit">params? ????????{??
  44. ????????????MethodInfo?mi?=?agentType.GetMethod(methodName);??
  45. ????????????return?this.Invoke(mi,?args);??
  46. ///<summary<??
  47. ///调用指定方法??
  48. ///</summary<??
  49. ///<param?name="method"<方法信息</param<??
  50. ///<param?name="args"<参数,按照参数顺序赋值</param<??
  51. ///<returns<Web服务的返回值</returns<??
  52. object?Invoke(MethodInfo?method,153); font-weight:bold; background-color:inherit">return?method.Invoke(agent,153); font-weight:bold; background-color:inherit">public?MethodInfo[]?Methods??
  53. get??
  54. ????????????{??
  55. ????????????????return?agentType.GetMethods();??
  56. ????????????}??
  57. ????????}??
  58. ????}??
  59. }??


?

?
    using?System.ComponentModel;??
  1. using?System.Data;??
  2. using?System.Drawing;??
  3. using?System.Windows.Forms;??
  4. namespace?WindowsApplication1??
  5. ????public?partial?class?Form1?:?Form??
  6. ????{??
  7. string?_url?=?"http://www.baidu.com";??
  8. public?Form1()??
  9. ????????????InitializeComponent();??
  10. ????????????init_Data();??
  11. void?init_Data()??
  12. ????????????WindowsServiceWebDefaultHotCity.WebServiceAgent?agent?=?new?WindowsServiceWebDefaultHotCity.WebServiceAgent(_url);??
  13. object[]?args?=?object[6];??
  14. ????????????args[0]?=?"PEK";??
  15. ????????????args[1]?=?"CAN";??
  16. ????????????args[2]?=?"";??
  17. ????????????args[3]?=?"2008-08-02";??
  18. ????????????args[4]?=?"00:00";??
  19. ????????????args[5]?=?"own_9588";??
  20. ????????????string?text=agent.Invoke("GetAllFlight",?args).ToString();??
  21. ????????????textBox1.Text?=?text;??
  22. ????}??
  23. }??
?
    ????我们都知道,调用WS可以在工程中添加对WS的WEB引用。???
  1. 但是,如果我们不想通过添加引用的方式,而是在代码中动态引用该怎么办呢????
  2. 首先,我们该想到WS的实现也是一个类的形式。???
  3. 其次,WS在传输过程中是通过WSDL来进行描述的(使用SOAP协议)。???
  4. 因此,我们需要获取WS的WSDL描述,并通过该描述来动态生成程序集。???
  5. 最后:通过反射来获取新生成的程序集,并调用其方法!???
  6. 上述步骤需要引用如下四个名称空间:???
  7. using?System.Web.Services.Description;?//WS的描述???
  8. //以下几个用于根据描述动态生成代码并动态编译获取程序集???
  9. using?System.CodeDom;???
  10. using?Microsoft.CSharp;???
  11. using?System.CodeDom.Compiler;???
  12. 上述几个名称空间中包括如下几个重要的类:???
  13. using?System.Web.Services.Description下:???
  14. ServiceDescription?//WS描述???
  15. ServiceDescriptionImporter?//通过描述生成客户端代理类,特别注意其中的Style???
  16. 以下是MSDN对其的描述:???
  17. XML?Web?services?的接口通常由?Web?服务描述语言?(WSDL)?文件来说明。例如,若要获取有关使用?http://localhost/service.asmx?处公开的?ASP.NET?的?Web?服务的?WSDL?说明,只需导航到?http://localhost/service.asmx?WSDL。使用?ServiceDescriptionImporter?类可以方便地将?WSDL?说明中包含的信息导入到?System.CodeDom.CodeCompileUnit?对象。通过调整?Style?参数的值,可以指示?ServiceDescriptionImporter?实例生成客户端代理类(通过透明调用该类可提供?Web?服务的功能)或生成抽象类(该类封装?Web?服务的功能而不实现该功能)。如果将?Style?属性设置为?Client,则?ServiceDescriptionImporter?生成客户端代理类,通过调用这些类来提供说明的?Web?服务的功能。如果将?Style?属性设置为?Server,则?ServiceDescriptionImporter?实例生成抽象类,这些类表示所说明的?XML?Web?services?的功能而不进行实现。然后,可以通过编写从这些抽象类继承的类来对其进行实现,并实现相关的方法。??
  18. using?System.CodeDom下:???
  19. CodedomUnit?//它用于设定动态代码的名称空间,类名等,可以通过ServiceDescriptionImporter.Import()方法将WS的描述代码写入该类,以作动态编译用??

using System.CodeDom.Compiler下:?
CodedomProvider //用于创建和检索代码生成器和代码编译器的实例,我们主要用到其实现子类CShareCodeProvider?
可以直接用CShareCodeProvider provider=new CShareCodeProvider()来生成,或者用CodedomProvider.CreateProvider("CSharp")来生成?
ICodeCompiler //用于编译基于 System.CodeDom 的源代码表示形式。?
它通过CodedomProvider的CreateCompiler()方法来?
CompilerResults //表示从编译器返回的编译结果。 它由ICodeCompiler根据指定的编译器设置从指定的 CodeCompileUnit 所包含的 System.CodeDom 树中编译程序集并返回。CompiledAssembly 属性指示编译的程序集。

了解如上信息后,就可动态调用WS了。?
如下是摘自http://www.cnblogs.com/ruochen/archive/2007/12/11/990427.html的代码演示:
Code?

?? 该方法可以使程序不通过web引用的方式去调用webservices方法,直接在代码里调用该方法就能达到动态调用webservices的目的。使用前先引用System.Web.Services动态链接库,是.net自带的dll。

方法如下:

?
    using?System.Net;??
  1. using?System.IO;??
  2. using?Microsoft.CSharp;??
  3. using?System.CodeDom.Compiler;??
  4. namespace?TestSkin??
  5. {??
  6. class?Webservices??
  7. ///?<summary<??
  8. ///?实例化WebServices??
  9. ///?</summary<??
  10. ///?<param?name="url"<WebServices地址</param<??
  11. ///?<param?name="methodname"<调用的方法</param<??
  12. ///?<param?name="args"<把webservices里需要的参数按顺序放到这个object[]里</param<??
  13. //这里的namespace是需引用的webservices的命名空间,在这里是写死的,大家可以加一个参数从外面传进来。??
  14. namespace?=?"client";??
  15. ???????????????? ????????????????WebClient?wc?=? ????????????????Stream?stream?=?wc.OpenRead(url?+?"?WSDL");??
  16. ????????????????ServiceDescription?sd?=?ServiceDescription.Read(stream);??
  17. string?classname?=?sd.Services[0].Name;??
  18. ????????????????ServiceDescriptionImporter?sdi?=?new?ServiceDescriptionImporter();??
  19. ????????????????sdi.AddServiceDescription(sd,?"",?"");??
  20. ????????????????CodeNamespace?cn?=?namespace);??
  21. ????????????????//生成客户端代理类代码??
  22. ????????????????CodeCompileUnit?ccu?=?new?CodeCompileUnit();??
  23. ????????????????ccu.Namespaces.Add(cn);??
  24. ????????????????sdi.Import(cn,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px"> ????????????????CSharpCodeProvider?csc?=?new?CSharpCodeProvider();??
  25. ????????????????ICodeCompiler?icc?=?csc.CreateCompiler();??
  26. //设定编译参数??
  27. ????????????????CompilerParameters?cplist?=? ????????????????cplist.GenerateExecutable?=?false;??
  28. ????????????????cplist.GenerateInMemory?=?true;??
  29. ????????????????cplist.ReferencedAssemblies.Add("System.dll");??
  30. ????????????????cplist.ReferencedAssemblies.Add("System.XML.dll");??
  31. ????????????????cplist.ReferencedAssemblies.Add("System.Web.Services.dll");??
  32. ????????????????cplist.ReferencedAssemblies.Add("System.Data.dll");??
  33. //编译代理类??
  34. ????????????????CompilerResults?cr?=?icc.CompileAssemblyFromDom(cplist,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px"> ????????????????if?(true?==?cr.Errors.HasErrors)??
  35. ????????????????{??
  36. ????????????????????System.Text.StringBuilder?sb?=?new?System.Text.StringBuilder();??
  37. ????????????????????foreach?(System.CodeDom.Compiler.CompilerError?ce?in?cr.Errors)??
  38. ????????????????????{??
  39. ????????????????????????sb.Append(ce.ToString());??
  40. ????????????????????????sb.Append(System.Environment.NewLine);??
  41. ????????????????????}??
  42. ????????????????????new?Exception(sb.ToString());??
  43. ????????????????}??
  44. //生成代理实例,并调用方法??
  45. ????????????????System.Reflection.Assembly?assembly?=?cr.CompiledAssembly;??
  46. ????????????????Type?t?=?assembly.GetType(@namespace?+?"."?+?classname,153); font-weight:bold; background-color:inherit">true);??
  47. object?obj?=?Activator.CreateInstance(t);??
  48. ????????????????System.Reflection.MethodInfo?mi?=?t.GetMethod(methodname);??
  49. catch??
  50. null;??
  51. }??

?

===了解上述类和方法后,基本就可以动态调用WS了。?
特别注意的是:动态编译后需要用到反射来读取并执行。因此需要您了解什么是反射及如何反射。??

web service的动态调用,主要有三种方法。

  1、修改config文件。只要你引用了web service,就会在config文件中出现asmx文件的地址。只需要修改该地址即可。

  2、程序修改url。web service是集成了System.Web.Service.WebService类的,而该类有一个Url属性。通过修改该属性可以达到与方法一一样的效果,并且比它还要灵活。有的时候,我们需要提供一个列表,有很多的服务器让用户选择。程序根据用户的选择连接到不同的服务器上调用web service。这时,就可以用这个方法了。

  3、接口引用。有的时候,我们需要调用不同服务器上的web service,但他们彼此又不一样,只是都实现了同一个接口。这时候,就可以考虑下面的这个方法。只要先引用所有的web service,然后用接口实例来保存创建出来的web service对象即可。

  4、动态编译。这个应该算得上是真正意义上的动态了。有的时候,各个服务器上的web service更新比较快,我们不可能天天去更新代理类的,这个时候就可以用这个方法了。

  在该方法中,有一点限制。就是各个服务器的web service,要么是都继承了同一个接口,要么是都有一些同样签名的方法,而且service的类名最好是一样的。不过就算不符合这条件也没关系,后面我会在注释中注明的。看代码:

?
    using?System;????
  1. using?System.CodeDom;????
  2. using?System.CodeDom.Compiler;????
  3. using?System.IO;????
  4. using?System.Net;????
  5. using?System.Reflection;????
  6. using?System.Web.Services.Description;????
  7. using?Microsoft.CSharp;????
  8. ????
  9. //获取Web?Service描述????
  10. WebClient?wc=?new?WebClient();????
  11. Stream?stream?=?wc.OpenRead("http://localhost/TestService.asmx?WSDL");??//这里指定你自己的web?service?url,一定要以?WSDL结尾????
  12. ServiceDescription?sd?=?ServiceDescription.Read(stream);????
  13. ServiceDescriptionImporter?sdi?=?new?ServiceDescriptionImporter();????
  14. sdi.ProtocolName?=?"soap";????
  15. sdi.Style?=?ServiceDescriptionImportStyle.Client;????
  16. sdi.AddServiceDescription(sd,153); font-weight:bold; background-color:inherit">null);????
  17. //指定命名空间????
  18. CodeNamespace?cn?=?new?CodeNamespace("Test");??//这里随便指定一个命名空间,但要与后面的一致????
  19. CodeCompileUnit?ccu?=?new?CodeCompileUnit();????
  20. ccu.Namespaces.Add(cn);????
  21. sdi.Import(cn,?ccu);????
  22. 建立C#编译器????
  23. CSharpCodeProvider?csc?=?new?CSharpCodeProvider();????
  24. ICodeCompiler?icc?=?csc.CreateCompiler();????
  25. CompilerParameters?cp?=?new?CompilerParameters();????
  26. cp.GenerateExecutable?=?false;????
  27. cp.GenerateInMemory?=?true;????
  28. //添加编译条件????
  29. cp.ReferencedAssemblies.Add("System.dll");????
  30. cp.ReferencedAssemblies.Add("System.XML.dll");????
  31. cp.ReferencedAssemblies.Add("System.Web.Services.dll");????
  32. //编译程序集????
  33. CompilerResults?cr?=?icc.CompileAssemblyFromDom(cp,0); background-color:inherit">//检查是否编译成功????
  34. if?(!cr.Errors.HasErrors)????
  35. {????
  36. ??//编译成功????
  37. ??//获取程序集????
  38. ??Assembly?assembly?=?cr.CompiledAssembly;????
  39. //获取程序集类型????
  40. //前面的Test就是命名空间,必须要与前面指定的一致????
  41. //后面的TestService就是service的类名????
  42. //如果所有的服务器都是一致的类名,这里就可以写死,否则要动态提供类名????
  43. ??Type?type?=?assembly.GetType("Test.TestService",153); font-weight:bold; background-color:inherit">true);????
  44. ??object?service?=?Activator.CreateInstance(type);????
  45. //获取方法????
  46. //如果所有的服务器都是一致的方法名,这里可以写死,否则就要动态提供方法名????
  47. ??MethodInfo?mi?=?type.GetMethod("HelloWorld");????
  48. //调用方法????
  49. //如果方法没有参数,第二个参数可以传递null,否则就要传递object数组,数组元素的顺序要与参数的顺序一致????
  50. //如果所有服务器的方法签名都是一致的,object数组的顺序就可以写死了,否则还要动态调整元素的数量及顺序????
  51. ??mi.Invoke(service,0); background-color:inherit">//最后,返回的是object类型,根据方法的签名,把返回值转换成不同的对象即可。????
  52. }????
  53. else????
  54. //这里自己处理编译错误????
  55. }????


转载:http://blog.csdn.net/ysq5202121/article/details/6942813


方法二:利用 wsdl.exe生成webservice代理类:

根据提供的wsdl生成webservice代理类,然后在代码里引用这个类文件。

步骤:1、在开始菜单找到? Microsoft Visual Studio 2010 下面的Visual Studio Tools , 点击Visual Studio 命令提示(2010),打开命令行。

????????? 2、?在命令行中输入:? wsdl /language:c# /n:TestDemo /out:d:/Temp/TestService.cs?http://jm1.services.gmcc.net/ad/Services/AD.asmx?wsdl

??????????????? 这句命令行的意思是:对最后面的服务地址进行编译,在D盘temp 目录下生成testservice文件。

????????? 3、 把上面命令编译后的cs文件,复制到我们项目中,在项目代码中可以直接new 一个出来后,可以进行调用。

更为详细的可以参见: http://www.voidcn.com/article/p-drlofvnv-dn.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读