不是架构的架构之四:业务层的实现与自动代理
我們在開篇中提到,希望能有一種辦法,能自動適應系統的環境配置,在局域網小型應用中將直接訪問數據庫以獲得最高的性能,在分布式環境中自動使用WCF來獲得較好的安全性和連通性。
但是,我們不希望這樣的特性使我們的開發變得過于復雜,需要在新特性和工作量之間尋求一個合理的平衡點。
?
?
原理分析:
用自動代理的業務層結構如下:
檢測到局域網配置時的情況,將直接返回業務對象實例。
分布式配置的調用情況。
我們可以從圖上看出,使用局域網配置或分布式配置完全取決于自動代理對象,而對于使用者(表現層)是完全透明的。當然,對于分布式配置的情況,傳入業務端的參數和結果都是需要經過序列化的,否則將無法在WCF中傳輸,這是我們在開發業務層時需要注意的問題。
自動代理的對象實現很簡單,我們需要做的就是攔截調用,將調用的信息(業務對象名,方法名,參數)等構建為WCF服務對象的參數,通過統一的服務接口調用服務端,服務端得到調用后,根據調用信息實例化合適的業務對象,調用相應的方法,完成后將結果以統一的返回格式返回給自動代理對象,而這些返回的數據將被反序列化后作為該方法的返回值。
代碼實現:
在目前的開源框架中,Castle和Spring.net都提供了很好的自動代理的類庫。我們將以Spring.net為例來實現自動代理對象。
public static class BizAutoWcfProxy {public static T Get<T>(T instance) where T : class{var p = new ProxyFactory(instance);p.AddAdvice(new AroundAdvise());return p.GetProxy() as T;}internal static IWcfProxy GetMethodProxy(){var service = PubFunc.GetAppSetting("WcfService");if (string.IsNullOrEmpty(service)){return new WcfProxy();}var binding = new NetTcpBinding(SecurityMode.None, false);var f = new ChannelFactory<IWcfProxy>(binding, service);var proxy = f.CreateChannel();return proxy;} }上面是自動代理工廠的實現.這個工廠中,提供了一個供自動代理對象使用的方法GetMethodProxy,這個方法中檢測應用程序配置文件的WcfService配置,如果配置不為空,則創建自動代理對象,否則直接返回.
?
public class AroundAdvise : IMethodInterceptor {public object Invoke(IMethodInvocation invocation){Log.Get().Debug("方法{0}被調用被攔截", invocation.Method.Name);try{var p = BizAutoWcfProxy.GetMethodProxy();//調用信息var m = new MethodProxy{ClassName = invocation.TargetType.AssemblyQualifiedName, //業務對象名MethodName = invocation.Method.Name //方法};//將調用參數也包含在調用信息中if (invocation.Arguments != null && invocation.Arguments.Length > 0)m.Params = invocation.Arguments.ToList().ConvertAll(PubFunc.Serialize.ObjToBytes).ToArray();//調用WCF服務var r = p.Execute(m);//正常的情況,沒有異常出現if (!r.HasException){//返回值object returnValue = r.GetValue();var ind = 0;//處理ref和out的參數的返回invocation.Method.GetParameters().ToList().ForEach(mp =>{if (mp.IsOut){invocation.Arguments[mp.Position] = PubFunc.Serialize.BytesToObj(r.OutValue[ind++]);}});return returnValue;}//出現異常的情況,反序列號異常信息,重新在客戶端拋出var ex = PubFunc.Serialize.BytesToObj(r.Exception) as Exception;if (ex != null) throw ex;throw new Exception("無法反序列化異常信息");}catch (CommunicationException oe){Log.Get().Debug("WCF通訊錯誤", oe);throw;}} }?
上面是方法攔截的實現。這里除了需要考慮正常情況下調用之外,還要考慮服務器端可能發生的異常,這里增加了對異常的處理。
//唯一的WCF接口 [ServiceContract] public interface IWcfProxy {[OperationContract]ReturnValue Execute(MethodProxy m); } //服務實現 public class WcfProxy : IWcfProxy {public ReturnValue Execute(MethodProxy m){try{//服務端實例化業務對象var con = Type.GetType(m.ClassName).GetConstructor(BindingFlags.NonPublic| BindingFlags.Public| BindingFlags.Instance,null,new Type[0],null);var cls = con.Invoke(new object[0]);//處理參數的反序列化var method = cls.GetType().GetMethod(m.MethodName, BindingFlags.Instance | BindingFlags.Public);var pm = new object[0];if (m.Params != null && m.Params.Length > 0)pm = m.Params.ToList().ConvertAll(PubFunc.Serialize.BytesToObj).ToArray();//調用var rlt = method.Invoke(cls, pm);var r = new ReturnValue();r.SetValue(rlt);//處理out參數var outPlist = new List<byte[]>();method.GetParameters().ToList().ForEach(p =>{if(p.IsOut){outPlist.Add(PubFunc.Serialize.ObjToBytes(pm[p.Position]));}});if (outPlist.Count > 0)r.OutValue = outPlist.ToArray();//正常返回return r;}catch(TargetInvocationException ex1){var ex = ex1.InnerException;//處理服務器端發生的兩種異常信息,這些屬于正常的業務異常,需要返回到客戶端if (ex is BizException || ex is DAException){var r = new ReturnValue();r.HasException = true;r.Exception = PubFunc.Serialize.ObjToBytes(ex);return r;}else{//非正常情況下的異常,統一包裝為服務端異常返回var serverex = new ServerException(ex.Message);serverex.Trace = ex.StackTrace;var r = new ReturnValue();r.HasException = true;r.Exception = PubFunc.Serialize.ObjToBytes(serverex);return r;}}} } //服務返回對象 [DataContract] public class ReturnValue {[DataMember]public bool HasException { get; set; }[DataMember]public byte[] Exception { get; set; }[DataMember]public byte[] Value { get; set; }[DataMember]public byte[][] OutValue { get; set; }public void SetValue(object value){if (value == null){Value = null; return;}Value=PubFunc.Serialize.ObjToBytes(value);}public object GetValue(){if (Value == null){return null;}return PubFunc.Serialize.BytesToObj(Value);} } //調用信息 [DataContract] public class MethodProxy {[DataMember]public string ClassName { get; set; }[DataMember]public string MethodName { get; set; }[DataMember]public byte[][] Params{get;set;} }這里是完整的服務端的方法,提供WCF接口,處理業務層對象調用的過程。
實現不算復雜,代碼也不多,歡迎討論。不足之處請指正。
轉載于:https://www.cnblogs.com/yiway/archive/2011/01/24/MY_FW_4.html
總結
以上是生活随笔為你收集整理的不是架构的架构之四:业务层的实现与自动代理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#委托,事件理解入门 (译稿)
- 下一篇: 指针04 - 零基础入门学习C语言44