用C#调用WebService,一般简单的都是在VS引用里右键添加Web引用,强大的VS就会把所有的代码给你自动生成出来,你要做的就是只要调用就可以了,这里就不详细介绍了。
先说说我这里的背景,我在做一个软件时,WebService的地址端口等信息不是固定的,会有一个配置文件,用户会自己修改配置文件,这样的话,如果我用自动生成的方式就不可以了,你想啊,我原来WebService的地址是A,你改完之后变成B了,我自动生成的是A的service代码,换成B了还能调用到吗?
经过各种百度终于找到了动态调用的方法,然后自己改进了一下,如下:
1 using System; 2 using System.CodeDom; 3 using System.CodeDom.Compiler; 4 using System.Collections.Generic; 5 using System.IO; 6 using System.Net; 7 using System.Web.Services.Description; 8 using Microsoft.CSharp; 9 using System.Threading; 10 11 namespace Service 12 { 13 public class WebServiceHelp 14 { 15 /// <summary> 16 /// Save assemblys by the specific webservice url 17 /// </summary> 18 private static Dictionary<string, System.Reflection.Assembly> Assemblys = new Dictionary<string, System.Reflection.Assembly>(); 19 20 /// <summary> 21 /// Invoke method of web service 22 /// </summary> 23 /// <param name="url">service address</param> 24 /// <param name="className">WebService class name</param> 25 /// <param name="methodName">Method Name</param> 26 /// <param name="args">Arguments</param> 27 /// <returns>Return value</returns> 28 public static object InvokeWebService(string url, string className, string methodName, params object[] args) 29 { 30 string @namespace = "Service"; 31 if (string.IsNullOrEmpty(className)) 32 { 33 className = GetWsClassName(url); 34 } 35 try 36 { 37 System.Reflection.Assembly assembly = null; 38 if (!Assemblys.ContainsKey(url)) 39 { 40 //获取WSDL 41 WebClient wc = new WebClient(); 42 Stream stream = wc.OpenRead(url + "?WSDL"); 43 44 ServiceDescription sd = ServiceDescription.Read(stream); 45 ServiceDescriptionImporter sdi = new ServiceDescriptionImporter(); 46 sdi.AddServiceDescription(sd, "", ""); 47 CodeNamespace cn = new CodeNamespace(@namespace); 48 //生成客户端代理类代码 49 CodeCompileUnit ccu = new CodeCompileUnit(); 50 ccu.Namespaces.Add(cn); 51 sdi.Import(cn, ccu); 52 CSharpCodeProvider icc = new CSharpCodeProvider(); 53 //设定编译参数 54 CompilerParameters cplist = new CompilerParameters(); 55 cplist.GenerateExecutable = false; 56 cplist.GenerateInMemory = true; 57 cplist.ReferencedAssemblies.Add("System.dll"); 58 cplist.ReferencedAssemblies.Add("System.XML.dll"); 59 cplist.ReferencedAssemblies.Add("System.Web.Services.dll"); 60 cplist.ReferencedAssemblies.Add("System.Data.dll"); 61 //编译代理类 62 CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu); 63 if (true == cr.Errors.HasErrors) 64 { 65 System.Text.StringBuilder sb = new System.Text.StringBuilder(); 66 foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors) 67 { 68 sb.Append(ce.ToString()); 69 sb.Append(System.Environment.NewLine); 70 } 71 throw new Exception(sb.ToString()); 72 } 73 //生成代理实例,并调用方法 74 assembly = cr.CompiledAssembly; 75 Assemblys[url] = assembly; 76 } 77 else 78 { 79 assembly = Assemblys[url]; 80 } 81 82 Type t = assembly.GetType(@namespace + "." + className, true, true); 83 object obj = Activator.CreateInstance(t); 84 System.Reflection.MethodInfo mi = t.GetMethod(methodName); 85 return mi.Invoke(obj, args); 86 } 87 catch (ThreadAbortException tae) 88 { 89 //Logger.Warn(tae.ToString()); 90 return null; 91 } 92 catch (Exception ex) 93 { 94 //Logger.Error(ex.ToString()); 95 throw new Exception(ex.Message); 96 } 97 } 98 99 private static string GetWsClassName(string wsUrl) 100 { 101 string[] parts = wsUrl.Split('/'); 102 string[] pps = parts[parts.Length - 1].Split('.'); 103 return pps[0]; 104 } 105 } 106 }
这里说明一下,开头的Assemblys是用来存放动态编译的Assembly信息,不然的话,每次调用Service方法都要重新生成一边,那是相当的慢啊!
在调用的时候只要传入相应的信息就可以了,调用时:
1 public string GetPathByVMID(string vmId) 2 { 3 return WebServiceHelp.InvokeWebService(ConfigConstant.ServiceAdress, "VMServiceService", "getPathByVmID", vmId) as string; 4 }
ServiceAdress的格式"http://127.0.0.1:8080/services/VMService";