今天和大家一起學習一下當前流行的MVC5+EF+AutoFac+AutoMapper輕型架構,先上一張框架圖
一、項目基本框架搭建
寫程序的順序是Model-DAL-BLL-UI,Model層就是表實體,我們略過,下面上DAL層代碼

using Model; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace DAL { public class BaseDal<T> where T : class, new() { public DataModel _currentDbContext = DbContextFactory.GetDbContext(); public T Add(T item) { return _currentDbContext.Set<T>().Add(item); } public int Count(Expression<Func<T, bool>> predicate) { //set<t>針對對上下文和基礎存儲中給定類型的實體的訪問返回一個 DbSet<TEntity> 實例。 return _currentDbContext.Set<T>().Count(predicate);//返回指定序列中滿足條件的元素數量。 } public bool Update(T entity) { //Attach將實體以“未更改”的狀態放置到上下文中,就好像從數據庫讀取了該實體一樣。 _currentDbContext.Set<T>().Attach(entity); _currentDbContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Modified; return _currentDbContext.SaveChanges() > 0; } public bool Delete(T entity) { _currentDbContext.Set<T>().Attach(entity); _currentDbContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Deleted; return _currentDbContext.SaveChanges() > 0; } public bool Exist(Expression<Func<T, bool>> anyLambda) { return _currentDbContext.Set<T>().Any(anyLambda); } public T Find(Expression<Func<T, bool>> whereLambda) { T entity = _currentDbContext.Set<T>().FirstOrDefault(); return entity; } public IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc) { var _list = _currentDbContext.Set<T>().Where<T>(whereLamdba); _list = OrderBy(_list, orderName, isAsc); return _list; } /// <summary> /// 排序 /// </summary> /// <typeparam name="T">類型</typeparam> /// <param name="source">原IQueryable</param> /// <param name="propertyName">排序屬性名</param> /// <param name="isAsc">是否正序</param> /// <returns>排序后的IQueryable<T></returns> private IQueryable<T> OrderBy(IQueryable<T> source, string propertyName, bool isAsc) { if (source == null) throw new ArgumentNullException("source", "不能為空"); if (string.IsNullOrEmpty(propertyName)) return source; var _parameter = Expression.Parameter(source.ElementType); var _property = Expression.Property(_parameter, propertyName); if (_property == null) throw new ArgumentNullException("propertyName", "屬性不存在"); var _lambda = Expression.Lambda(_property, _parameter); var _methodName = isAsc ? "OrderBy" : "OrderByDescending"; var _resultExpression = Expression.Call(typeof(Queryable), _methodName, new Type[] { source.ElementType, _property.Type }, source.Expression, Expression.Quote(_lambda)); return source.Provider.CreateQuery<T>(_resultExpression); } public IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc) { var _list = _currentDbContext.Set<T>().Where<T>(whereLamdba); totalRecord = _list.Count(); //if (isAsc) _list = _list.OrderBy<T, S>(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize); //else _list = _list.OrderByDescending<T, S>(orderLamdba).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize); _list = OrderBy(_list, orderName, isAsc).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize); return _list; } } }
相信大家都能看懂吧,EF框架抽象出來的CRUD方法

namespace DAL { public class UserInfoDal:BaseDal<UserInfo>,IUserInfoDal { } }
IDAL層代碼給大家看一下,因為我們要解耦各個層之間的首先要實現面向接口編程

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace IDAL { public interface IBaseDal<T> { T Add(T item); int Count(Expression<Func<T, bool>> predicate); bool Update(T entity); bool Delete(T entity); bool Exist(Expression<Func<T, bool>> anyLambda); T Find(Expression<Func<T, bool>> whereLambda); IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc); IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc); } }
BLL層的代碼大家都能看懂吧,看不懂的話要多加研究了

using DAL; using IDAL; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace BLL { public class BaseService<T> where T:class,new() { public BaseService(IBaseDal<T> currentDal) { this._currentDal = currentDal; } protected IBaseDal<T> _currentDal { get; set; } public T Add(T item) { return _currentDal.Add(item); } public int Count(Expression<Func<T, bool>> predicate) { return _currentDal.Count(predicate); } public bool Update(T entity) { return _currentDal.Update(entity); } public bool Delete(T entity) { return _currentDal.Delete(entity); } public bool Exist(Expression<Func<T, bool>> anyLambda) { return _currentDal.Exist(anyLambda); } public T Find(Expression<Func<T, bool>> whereLambda) { return _currentDal.Find(whereLambda); } public IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc) { return _currentDal.FindList(whereLamdba, orderName, isAsc); } public IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc) { return _currentDal.FindPageList(pageIndex, pageSize, out totalRecord, whereLamdba, orderName, isAsc); } } }
同樣面向接口編程,我們也要抽象出IBLL層,實現與UI的面向接口

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace IBLL { public interface IBaseService<T> where T:class,new() { T Add(T item); int Count(Expression<Func<T, bool>> predicate); bool Update(T entity); bool Delete(T entity); bool Exist(Expression<Func<T, bool>> anyLambda); T Find(Expression<Func<T, bool>> whereLambda); IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc); IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc); } }
二、運用AutoFac進行依賴注入,實現各層次間低耦合。(其實就是一個第三方的抽象工廠,我們自己也是可以寫出來的,相信自己)
autofac 4.0 版本以上,官方建議使用外代*.JSON\*.XML的文件進行注入,而不是直接寫在web.config文件中(如我們的架構圖)
接下來看一下,如何運用Autofac進行依賴注入,先介紹代碼自動注入
//創建autofac管理注冊類的容器實例 ContainerBuilder builder = new ContainerBuilder(); #region 全自動api注入 //UI項目只用引用service和repository的接口,不用引用實現的dll。 //如需加載實現的程序集,將dll拷貝到bin目錄下即可,不用引用dll var IServices = Assembly.Load("IBLL"); var Services = Assembly.Load("BLL"); var IRepository = Assembly.Load("IDAL"); var Repository = Assembly.Load("DAL"); //根據名稱約定(數據訪問層的接口和實現均以Repository結尾),實現數據訪問接口和數據訪問實現的依賴 builder.RegisterAssemblyTypes(IRepository, Repository) .Where(t => t.Name.EndsWith("Dal")) .AsImplementedInterfaces(); //根據名稱約定(服務層的接口和實現均以Service結尾),實現服務接口和服務實現的依賴 builder.RegisterAssemblyTypes(IServices, Services) .Where(t => t.Name.EndsWith("Service")) .AsImplementedInterfaces(); #endregion
下面是配置文件注入,這種配置文件注入適合大項目,管理方便

