国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

WCF技術(shù)剖析之三十:一個(gè)很有用的WCF調(diào)用編程技巧

2019-11-17 03:54:06
字體:
供稿:網(wǎng)友
在進(jìn)行基于會(huì)話信道的WCF服務(wù)調(diào)用中,由于受到并發(fā)信道數(shù)量的限制,我們需要及時(shí)的關(guān)閉信道;當(dāng)遇到某些異常,我們需要強(qiáng)行中止(Abort)信道,相關(guān)的原理,可以參考我的文章《服務(wù)代理不能得到及時(shí)關(guān)閉會(huì)有什么后果?》。在真正的企業(yè)級(jí)開發(fā)中,正如我們一般不會(huì)讓開發(fā)人員手工控制數(shù)據(jù)庫連接的開啟和關(guān)閉一樣,我們一般也不會(huì)讓開發(fā)人員手工去創(chuàng)建、開啟、中止和關(guān)閉信道,這些工作是框架應(yīng)該完成的操作。這篇文章,我們就來介紹如果通過一些編程技巧,讓開發(fā)者能夠無視“信道”的存在,像調(diào)用一個(gè)普通對(duì)象一樣進(jìn)行服務(wù)調(diào)用。

一、正常的服務(wù)調(diào)用方式
如果通過ChannelFactory<TChannel>創(chuàng)建用于服務(wù)調(diào)用的代理,下面的代碼片段描述了客戶端典型的服務(wù)調(diào)用形式:將服務(wù)調(diào)用在基于代理對(duì)象的using塊中,并通過try/catch進(jìn)一步對(duì)服務(wù)調(diào)用操作進(jìn)行異常處理。當(dāng)TimeoutException或者CommunicationException被捕獲后,調(diào)用Abort方法將信道中止。當(dāng)程序執(zhí)行到using的末尾,Dispose方法會(huì)進(jìn)一步調(diào)用Close方法對(duì)信道進(jìn)行關(guān)閉。

class PRogram{    static void Main(string[] args)    {        using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice"))        {            ICalculator calculator = channelFactory.CreateChannel();            using (calculator as IDisposable)            {                try                {                    Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, calculator.Add(1, 2));                }                catch (TimeoutException)                {                    (calculator as ICommunicationObject).Abort();                    throw;                }                catch (CommunicationException)                {                    (calculator as ICommunicationObject).Abort();                    throw;                }            }        }         Console.Read();    }}
二、借助通過Delegate實(shí)現(xiàn)異常處理和服務(wù)代理的關(guān)閉
雖然上面的編程方式是正確的服務(wù)調(diào)用方式,但是在真正的應(yīng)用中,如果在每處進(jìn)行服務(wù)調(diào)用的地方都采用上面的方式,在我看來是不能容忍的。這不但會(huì)讓你的程序顯得臃腫不堪,而且?guī)矸浅6嘀貜?fù)的代碼,此外頻繁創(chuàng)建ChannelFactory<TChannel>對(duì)性能也會(huì)有影響。我們可以通過一些公共個(gè)方法實(shí)現(xiàn)對(duì)重復(fù)代碼(ChannelFactory<TChannel>的創(chuàng)建,服務(wù)調(diào)用的創(chuàng)建、中止和關(guān)閉,以及異常處理)。為此我創(chuàng)建了如下一個(gè)ServiceInvoker類型,通過兩個(gè)重載的Invoke方法實(shí)現(xiàn)對(duì)目標(biāo)服務(wù)的調(diào)用。

   1: using System;   2: using System.Collections.Generic;   3: using System.ServiceModel;   4: namespace Artech.Lib   5: {   6:     public class ServiceInvoker   7:     {   8:         private static Dictionary<string, ChannelFactory> channelFactories = new Dictionary<string, ChannelFactory>();   9:         private static object syncHelper = new object();  10:    11:         private static ChannelFactory<TChannel> GetChannelFactory<TChannel>(string endpointConfigurationName)  12:         {  13:             ChannelFactory<TChannel> channelFactory = null;  14:             if (channelFactories.ContainsKey(endpointConfigurationName))  15:             {  16:                 channelFactory = channelFactories[endpointConfigurationName] as ChannelFactory<TChannel>;  17:             }  18:    19:             if (null == channelFactory)  20:             {  21:                 channelFactory = new ChannelFactory<TChannel>(endpointConfigurationName);  22:                 lock (syncHelper)  23:                 {  24:                     channelFactories[endpointConfigurationName] = channelFactory;  25:                 }  26:             }  27:             return channelFactory;  28:         }  29:    30:         public static void Invoke<TChannel>(Action<TChannel> action, TChannel proxy)  31:         {  32:             ICommunicationObject channel = proxy as ICommunicationObject;  33:             if (null == channel)  34:             {  35:                 throw new ArgumentException("The proxy is not a valid channel implementing the ICommunicationObject interface", "proxy");  36:             }  37:             try  38:             {  39:                 action(proxy);  40:             }  41:             catch (TimeoutException)  42:             {  43:                 channel.Abort();  44:                 throw;  45:             }  46:             catch (CommunicationException)  47:             {  48:                 channel.Abort();  49:                 throw;  50:             }  51:             finally  52:             {  53:                 channel.Close();  54:             }  55:         }  56:    57:         public static TResult Invoke<TChannel, TResult>(Func<TChannel, TResult> function, TChannel proxy)  58:         {  59:             ICommunicationObject channel = proxy as ICommunicationObject;  60:             if (null == channel)  61:             {  62:                 throw new ArgumentException("The proxy is not a valid channel implementing the ICommunicationObject interface", "proxy");  63:             }  64:             try  65:             {  66:               return  function(proxy);  67:             }  68:             catch (TimeoutException)  69:             {  70:                 channel.Abort();  71:                 throw;  72:             }  73:             catch (CommunicationException)  74:             {  75:                 channel.Abort();  76:                 throw;  77:             }  78:             finally  79:             {  80:                 channel.Close();  81:             }  82:         }  83:    84:         public static void Invoke<TChannel>(Action<TChannel> action, string endpointConfigurationName)  85:         {  86:             Guard.ArgumentNotNullOrEmpty(endpointConfigurationName, "endpointConfigurationName");  87:             Invoke<TChannel>(action, GetChannelFactory<TChannel>(endpointConfigurationName).CreateChannel());  88:         }  89:    90:         public static TResult Invoke<TChannel, TResult>(Func<TChannel, TResult> function, string endpointConfigurationName)  91:         {  92:             Guard.ArgumentNotNullOrEmpty(endpointConfigurationName, "endpointConfigurationName");             93:             return Invoke<TChannel, TResult>(function, GetChannelFactory<TChannel>(endpointConfigurationName).CreateChannel());  94:         }          95:     }  96: }

