前言
原來一直使用他人的開源項目框架,異常的定位會很麻煩,甚至不知道這個異常來自我的代碼還是這個框架本身。他人的框架有一定的制約性,也有可能是我對那些框架並沒深入了解,因為這些開源框架在網上也很難找到高效並且規范的文檔。比如別人的框架可能調用了Enterprise Library來實現權限的驗證,但在我的項目中,權限驗證有可以復用的模塊,所以在整合時會非常不靈活。。。。
參考了很多網上的優秀框架,看了幾本書后,突然意識到易用才是開發和使用框架的出發點與立足點,框架並不是越復雜越好,評價一個框架的好壞,應綜合考慮它的學習成本,使用成本和維護成本。考慮了以上因素后於是打算做一套輕量的框架出來,方便日后的擴充,雖然框架已經非常簡單,但依舊可能存在着問題,希望大神們能指點迷津。
開發背景
我所要面對的項目,並沒有特別復雜的業務邏輯,需要面對的最大問題是高並發。這也是我舍棄原有的框架的重要原因。
因為業務邏輯並不復雜,所以采用的dbfirst的設計思路,一方面是項目后續開發時他人好更容易上手,一方面是對於codefirst我也只是停留在會用的階段,對於高深的DDD,理解還十分有限,可能會引入很多錯誤的思維方式。
項目的開發環境為:Windows7 SP1、Visual Studio 2013、Sql Server 2012、.NET Framework4.5。
項目依托ASP.NET MVC + WebAPI,數據存儲采用EntityFramework。
總體框架
這是項目解決方案的截圖,從上到下分為WEB層,Core層,Model層與Infrastructure層,功能分別如下
- web:承載MVC以及WebAPI,負責展現
- Core:處理具體的業務邏輯
- Model:分為Entity數據實體與WebModel,WebModel主要包括WEB層與Core層數據傳遞的model與Web頁面上的實體
- Infrastructure:基礎實施層,存放一些可以復用的類與方法
項目的依賴關系是這樣的,使用Autofac注入。原來使用的是spring.net,這次改為更加輕量了Autofac做依賴注入,效率更高(網上說的(-:),也能找到很多的幫助文檔。並且Autofac為mvc提供了以每一次請求作為注入依據的方案,將實體以參數的形式傳入到控制器中,非常實用。
創建過程
在Entity程序集中,通過數據庫生成edmx,這里面也包含了實體對象的模型。接下來就要在core中創建Entities的DbContext實體。
在我原來的系統中,我一般會在EF上在創建一個DAL(數據庫訪問層),用來存放常用的增刪改查的方法,但后來逐漸體會到EF框架本身其實已經很好地封裝好了傳統DAL層中的方法,如果在放一個DAL層就有重復封裝之嫌。這里就不詳細討論這層DAL封裝是否有必要,因為不同的人的習慣會不同,如果你是傳統三層過來的,也許放個DAL會更得心應手些,當然不放也有不放的好處,比如業務在操作數據庫時可以更加靈活,編碼時少了層接口也可以顯得更加直觀。但是不加DAL無法對數據庫的操作進行封裝,從而應運而生了另一個看似比較棘手的問題,如果日后變更數據庫,需要變更core層中的代碼嗎?這將導致高耦合。這個問題我當初也糾結了很久,但轉過來一想,Entity framework是一個開源框架,對主流數據庫包括oracle等都已支持,變更數據庫只需要重新生成對應數據庫類型的edmx,對業務core是沒有影響的。
我在業務層創建了一個CoreSession類,用來存放給web的業務操作的集合。
下面是接口。
1 public interface ICoreSession 2 { 3
4 }
下面是實現,里面有一個db屬性,存放實例后的Entity對象,並最構造方法中新建實例。
1 public class CoreSession:EDUA_ICore.ICoreSession 2 { 3 private DbContext db { get; set; } 4 public CoreSession() 5 { 6 db = new Entity.EDUAEntities(); 7 } 8 public int SaveChanges() 9 { 10 return db.SaveChanges(); 11 } 12 }
一個最簡單的core層構建完成了,雖然里面暫時沒有任何的方法。接下來要在web層中創建core對象。那么core在web層中能否單例呢?core的單例也就意味着EF實體的單例,因為EF的實例過程在core的構造方法中。而EF本身是不能保證線程安全的。那天在和前輩們討論EF該不該單例這個問題時,幾乎兩人同時告訴我千萬不要,他們都中過招,如果用最簡單的static來實現single,不僅僅是高並發,而是只要並發時就會出問題。當然有另一種方法,用callcontext將core對象放入線程中,每次用時從線程中取,用這種方法來保證EF的線程安全性,這是我用過的一種較靠譜的單例方法,而且暫時還沒出過什么問題。但為了保證高並發時的性能,並且借鑒Autofac(Ioc)所提供的機制,我決定采用為每一次請求創建一個Core對象。
我配置Autofac的過程如下
1.下載並引入Autofac的程序集
下載地址:http://autofac.org/
這里需要在WEB引入這兩個程序集,前者是autofac的核心,后者是它的mvc插件,如果需要將注入的映射對象寫到配置文件里,還需要引入Autofac.Configuration.dll 這個程序集,由於我直接將映射寫在了代碼中,所以沒有引。
2.在web層中創建RegisterAutofacForSingle類,雖然名字說是single,但只是注冊時的single,並不是說將對象單例了。
1 public class RegisterAutofacForSingle 2 { 3 public static void RegisterAutofac() 4 { 5 ContainerBuilder builder = new ContainerBuilder(); 6 builder.RegisterControllers(Assembly.GetExecutingAssembly()); 7 8 //注冊給控制器 9 builder.RegisterType<EDUA_Core.CoreSession>().As<EDUA_ICore.ICoreSession>().InstancePerHttpRequest(); 10 11 //注冊給過濾器 12 builder.RegisterType<EDUA_Core.CoreSession>().As<EDUA_ICore.ICoreSession>(); 13 builder.RegisterType<Filters.MyAuthorizeAttribute>().SingleInstance(); 14 builder.RegisterFilterProvider(); 15 16 var container = builder.Build(); 17 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 18 } 19 20 }
第6行注冊了控制器的版本,第9行的方法InstancePerHttpRequest()為每一個新的請求創建一個新實例,后面注冊給過濾器的行為中,是全局單例的,因為我的過濾器中不會存在寫的操作,不存在並發時的讀寫問題。
3.在Globa.asax文件中注冊Autofac
1 public class MvcApplication : System.Web.HttpApplication 2 { 3 protected void Application_Start() 4 { 5 //注冊Autofac 6 RegisterAutofacForSingle.RegisterAutofac(); 7 8 AreaRegistration.RegisterAllAreas(); 9 10 WebApiConfig.Register(GlobalConfiguration.Configuration); 11 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 12 RouteConfig.RegisterRoutes(RouteTable.Routes); 13 BundleConfig.RegisterBundles(BundleTable.Bundles); 14 } 15 }
需要注意的是,由於RegisterAutofacForSingle中給過濾器注冊了注入,所以注冊Autofac需要放在注冊過濾器之前,不然會報錯。我把Autofac的注冊放在了最前面。
4.在控制器與過濾器中添加core對象實例
1 private ICoreSession iCoreSession; 2 public MyAuthorizeAttribute(ICoreSession iCoreSession) 3 { 4 this.iCoreSession = iCoreSession; 5 }
至此, 在控制器和過濾器中就都可以直接調用到core中的內容了。
在接下去的文章中我會舉一個登陸的例子來擴充core層,並且在過濾器中實現權限的判斷。
轉載請注明出處 huhuhuo的博客園
地址:http://www.cnblogs.com/linhan/p/4287059.html