{ "components": [ { "type": "DAL.UserInfoDal,DAL", "services": [ { "type": "IDAL.IUserInfoDal" } ], "injectProperties": true }, { "type": "DAL.OrderInfoDal,DAL", "services": [ { "type": "IDAL.IOrderInfoDal" } ], "injectProperties": true }, { "type": "BLL.UserInfoService,BLL", "services": [ { "type": "IBLL.IUserInfoService" } ], "injectProperties": true }, { "type": "BLL.OrderInfoService,BLL", "services": [ { "type": "IBLL.IOrderInfoService" } ], "injectProperties": true } ] }
配置方式注入代碼如下:
#region 配置注入適合大項目 var config = new ConfigurationBuilder(); //config.AddXmlFile(@"D:\ASP.NET成長之路\asp.net經典框架網絡資源\AutoFac\AutoFacDemo\AutoFacDemo\IOC\auto.xml"); config.AddJsonFile(@"D:\ASP.NET成長之路\asp.net經典框架網絡資源\AutoFac\AutoFacDemo\AutoFacDemo\IOC\auto.json"); var module = new ConfigurationModule(config.Build()); #endregion
不管用什么樣的方式注入,最后要和MVC融合使用的話必選加載下面的代碼:
//使用Autofac提供的RegisterControllers擴展方法來對程序集中所有的Controller一次性的完成注冊 builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();//生成具體的實例(屬性注入) var container = builder.Build(); //下面就是使用MVC的擴展 更改了MVC中的注入方式. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
並且要在Global文件中的Application_Start()執行注入的方法(將上面的注入代碼封裝到一個類的方法中)
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { //autofac注入 AutoFacInitialize.AutofacIntitialy(); Database.SetInitializer(new UseInfoInitializer()); AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); } }
今天先寫到這里吧,明天或者后天,把AutoMapper的融入寫出來。
各位園友,多多指教,小僧可能有些地方有缺陷,多多留言,共同進步,謝謝!