處于對(duì)性能的考慮,避免對(duì)ChannelFactory<TChannel>的頻繁創(chuàng)建,通過一個(gè)字典對(duì)象將創(chuàng)建出來的ChannelFactory<TChannel>緩存起來;兩個(gè)Invoke方法中,服務(wù)的調(diào)用通過兩個(gè)Delegate對(duì)象(Action<TChannel>和Func<TChannel, TResult>)表示,另一個(gè)參數(shù)表示終結(jié)點(diǎn)的配置名稱。那么這時(shí)的服務(wù)調(diào)用就會(huì)變得相當(dāng)簡(jiǎn)單:

   1: using System;   2: using Artech.Lib;   3: using Artech.WcfServices.Contracts;   4: namespace Artech.WcfServices.Clients   5: {   6:     class Program   7:     {   8:         static void Main(string[] args)   9:         {  10:             int result = ServiceInvoker.Invoke<ICalculator, int>(calculator => calculator.Add(1, 2), "calculatorservice");  11:             Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, result);  12:             Console.Read();  13:         }  14:     }  15: }
三、對(duì)ServiceInvoker的改進(jìn)
實(shí)際上,為了對(duì)服務(wù)調(diào)用實(shí)現(xiàn)細(xì)節(jié)進(jìn)行進(jìn)一步的封裝,一般地我們可以將其定義在一個(gè)獨(dú)立的層中,比如服務(wù)代理層(這里的層不一定像數(shù)據(jù)訪問層、業(yè)務(wù)邏輯層一樣需要一個(gè)明顯的界限,這里可能就是一個(gè)單獨(dú)的類型而已)。在這種情況下,我們可以上面的ServiceInvoker方法進(jìn)行一定的改造,使之更加符合這種分層的場(chǎng)景。上面我們調(diào)用靜態(tài)方法的形式進(jìn)行服務(wù)的調(diào)用,現(xiàn)在我們需要的是:實(shí)例化服務(wù)代理對(duì)象,并調(diào)用相應(yīng)的方法。為此,我創(chuàng)建了一個(gè)泛型的ServiceInvoker<TChannel>類型,該類型繼承自上述的ServiceInvoker,泛型類型表示服務(wù)契約類型。ServiceInvoker<TChannel>定義如下:

   1: using System;   2: namespace Artech.Lib   3: {   4:     public class ServiceInvoker<TChannel>:ServiceInvoker   5:     {   6:         public string EndpointConfigurationName   7:         {get; private set;}   8:     9:         public ServiceInvoker(string endpointConfigurationName)  10:         {  11:             Guard.ArgumentNotNullOrEmpty(endpointConfigurationName, "endpointConfigurationName");  12:             this.EndpointConfigurationName = endpointConfigurationName;  13:         }  14:    15:         public void Invoke(Action<TChannel> action)  16:         {  17:             Invoke<TChannel>(action, this.EndpointConfigurationName);  18:         }  19:    20:         public TResult Invoke<TResult>(Func<TChannel, TResult> function)  21:         {  22:             return Invoke<TChannel, TResult>(function, this.EndpointConfigurationName);  23:         }  24:     }  25: }
