多是咱們共同的強迫症,不要說看到,就算想到太多的try-catch也很難接受。html
因而,開始了一些嘗試,這些嘗試都算是思惟的鍛鍊、場面的見識、經驗的積累。框架
一開始,在ConcreteService中,擁有了太多的try-catch,而影響碼字的興趣。函數
代碼1 原始代碼 /// <summary> /// 契約 /// </summary> public interface IUpdateManyManyThingContract { bool UpdateSth1(DataSet ds); bool UpdateSth2(DataSet ds); bool UpdateSth3(DataSet ds); bool UpdateSth4(DataSet ds); //... } /// <summary> /// 服務實現 /// </summary> public class ConcreteService : IUpdateManyManyThingContract { private IDao m_Dao; public bool UpdateSth1(DataSet ds) { try { var dt = ds.First(); if (!dt.HasElements()) return true; foreach (DataRow row in dt.Rows) { //構造 var entity = new Branch(row); m_Dao.SaveOrUpdate(entity); } return true; } catch (Exception ex) { Logger.Log(ex); return false; } } public bool UpdateSth2(DataSet ds) { try { } catch (Exception) { } } public bool UpdateSth3(DataSet ds) { throw new NotImplementedException(); } public bool UpdateSth4(DataSet ds) { throw new NotImplementedException(); } //many update methods,many try-catches... }
如上代碼,UpdateSth函數裏面都須要實現一個try-catch,而以爲噁心到本身了。ui
因而,基於本身的積累,開始了重構的第一個版本。spa
針對這個服務(ConcreteService)的特殊性,定製了一個專門的方法進行控制——TrycatchBlock。.net
代碼2 提取方法片斷
/// <summary> /// 服務實現 /// </summary> public class ConcreteService : IUpdateManyManyThingContract { private IDao m_Dao; public bool UpdateSth1(DataSet ds) { return TrycatchBlock(() => { var dt = ds.First(); if (!dt.HasElements()) return true; foreach (DataRow row in dt.Rows) { //構造 var entity = new Branch(row); m_Dao.SaveOrUpdate(entity); } return true; }); } public bool UpdateSth2(DataSet ds) { return TrycatchBlock(() => { //... return true; //... //return false; }); } public bool UpdateSth3(DataSet ds) { throw new NotImplementedException(); } public bool UpdateSth4(DataSet ds) { throw new NotImplementedException(); } //many update methods,many try-catches... //try-catch控制塊 private bool TrycatchBlock(Func<bool> body) { try { return body(); } catch (Exception ex) { Logger.Log(ex); return false; } } }
是的,這是一次進步,將全部的try-catch的功能職責都集中到了一個函數裏面,也方便調試了。代理
可是,還得每一個方法都加上一句:return TrycatchBlock(() => { 。。。 })。調試
從本質上來講,仍是在進行中重複。code
通過老大的指點:考慮MVC中的相似FilterAttribute的註解。htm
思路演進:MVC中,有一個HandErrorAttribute的特性,用於攔截控制器或者動做的異常。。。。。。對,這是個思路,但過了沒多久,我就放棄了。
放棄理由:「Request請求——>路由數據——>ControllerInvoker——>反射調用Controller或Action。」,這裏面用了不少元數據(***Descriptor,***Invoker等)手段,實現難度不小。
另外,我須要的是「instance.MethodAction」(對象直接調用方法)的方式,由於是爲WCF直接提供服務(WCF會根據配置文件中服務的名稱建立服務),不須要使用反射進行動態調用。
瀏覽網頁的過程當中,想起動態代理——Castle Dynamic Proxy,是的,Moq,Spring.net等一系列優秀的框架中引用到了它。
想起一個老外曾經說過的一句話「計算機的任何問題,均可以經過一箇中間層來解決」,固然,這裏的中間層,是一個普遍和抽象的概念,好比,中間1號調中間2號、中間2號調目標,多是一個遞歸的結構也說不定。
因而使用interceptor繼續一個版本:
代碼3:中間層——ConcreteServiceProxy;攔截器——ServiceDynamicProxyInterceptor。 /// <summary> /// 服務實現 /// </summary> public class ConcreteService : IUpdateManyManyThingContract { private IDao m_Dao; public bool UpdateSth1(DataSet ds) { var dt = ds.First(); if (!dt.HasElements()) return true; foreach (DataRow row in dt.Rows) { //構造 var entity = new Branch(row); m_Dao.SaveOrUpdate(entity); } return true; } public bool UpdateSth2(DataSet ds) { //... return true; //... //return false; } public bool UpdateSth3(DataSet ds) { throw new NotImplementedException(); } public bool UpdateSth4(DataSet ds) { throw new NotImplementedException(); } //many update methods,many try-catches... } public class ConcreteServiceProxy : IUpdateManyManyThingContract { private ConcreteService m_Service; public ConcreteServiceProxy() { m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>(); } public bool UpdateSth1(DataSet ds) { return m_Service.UpdateSth1(ds); } public bool UpdateSth2(DataSet ds) { return m_Service.UpdateSth2(ds); } public bool UpdateSth3(DataSet ds) { return m_Service.UpdateSth3(ds); } public bool UpdateSth4(DataSet ds) { return m_Service.UpdateSth4(ds); } } public class ServiceDynamicProxyInterceptor : IInterceptor { /// <summary> /// 工廠方法 /// </summary> /// <typeparam name="T">服務類型</typeparam> /// <returns>一個通過代理的服務</returns> public static T CreateServiceProxy<T>() where T : class { ProxyGenerator generator = new ProxyGenerator(); ServiceDynamicProxyInterceptor interceptor = new ServiceDynamicProxyInterceptor(); T entity = generator.CreateClassProxy<T>(interceptor); return entity; } public void Intercept(IInvocation invocation) { try { invocation.Proceed(); } catch (Exception ex) { Log.Error(ex.Message); invocation.ReturnValue = false; } } }
上述代碼是一目瞭然,使用m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();就獲得一個代理過的對象,也就可以進行攔截。
多了一箇中間層——ConcreteServiceProxy,井井有條了,可是代碼一樣沒有減小,這個彷佛又看起來屢次一舉。
何況還要改配置文件,WCF的配置,以下下劃線部分。
<service name="MyNameSpace.Service.ConcreteServiceProxy" behaviorConfiguration="WFServiceBehavior">
到使用中間層爲止,我已是可以接受的了。但老大以爲還能夠再精簡,確實是經驗豐富,又被指點了,而後提點我使用IOC,目標是去除中間層——ConcreteServiceProxy。
思路:
1) 先使用動態代理建立一個被代理過的(Proxied)ConcreteService對象;
2) 將此對象放入IOC中(如Autofac,Unity等);
3) 若是須要使用ConcreteService類型的實例,從IOC中獲取便可。
注:(去除了中間層——ConcreteServiceProxy;同時ConcreteService不用加try-catch;也不用改配置文件了)
代碼4:去除了中間層——ConcreteServiceProxy;同時ConcreteService不用加try-catch;也不用改配置文件了 public class DependencyRegistrar : IDependencyRegistrar { public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder) { var proxiedService = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>(); builder.Register(c => proxiedServicec).As<ConcreteService>().InstancePerRequest(); } public int Order { get { return 0; } } }
一次多好的體驗啊!!!
用DP(Dynamic Proxy)完成了攔截;用IOC完成了DI。
寫到這裏,問題來了,WCF可以經過配置文件配置的服務名稱,即MyNameSpace.Service.ConcreteService,自動去IOC中找到被代理的對象嗎?Autofac.WCF能不能幫助它完成呢?
(附)動態代理連接:
http://docs.castleproject.org/Tools.DynamicProxy.ashx
http://www.cnblogs.com/daxnet/archive/2011/09/07/2169520.html
http://www.cnblogs.com/RicCC/archive/2010/03/15/castle-dynamic-proxy.html
總結:就先寫到這裏,體驗的感受哪怕就是一點點,也很爽!歡迎拍磚。
Demo連接:http://files.cnblogs.com/pengzhen/TryCatchDemo.rar