首页 > 代码库 > C# 动态加载WebService

C# 动态加载WebService

项目中需要用到WebService的方式来进行两个服务之间的方法调用,之前都是在项目中添加服务引用的方式来实现,但是这种方式有一个弊端,就是如果提供WebService服务的一方的IP、端口一旦变更,

调用的一方代码就需要重新编译部署,实际使用不是很方便,因此就采用了下面的方法,通过在代码中动态加载WebService的方式,把IP地址、端口都做成配置项。这样如果只是url的ip和端口出现变更,

就不需要再去重新编译代码了。

具体代码如下:

    public static class WebServiceHelper
    {
        static SortedList<string, Type> _typeList = new SortedList<string, Type>();

        #region InvokeWebService

        static string GetCacheKey(string url, string className)
        {
            return url.ToLower() + className;
        }
        static Type GetTypeFromCache(string url, string className)
        {
            string key = GetCacheKey(url, className);
            foreach (KeyValuePair<string, Type> pair in _typeList)
            {
                if (key == pair.Key)
                {
                    return pair.Value;
                }
            }

            return null;
        }
        static Type GetTypeFromWebService(string url, string className)
        {            
            if ((className == null) || (className == ""))
            {
                className = GetWsClassName(url);
            }

            //获取WSDL
            WebClient wc = new WebClient();
            Stream stream = wc.OpenRead(url);
            ServiceDescription sd = ServiceDescription.Read(stream);

            ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
            sdi.AddServiceDescription(sd, "", "");            
            CodeNamespace cn = new CodeNamespace();

            //生成客户端代理类代码
            CodeCompileUnit ccu = new CodeCompileUnit();
            ccu.Namespaces.Add(cn);
            sdi.Import(cn, ccu);
            CSharpCodeProvider csc = new CSharpCodeProvider();            

            //设定编译参数
            CompilerParameters cplist = new CompilerParameters();
            cplist.GenerateExecutable = false;
            cplist.GenerateInMemory = true;
            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 = csc.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());
            }

            //生成代理实例,并调用方法
            System.Reflection.Assembly assembly = cr.CompiledAssembly;            
            Type t = assembly.GetType(className, true, true);

            return t;
        }

        /// <summary>
        /// 动态调用web服务
        /// </summary>
        /// <param name="url">WebService地址</param>
        /// <param name="methodName">需要调用的方法</param>
        /// <param name="args">方法用到的参数列表(需要按照顺序)</param>
        /// <returns></returns>

        public static object InvokeWebService(string url, string methodName, object[] args)
        {
            return InvokeWebService(url, null, methodName, args);
        }

        public static object InvokeWebService(string url, string className, string methodName, object[] args)
        {
            try
            {
                Type t = GetTypeFromCache(url, className);
                if (t == null)
                {
                    t = GetTypeFromWebService(url, className);

                    //添加到缓冲中
                    string key = GetCacheKey(url, className);
                    _typeList.Add(key, t);
                }

                object obj = Activator.CreateInstance(t);
                MethodInfo mi = t.GetMethod(methodName);

                return mi.Invoke(obj, args);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));
            }
        }

        private static string GetWsClassName(string wsUrl)
        {
            string[] parts = wsUrl.Split(/);
            string[] pps = parts[parts.Length - 1].Split(?);

            return pps[0];
        }
        #endregion
    }

这是最底层的方法类,在实际使用中,我又在上层封装了一个具体接口方法调用的类,示例如下:

    public class WebHelper
    {

        ServiceReference.findSceneVideoDataServicePortTypeClient ts = new ServiceReference.findSceneVideoDataServicePortTypeClient();
        LogPrn logger = new LogPrn("WebHelper");

        //现勘webservice地址
        private string xkWebserveUrl = "";

        public WebHelper(string webserveurl)
        {
            xkWebserveUrl = webserveurl; 
        }
        

             
        /// <summary>
        /// 数量获取服务
        /// </summary>
        /// <param name="unitcode">六位单位代码(选填)</param>
        /// <param name="kno">关联编号(选填)</param>
        /// <param name="updatetimefrom">起始时间(yyyy-mm-dd HH:MM:SS)(选填)</param>
        /// <param name="updatetimeto">结束时间(yyyy-mm-dd HH:MM:SS)(选填)</param>
        /// <param name="scenedetail">发案地点(选填)</param>
        /// <param name="allflag">查询范围(必填)</param>
        /// <param name="caseno">案件编号(A号)(选填)</param>
        /// <returns>-1:单位代码必须为6位数字;
        /// -2:时间不符合格式:yyyy-mm-dd HH:MM:SS;
        /// n(n>=0):根据条件查询结果数量;
        /// -3:其他异常</returns>
        /// <summary> 
        public int getOriginalDataCount(string unitcode, string kno, string updatetimefrom, string updatetimeto, string scenedetail, string allflag, string caseno)
        {
            //if(string.IsNullOrEmpty(unitcode))
            //{
            //    return -3;
            //}
            if (string.IsNullOrEmpty(allflag))
            {
                return -3;
            }
            int result = 0;
            try
            {               
                //result = ts.getOriginalDataCount(unitcode, kno, updatetimefrom, updatetimeto); 
                string[] args = new string[7];
                args[0] = unitcode;
                args[1] = kno;
                args[2] = updatetimefrom;
                args[3] = updatetimeto;
                args[4] = scenedetail;
                args[5] = allflag;
                args[6] = caseno;
                object obj = WebServiceHelper.InvokeWebService(xkWebserveUrl, "getOriginalDataCount", args);
                result = (int)obj;
            }
            catch (Exception ex)
            {
                //TODO 记录异常信息
                logger.Error(ex.ToString());
                result = -3;
            }
            return result;
        }

        

      
        /// <summary>
        /// 安装位置信息反馈
        /// </summary>
        /// <param name="macAddress">Mac地址(必填)</param>
        /// <param name="installPath">视频客户端安装路径(必填),绝对路径,要精确到exe文件</param>
        /// <returns>1.反馈成功,0.反馈失败,-1.mac地址格式不正确,-2.安装路径格式不正确</returns>
        public string InstallPositionFeedBack(string macAddress, string installPath)
        {
            if (string.IsNullOrEmpty(macAddress) || string.IsNullOrEmpty(installPath))
            {
                return null;
            }
            string result = "";
            try
            {                
                string[] args = new string[2];
                args[0] = macAddress;
                args[1] = installPath;
                object obj = WebServiceHelper.InvokeWebService(xkWebserveUrl, "installPositionFeedBack", args);
                result = (string)obj;
                return result;
            }
             catch (Exception ex)
            {
                //TODO 记录异常信息
                logger.Error(ex.ToString());
                return null;
            }
        }
    }

 

C# 动态加载WebService