在某些情况下,我们不能修改项目,重新引入一个WebService,然后再修改代码编译。所以最好解决办法是,通过一个小的dll,或者是cs文件,来实现动态加载webservice,这样现有项目,只需要在Web.config中加入一个webservice引用路径节点即可。参考别人做的例子,现在自己编码实现了一下,大体过程如下详述,主要代码,还是参考了论坛里别的朋友的帖子,不过是再次整理了下顺序,表示感谢,呵呵!
现在用VS2010编码,做个Demo实例。
1.服务器端WebService实例:
新建一个项目,提供两个方法,一个是返回一个ArrayList数组,一个是带参数方法,返回一个字符串。至于WebService支持的返回参数类型,不做详述。至少泛型是不支持的。
代码如下:
[WebMethod(Description = "返回数组列表方法")]
public ArrayList GetALString()
{
return GetArrayListString();
}[WebMethod(Description = "带有参数方法")]
public string GetMsgFromService(object[] arges)
{
return GetHelloWord((string)arges[0], (string)arges[1]);
}
/// <summary>
/// 返回Arraylist数组
/// </summary>
/// <returns></returns>
private ArrayList GetArrayListString()
{
ArrayList reList = new ArrayList();
reList.Add("Dynamic");
reList.Add("WebService");
reList.Add("True");
return reList;
}
/// <summary>
/// 根据传入参数,返回一个组合字符串
/// </summary>
/// <param name="sName"></param>
/// <param name="sWrod"></param>
/// <returns></returns>
private string GetHelloWord(string sName, string sWrod)
{
return "This Message From Service【"+ sName + ": "+ sWrod +"】";
}
2.客户端调用WebService类代码如下:
using System; using System.Collections.Generic; using System; using System.IO; using System.Net; using System.CodeDom; using System.Configuration; using System.Reflection; using System.CodeDom.Compiler; using Microsoft.CSharp; using System.Web.Services.Description; namespace WebDemo { class ServiceClass { public static SortedList<string, Type> _typeList = new SortedList<string, Type>(); #region InvokeWebService private static string m_ServiceIP = ConfigurationManager.AppSettings["WebServiceIP"]; private static string m_ServiceNamespace = ConfigurationManager.AppSettings["WebServiceNamespace"]; private static string sClassName = GetWsClassName(m_ServiceIP); private static string GetCacheKey() { return m_ServiceIP + "_ServiceData_" + sClassName; } private static Type GetTypeFromCache() { string key = GetCacheKey(); foreach (KeyValuePair<string, Type> pair in _typeList) { if (key == pair.Key) { return pair.Value; } } return null; } private static Type GetTypeFromWebService() { string @namespace = m_ServiceNamespace; //获取WSDL WebClient wc = new WebClient(); Stream stream = wc.OpenRead(m_ServiceIP + "?WSDL"); ServiceDescription sd = ServiceDescription.Read(stream); ServiceDescriptionImporter sdi = new ServiceDescriptionImporter(); sdi.AddServiceDescription(sd, "", ""); CodeNamespace cn = new CodeNamespace(@namespace); //生成客户端代理类代码 CodeCompileUnit ccu = new CodeCompileUnit(); ccu.Namespaces.Add(cn); sdi.Import(cn, ccu); CSharpCodeProvider csc = new CSharpCodeProvider(); ICodeCompiler icc = csc.CreateCompiler(); //设定编译参数 CompilerParameters cplist = new CompilerParameters(); cplist.GenerateExecutable = false; cplist.GenerateInMemory = true; // cplist.OutputAssembly = "CheckWebServer.dll";//输出程序集的名称 cplist.ReferencedAssemblies.Add("System.dll"); cplist.ReferencedAssemblies.Add("System.XML.dll"); cplist.ReferencedAssemblies.Add("System.Web.Services.dll"); cplist.ReferencedAssemblies.Add("System.Data.dll"); //编译代理类 CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu); if (true == cr.Errors.HasErrors) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors) { sb.Append(ce.ToString()); sb.Append(System.Environment.NewLine); } throw new Exception(sb.ToString()); } // Assembly asm = Assembly.LoadFrom("CheckWebServer.dll");//加载前面生成的程序集 //生成代理实例,并调用方法 Assembly assembly = cr.CompiledAssembly; Type t = assembly.GetType(@namespace + "." + sClassName, true, true); return t; } //动态调用web服务 public static object InvokeWebService(string methodName, object[] args) { try { Type t = GetTypeFromCache(); if (t == null) { t = GetTypeFromWebService(); //添加到缓冲中 string key = GetCacheKey(); if (!_typeList.ContainsKey(key)) _typeList.Add(key, t); } object obj = Activator.CreateInstance(t); MethodInfo mi = t.GetMethod(methodName); if (args == null || args.Length < 0) { return mi.Invoke(obj, null); } else { return mi.Invoke(obj, new object[] { args }); } } catch (Exception ex) { throw new Exception(ex.InnerException.Message); } } /// <summary> /// 默认类名为URL中.asmx类名 /// </summary> /// <param name="wsUrl"></param> /// <returns></returns> private static string GetWsClassName(string wsUrl) { string[] parts = wsUrl.Split('/'); string[] pps = parts[parts.Length - 1].Split('.'); return pps[0]; } #endregion } }
3.页面访问调用方法如下:
protected void BTN_Array_Click(object sender, EventArgs e) { object result = ServiceClass.InvokeWebService("GetALString", null); Array list = (Array)result; StringBuilder reText = new StringBuilder(); foreach (string str in list) { reText.Append(str); } LB_Text.Text = reText.ToString(); } protected void BTN_String_Click(object sender, EventArgs e) { object[] args = new object[2]; args[0] = "Tank"; args[1] = "From WebClient"; object result = ServiceClass.InvokeWebService("GetMsgFromService", args); LB_Text.Text = (string)result; }
Ok,小结:
1)的了解WebService调用方法,可返回类型,比如开始返回了个Hashtabale,泛型,这些都是不支持的,反编译,问题又不好查找。
2)动态添加,开始没注意缓存是否已经存在,导致容易出现问题,最好进行缓存插入时,先判断是否已经存在_typeList.ContainsKey(key),不存在再插入。
3)传递参数必须为object类型,且webservice也是同类型,否则调用会因为类型无法转换而失败。
附上自做代码小例子。提供给大家下载扩充交流。http://files.cnblogs.com/tank-lizi/DynamicWebService.rar