Web Services 和WCF技術分析之反射

1,二者的區別。前端

WCF能夠不依賴於IIS。程序員

WCF能夠配置成BasicHttpBinding來兼容(或者說變身成)WS。
WCF能夠基於TCP或者MessegeQueue來傳輸數據。
WCF的可配置性比WS強,好比安全性。
WCF能夠是有狀態的,並支持事務。
WCF 支持多種通訊協議 Http/Https 、TCP/UDP、MSMQ、命名管道、對等網、
  消息可達性、事務流等。
WCF 能夠與ASP.NET 集成、共享一個上下文(HttpContext)。
WCF 支持多種消息傳輸格式 :text,binary,mtom,Json 等。
WCF 安全性要強:支持對稱安全、非對稱安全、消息安全、傳輸安全、
  SSL 流安全、Windows 流安全等。
WCF 支持多種會話模式:單向、雙向、請求/響應。
WCF 支持REST 。
WCF 支持多種格式化方式。DataContractSerializer、XmlSerializer、 
  DataContractJsonSerializer 等。
WCF 支持 WAS hosting、Windows 服務 hosting、Self-Hosting、IIS hosting 等。
WCF 支持多種併發模式:單例、單調、會話 web

2,這裏要講的是經過純運行時代理實現方法的調用。主要用到的技術是反射。編程

一,web servicesjson

private object agent;安全

        private Type agentType;併發

        private const string CODE_NAMESPACE = "Demo";ide

        /// <summary<  函數

        /// 構造函數  性能

        /// </summary<  

        /// <param name="url"<</param<  

        public WebServiceAgent(string url)

        {

            try

            {

              

                XmlTextReader reader = new XmlTextReader(url + "?wsdl");

 

                //建立和格式化 WSDL 文檔  

 

                System.Web.Services.Description.ServiceDescription sd = System.Web.Services.Description.ServiceDescription.Read(reader);

 

                //建立客戶端代理代理類  

                ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();

                sdi.AddServiceDescription(sd, null, null);

 

                //使用 CodeDom 編譯客戶端代理類  

                CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);

                CodeCompileUnit ccu = new CodeCompileUnit();

                ccu.Namespaces.Add(cn);

                sdi.Import(cn, ccu);

                Microsoft.CSharp.CSharpCodeProvider icc = new Microsoft.CSharp.CSharpCodeProvider();

                CompilerParameters cp = new CompilerParameters();

                CompilerResults cr = icc.CompileAssemblyFromDom(cp, ccu);

                agentType = cr.CompiledAssembly.GetTypes()[0];

                agent = Activator.CreateInstance(agentType);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

實現思路:利用wsdl生成xml文檔,利用反射生成客戶端代理 agent = Activator.CreateInstance(agentType);

二,WCF,引用WCF服務,網上可以找到詳細的例子,但都集中於兩種方式,1,添加服務引用,這樣每次服務變動,須要更新一下引用。2,經過ChannelFactory快速綁定一個終結點,但也須要客戶端代理(契約)。WCF一個好處是它是基於契約的,意思是我無論裏面如何實現,客戶端只關心契約的結果。在構建複雜應用場景中,如何讓咱們代碼高內聚,低耦合,有同窗說了能夠面向接口編程呀,誠然,WCF實現了,這是終極解決方案麼?固然不是,假如接口變更了麼?相信這是全部程序員的噩夢。.net用反射機制來解決此類問題,全部操做動態生成,這樣,咱們不用在關心服務端的變動會影響到客戶端。只需閱讀接口文檔,這樣咱們關心的問題轉移到配置文件。這種方式會犧牲一些性能(反射),這裏咱們須要在性能和便於維護以前平衡了。

  public WebServiceAgent(string url,string aa)

        {

            try

            {

                //獲取WSDL

                WebClient wc = new WebClient();

                Stream stream = wc.OpenRead(url + "?singleWsdl");

                  System.Web.Services.Description.ServiceDescription sd = System.Web.Services.Description.ServiceDescription.Read(stream);

                ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();

                sdi.AddServiceDescription(sd, "", "");

                CodeNamespace cn = new CodeNamespace(CODE_NAMESPACE);

                //生成客戶端代理類代碼

                CodeCompileUnit ccu = new CodeCompileUnit();

                ccu.Namespaces.Add(cn);

                sdi.Import(cn, ccu);

                CodeDomProvider provider = 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 = provider.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());

                }

                //生成代理實例

                agentType = cr.CompiledAssembly.GetTypes()[0];

                agent = Activator.CreateInstance(agentType);

                EndpointAddress address = new EndpointAddress("http://localhost:6666/UserInfo/");

                WSHttpBinding binding = new WSHttpBinding();

               

            }

            catch (Exception ex)

            {

                throw new Exception(ex.InnerException.Message, new Exception(ex.InnerException.StackTrace));

            }

        }

原理同web services。

3,經過代理調用方法,這裏主要介紹WCF,由於沒有親自編碼,後面不對webservices在作介紹。

  public object Invoke(string methodName, params object[] args)

        {

            MethodInfo mi = agentType.GetMethod(methodName);

            try

            {

                var ret = this.Invoke(mi, args);

                var ds = new DataContractJsonSerializer(ret.GetType());

                var ms = new MemoryStream();

                ds.WriteObject(ms, ret);

                var strJSON = Encoding.UTF8.GetString(ms.ToArray());

                ms.Close();

                return strJSON;

            }

            catch (Exception e)

            {

                return e.Message;

            }

            

        }

這裏我默認返回是一個集合,由於客戶端不清楚返回集合的結構,而咱們又不想編寫多餘的客戶端腳本,這裏經過DataContractJsonSerializer實現到json的轉換。這個前提是服務端實體類經過[DataContract]標記爲可被序列化。

        ///<summary<  

        ///調用指定方法  

        ///</summary<  

        ///<param name="method"<方法信息</param<  

        ///<param name="args"<參數,按照參數順序賦值</param<  

        ///<returns<Web服務的返回值</returns<  

        public object Invoke(MethodInfo method, params object[] args)

        {

            try

            {

                return method.Invoke(agent, args);

            }

            catch (Exception e)

            {

                return e.Message;

            }

           

        }

4,關於WCF傳遞參數問題,因爲沒有客戶端代理是動態建立的,咱們用 object[] args存放參數。

服務端代碼:

        [OperationContract]

        LoginCheckResult CheckLogin(string userName, string authorizationCode);

客戶端調用:

   object[] args = new object[2];

           // args[0] = rtbSend.Text;

            args[0] = "superadmin";

            args[1] = "aaa";

           var  receive =  service.Invoke(methodName, args).ToString() ;

這裏service是上面咱們動態生成的代理,methodName是咱們動態解析出來的方法名--CheckLogin

近年來REST風格服務很是流行,這種鬆散的接口是前端界的一股清流,所到之處,無不誇讚,傳統的Web Services和WCF備受歧視,輕量級和安全將是將來主導面向服務編程的兩大特性

相關文章
相關標籤/搜索