ASP.NET 动态加载WebService功能

        在某些情况下,我们不能修改项目,重新引入一个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也是同类型,否则调用会因为类型无法转换而失败。
 
附上自做代码小例子。提供给大家下载扩充交流。https://files.cnblogs.com/tank-lizi/DynamicWebService.rar 

posted on 2012-01-05 15:37  tank_坦克  阅读(419)  评论(0编辑  收藏  举报

导航