今天刚学习了下动态调用WebService,顺便写在博客上以方便以后自己用到,也分享给大家。
下面是WebService动态调用示意图
第一步,新建应用程序类库InvokeWebService,再创建静态类WebServiceHelpers,标记为【1】~【11】的解释在代码的后面,代码如下:
1 public static class WebServiceHelper
2 {
3 /// <summary>
4 /// 动态调用WebService
5 /// </summary>
6 /// <param name="url">WebService地址</param>
7 /// <param name="methodname">方法名(模块名)</param>
8 /// <param name="args">参数列表</param>
9 /// <returns>object</returns>
10 public static object InvokeWebService(string url, string methodname, object[] args)
11 {
12 return InvokeWebService(url, null, methodname, args);
13 }
14 /// <summary>
15 /// 动态调用WebService
16 /// </summary>
17 /// <param name="url">WebService地址</param>
18 /// <param name="classname">类名</param>
19 /// <param name="methodname">方法名(模块名)</param>
20 /// <param name="args">参数列表</param>
21 /// <returns>object</returns>
22 public static object InvokeWebService(string url, string classname, string methodname, object[] args)
23 {
24 string @namespace = "ServiceBase.WebService.DynamicWebLoad";
25 if (classname == null || classname == "")
26 {
27 classname = WebServiceHelper.GetClassName(url);
28 }
29 //获取服务描述语言(WSDL)
30 WebClient wc = new WebClient();
31 Stream stream = wc.OpenRead(url + "?WSDL");//【1】
32 ServiceDescription sd = ServiceDescription.Read(stream);//【2】
33 ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();//【3】
34 sdi.AddServiceDescription(sd, "", "");
35 CodeNamespace cn = new CodeNamespace(@namespace);//【4】
36 //生成客户端代理类代码
37 CodeCompileUnit ccu = new CodeCompileUnit();//【5】
38 ccu.Namespaces.Add(cn);
39 sdi.Import(cn, ccu);
40 CSharpCodeProvider csc = new CSharpCodeProvider();//【6】
41 ICodeCompiler icc = csc.CreateCompiler();//【7】
42 //设定编译器的参数
43 CompilerParameters cplist = new CompilerParameters();//【8】
44 cplist.GenerateExecutable = false;
45 cplist.GenerateInMemory = true;
46 cplist.ReferencedAssemblies.Add("System.dll");
47 cplist.ReferencedAssemblies.Add("System.XML.dll");
48 cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
49 cplist.ReferencedAssemblies.Add("System.Data.dll");
50 //编译代理类
51 CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);//【9】
52 if (true == cr.Errors.HasErrors)
53 {
54 System.Text.StringBuilder sb = new StringBuilder();
55 foreach (CompilerError ce in cr.Errors)
56 {
57 sb.Append(ce.ToString());
58 sb.Append(System.Environment.NewLine);
59 }
60 throw new Exception(sb.ToString());
61 }
62
63 //生成代理实例,并调用方法
64 System.Reflection.Assembly assembly = cr.CompiledAssembly;
65 Type t = assembly.GetType(@namespace + "." + classname, true, true);
66 object obj = Activator.CreateInstance(t);//【10】
67 System.Reflection.MethodInfo mi = t.GetMethod(methodname);//【11】
68 return mi.Invoke(obj, args);
69
70 }
71
72 private static string GetClassName(string url)
73 {
74 //假如URL为"http://localhost/InvokeService/Service1.asmx"
75 //最终的返回值为 Service1
76 string[] parts = url.Split('/');
77 string[] pps = parts[parts.Length - 1].Split('.');
78 return pps[0];
79 }
80
81 }
代码中的注解如下:
【1】如果URL后面不加"?WSDL",运行结果就是在调用Web Service,而不是Web服务描述语言(WSDL),界面如下:
如果URL后面加上"?WSDL",那返回的才是真正的Web服务描述语言(WSDL),运行结果如下:
【2】 ServiceDescription类提供一种方法,以创建和格式化用于描述 XML Web services 的有效的 Web 服务描述语言 (WSDL) 文档文件,该文件是完整的,具有适当的命名空间、元素和特性。 无法继承此类。
ServiceDescription.Read 方法 (Stream) 通过直接从 Stream实例加载 XML 来初始化ServiceDescription类的实例。
【3】 ServiceDescriptionImporter 类 公开一种为 XML Web services 生成客户端代理类的方法。
ServiceDescriptionImporter.AddServiceDescription 方法 将指定的ServiceDescription添加到要导入的ServiceDescriptions值的集合中。
【4】 CodeNamespace表示命名空间声明。
【5】 CodeCompileUnit会提供一个CodeDOM程式圆形的容器,CodeCompileUnit含有一个集合,可以储存含有CodeDOM原始程式码原形,专案参考的组件集合以及专案组件属性集合的CodeNamespace物件。
【6】 CSharpCodeProvider类提供存取C#程式码产生器和程式码编译器的执行个体。
【7】 取得C#程式码编译器的执行个体
【8】 创建编译器的参数实例
【9】 CompilerResults表示从编译器返回的编译结果。使用指定的编译器设定,根据CodeCompileUnit物件之指定阵列所包含的System.CodeDom树状结构,编译一个组件。
【10】 Activator类包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。无法继承此类Activator.CreateInstance 方法 使用与指定参数匹配程度最高的构造函数创建指定类型的实例。
【11】 MethodInfo 的实例可以通过调用GetMethods或者Type对象或派生自Type的对象的GetMethod方法来获取,还可以通过调用表示泛型方法定义的 MethodInfo 的MakeGenericMethod方法来获取。
第二步,新建Web Service应用程序,类名为Service1,类里只有一个方法没什么实际用处主要为了练习,代码如下:
1 /// <summary>
2 /// Service1 的摘要说明
3 /// </summary>
4 [WebService(Namespace = "http://tempuri.org/")]
5 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
6 [ToolboxItem(false)]
7 public class Service1 : System.Web.Services.WebService
8 {
9
10 [WebMethod]
11 public string HelloWorld(string Temp1,string Temp2)
12 {
13 return "参数1:" + Temp1 + " 参数2:" + Temp2;
14 }
15 }
编译成功后发布到本地服务器,在本例子中发布后Web Service路径为“http://localhost/InvokeService/Service1.asmx ”
第三步,创建测试应用程序,在测试应用程序里引入第一步生成的DLL,运行后界面如下:
代码如下:
1 private void button1_Click(object sender, EventArgs e)
2 {
3 string url = "http://localhost/InvokeService/Service1.asmx";
4 string[] args = new string[2];
5 args[0] = this.textBox1.Text;
6 args[1] = this.textBox2.Text;
7
8 object result = InvokeWebService.WebServiceHelper.InvokeWebService(url, "HelloWorld", args);
9 this.textBox3.Text = result.ToString();
10
11 }
调用Web Service后的运行结果如下:
总结:本例主要用到了以下四个知识点:
(1)WebService相关知识 ;