通過傳入終結(jié)點(diǎn)配置名稱創(chuàng)建ServiceInvoker<TChannel>對(duì)象,直接通過調(diào)用基類的靜態(tài)方法實(shí)現(xiàn)了兩個(gè)Invoke方法。

在分層設(shè)計(jì)中,為每一個(gè)層定義的組件創(chuàng)建基類是一個(gè)很常見的設(shè)計(jì)方式。在這里,假設(shè)所有的服務(wù)代理類型均繼承自基類:ServiceProxyBase<TChannel>,泛型類型為服務(wù)契約類型。同樣通過傳入終結(jié)點(diǎn)配置名稱創(chuàng)建服務(wù)代理,并借助于通過Invoker屬性表示的ServiceInvoker<TChannel>對(duì)象進(jìn)行服務(wù)的調(diào)用。ServiceProxyBase<TChannel>定義如下:

   1: namespace Artech.Lib   2: {   3:     public class ServiceProxyBase<TChannel>   4:     {   5:         public virtual ServiceInvoker<TChannel> Invoker   6:         { get; private set; }   7:     8:         public ServiceProxyBase(string endpointConfigurationName)   9:         {  10:             Guard.ArgumentNotNullOrEmpty(endpointConfigurationName, "endpointConfigurationName");  11:             this.Invoker = new ServiceInvoker<TChannel>(endpointConfigurationName);  12:         }  13:     }  14: }
那么,具體的服務(wù)代理類型就可以通過如下的方式定義了:

   1: using Artech.Lib;   2: using Artech.WcfServices.Contracts;   3: namespace Artech.WcfServices.Clients   4: {   5:     public class CalculatorProxy : ServiceProxyBase<ICalculator>, ICalculator   6:     {   7:         public CalculatorProxy():base(Constants.EndpointConfigurationNames.CalculatorService)   8:         { }   9:    10:         public int Add(int x, int y)  11:         {  12:             return this.Invoker.Invoke<int>(calculator => calculator.Add(x, y));  13:         }  14:     }  15:    16:     public class Constants  17:     {  18:         public class EndpointConfigurationNames  19:         {  20:             public const string CalculatorService = "calculatorservice";  21:         }  22:     }  23: }
那么現(xiàn)在服務(wù)代理的消費(fèi)者(一般是Presenter層對(duì)象),就可以直接實(shí)例化服務(wù)代理對(duì)象,并調(diào)用相應(yīng)的方法(這里的方法與服務(wù)契約方法一致)即可,所有關(guān)于服務(wù)調(diào)用的細(xì)節(jié)均被封裝在服務(wù)代理中。

   1: using System;   2: using Artech.Lib;   3: using Artech.WcfServices.Contracts;   4: namespace Artech.WcfServices.Clients   5: {   6:     class Program   7:     {   8:         static void Main(string[] args)   9:         {  10:             CalculatorProxy calculatorProxy = new CalculatorProxy();  11:             int result = calculatorProxy.Add(1, 2);  12:             Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, result);  13:             Console.Read();  14:         }  15:     }  16: }
四、局限

這個(gè)解決方案有一個(gè)很大的局限:服務(wù)方式不能包含ref和out參數(shù),因?yàn)檫@兩種類型的參數(shù)不能作為匿名方法的參數(shù)。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 札达县| 沧州市| 雅江县| 西乌珠穆沁旗| 三明市| 武穴市| 咸丰县| 社会| 长寿区| 阜平县| 罗源县| 宽城| 全椒县| 北碚区| 醴陵市| 宜州市| 旅游| 光泽县| 西乌珠穆沁旗| 南木林县| 左云县| 清远市| 郯城县| 南澳县| 通州区| 赤城县| 哈密市| 绥阳县| 奈曼旗| 仪陇县| 平罗县| 文登市| 雅江县| 华宁县| 宝坻区| 吴旗县| 察哈| 咸宁市| 商都县| 宁乡县| 卓尼县|