文章出處

添加wcf服務引用時,vs.net本來就會幫我們在app.config/web.config里生成各種配置,這沒啥好研究的,但本文談到的配置并不是這個。先看下面的圖:

通常,如果采用.NET的WCF技術來架構SOA風格的應用,我們會把項目做一些基本的分層,如上圖:

01. contract層:通常定義服務的接口(即服務契約ServiceContract,指明該服務提供了哪些方法可供外部調用)、以及接口方法中傳輸的Model定義(即:數據契約DataContract,指明方法中的對象參數的Class定義)

02. implementation層:即服務接口的實現

03. host層:wcf最終需要一個宿主環境,如果是web應用,最簡單的辦法莫過于直接寄宿在IIS上

04. client層:即服務的消費方,如果是b/s應用,通常就是一個web application

實際部署時,一般將wcf服務層和client層分開部署,如下圖:

如果并發數隨著業務的增長而增長,不管是client層的website,還是服務層的service,加上其它技術,比如集群或負載均衡之類,可以很方便進行擴充。服務的實現邏輯也可以方便的單獨的修改替換(前提是服務契約相對穩定)

但如果應用的規模較小,出于成本考慮,完全有可能Service層和Website Client部署在一臺機器上,雖然1個IIS上架2個站點完全沒有問題,但是總歸有點不爽,既然都在一臺機器上了,為啥還要自己調用自己,增加無謂的開銷呢?

最好是在不修改原來代碼的前提下,通過簡單的配置文件修改,就能讓原來遠程調用WCF的方式,改成直接調用本地DLL程序集,反過來也一樣,這樣就比較靈活了。事實上,我們公司很多項目就是這樣處理的,規模小的應用,直接全都部署在一臺機器上,等應用規模上去了,再分開部署,代碼完全不用動,只要修改相關配置即可。

原理其實非常簡單,反射即可,先在Client層的web.config或app.config中,增加類似以下節點:

1   <appSettings>
2     <!--調用方式:Remote遠程調用,Local本地調用(注:本地調用時,bin目錄下必須有[服務實現類]的dll)-->
3     <add key="CallType" value="Remote"/>  
4     <!--本地調用時,程序集的名稱-->
5     <add key="AssemblyName" value="sjtu.wcf.demo.implementation"/>
6     <!--本地調用時,[服務實現類]的名稱-->
7     <add key="ServiceTypeName" value="sjtu.wcf.demo.implementation.DemoService"/>
8   </appSettings>

CallType就決定了調用方式:“遠程調用”或“本地DLL調用”。然后在本地寫一個調用的Client類:(注:wcf的調用方式,參考了dudu的文章“享受無止境 - 改進版WCF Client”)

 1 using System;
 2 using System.Linq.Expressions;
 3 using System.Reflection;
 4 using System.ServiceModel;
 5 using sjtu.wcf.demo.client.configs;
 6 
 7 namespace sjtu.wcf.demo.client
 8 {
 9     /// <summary>
10     /// Wcf客戶端
11     /// </summary>
12     /// <typeparam name="T">ServiceContract接口</typeparam>
13     public class WcfClient<T> where T : class
14     {
15 
16         private readonly string assemblyName;
17         private readonly string implTypeName;
18         private readonly string callType;
19 
20         public WcfClient()
21         {
22             callType = ConfigHelper.CallType.ToLower();
23             if (callType == CallType.Local.ToString().ToLower())
24             {
25                 assemblyName = ConfigHelper.AssemblyName;
26                 implTypeName = ConfigHelper.ServiceTypeName;
27             }
28         }
29 
30         /// <summary>
31         /// 對外提供的Call方法
32         /// </summary>
33         /// <typeparam name="R"></typeparam>
34         /// <param name="expression"></param>
35         /// <returns></returns>
36         public R Call<R>(Expression<Func<T, R>> expression)
37         {
38             if (callType == CallType.Local.ToString().ToLower())
39             {
40                 return InvokeLocalMethod<R>(expression);
41             }
42             return InvokeRemoteMethod<R>(expression);
43         }
44 
45         /// <summary>
46         /// 調用本地程序集方法
47         /// </summary>
48         /// <typeparam name="R"></typeparam>
49         /// <param name="operation"></param>
50         /// <returns></returns>
51         private R InvokeLocalMethod<R>(Expression<Func<T, R>> operation)
52         {
53             Assembly asm = Assembly.Load(new AssemblyName(assemblyName));
54             T t = (T)asm.CreateInstance(implTypeName);
55             R result = operation.Compile().Invoke(t);
56             return result;
57         }
58 
59         /// <summary>
60         /// 調用遠程wcf方法
61         /// </summary>
62         /// <typeparam name="R"></typeparam>
63         /// <param name="operation"></param>
64         /// <returns></returns>
65         private R InvokeRemoteMethod<R>(Expression<Func<T, R>> operation)
66         {
67             ChannelFactory<T> channelFactory = new ChannelFactory<T>("*");
68 
69             T channel = channelFactory.CreateChannel();
70             var client = (IClientChannel)channel;
71             client.Open();
72             R result = operation.Compile().Invoke(channel);
73             try
74             {
75                 if (client.State != CommunicationState.Faulted)
76                 {
77                     client.Close();
78                 }
79             }
80             catch
81             {
82                 client.Abort();
83             }
84             return result;
85         }
86     }
87 }
View Code

這樣調用時,只需要一行代碼即可:

1 var students = new WcfClient<IStudent>().Call(c => c.GetStudents("jerry"));

完整示例代碼下載:http://files.cnblogs.com/yjmyzz/WcfInvoke.zip


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()