0_MVC+EF+Autofac(dbfirst)輕型項目框架_基本框架


前言

  原來一直使用他人的開源項目框架,異常的定位會很麻煩,甚至不知道這個異常來自我的代碼還是這個框架本身。他人的框架有一定的制約性,也有可能是我對那些框架並沒深入了解,因為這些開源框架在網上也很難找到高效並且規范的文檔。比如別人的框架可能調用了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層,功能分別如下

  1. web:承載MVC以及WebAPI,負責展現
  2. Core:處理具體的業務邏輯
  3. Model:分為Entity數據實體與WebModel,WebModel主要包括WEB層與Core層數據傳遞的model與Web頁面上的實體
  4. 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM