首页 > 代码库 > 多层架构+MVC+EF+AUTOFAC+AUTOMAPPER【转】

多层架构+MVC+EF+AUTOFAC+AUTOMAPPER【转】

多层架构+MVC+EF+AUTOFAC+AUTOMAPPER

最近使用ligerui搭建了一个简单的教务管理demo,将重要的地方记录,也希望能帮到有这方面需要园友。


一、目录

 1、多层架构+MVC+EF+AUTOFAC+AUTOMAPPER;

 2、MVC中验证码的实现(经常用,记录备用)

二、正文

 多层架构中等以上规模以上的系统用得比较多,此demo功能不多,出于抱着学习的态度搭建了一个多层架构,并加入现在很流行的依赖倒转(autofac)、对象映射工具(automapper)。

 话说没图你说个J8,先上框架图:

  Model层中Entity存放数据库实体,使用code first,ViewModel存放界面展示模型。DAL层中IDAO存放接口,EFDAO 实现IDAO。BLL结构与DAL类似,接口+实现。WEB层就是我们的UI层了,在这个框架中,WEB层使用MVC。什么,MVC不就是多层架构嘛,怎 么还把它放Web层呢?MVC并不等同于多层架构,有这样疑问的同学,请在园内搜索相关文章。Infrastructure层是我们的基础设施层,我把一 些常用的工具类封装后放入其中,方便其它地方调用。

  IDao中定义了一个公共基类,基类中定义所有子类都会用到的查询方法:

 1 namespace YTJWGL_IDao 2 { 3     public interface IBaseDao<T> 4     { 5         #region 查询普通实现方案(基于Lambda表达式的Where查询) 6         /// <summary> 7         /// 获取所有Entity 8         /// </summary> 9         /// <param name="exp">Lambda条件的where</param>10         /// <returns></returns>11         IEnumerable<T> GetEntities(Func<T, bool> exp);12 13         /// <summary>14         /// 计算总个数(分页)15         /// </summary>16         /// <param name="exp">Lambda条件的where</param>17         /// <returns></returns>18         int GetEntitiesCount(Func<T, bool> exp);19 20         /// <summary>21         /// 分页查询(Linq分页方式)22         /// </summary>23         /// <param name="pageNumber">当前页</param>24         /// <param name="pageSize">页码</param>25         /// <param name="orderName">lambda排序名称</param>26         /// <param name="sortOrder">排序(升序or降序)</param>27         /// <param name="exp">lambda查询条件where</param>28         /// <returns></returns>29         IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp);30 31         /// <summary>32         /// 根据条件查找33         /// </summary>34         /// <param name="exp">lambda查询条件where</param>35         /// <returns></returns>36         T GetEntity(Func<T, bool> exp);37 38         #endregion39 40         //#endregion41         /// <summary>42         /// 插入Entity43         /// </summary>44         /// <param name="model"></param>45         /// <returns></returns>46         bool Insert(T entity);47         /// <summary>48         /// 更新Entity49         /// </summary>50         /// <param name="model"></param>51         /// <returns></returns>52         bool Update(T entity);53         /// <summary>54         /// 删除Entity55         /// </summary>56         /// <param name="entity"></param>57         /// <returns></returns>58         bool Delete(T entity);59         /// <summary>60         /// 删除实现 存储过程实现方式(调用spDelete+表名+ 主键ID)61         /// </summary>62         /// <param name="ID">删除的主键</param>63         /// <returns></returns>64         //bool Delete(object ID);65     }66 }
 

IDAO

  EFDao有一个类实现这一公共基类:

 1 namespace YTJWGL_EFDao  2 {  3     public class BaseEFDao<T> : IBaseDao<T> where T : class,new()//限制T的类型为class或者对象  4     {  5   6   7         #region 查询普通实现方案(基于Lambda表达式的Where查询)  8         /// <summary>  9         /// 获取所有Entity 10         /// </summary> 11         /// <param name="exp">Lambda条件的where</param> 12         /// <returns>返回IEnumerable类型</returns> 13         public virtual IEnumerable<T> GetEntities(Func<T, bool> exp) 14         { 15             using (Entities db = new Entities()) 16             { 17                 return db.Set<T>().Where(exp).ToList(); 18             } 19  20  21         } 22         /// <summary> 23         /// 计算总个数(分页) 24         /// </summary> 25         /// <param name="exp">Lambda条件的where</param> 26         /// <returns></returns> 27         public virtual int GetEntitiesCount(Func<T, bool> exp) 28         { 29             using (Entities db = new Entities()) 30             { 31                 return db.Set<T>().Where(exp).ToList().Count(); 32  33             } 34         } 35         /// <summary> 36         /// 分页查询(Linq分页方式) 37         /// </summary> 38         /// <param name="pageNumber">当前页</param> 39         /// <param name="pageSize">页码</param> 40         /// <param name="orderName">lambda排序名称</param> 41         /// <param name="sortOrder">排序(升序or降序)</param> 42         /// <param name="exp">lambda查询条件where</param> 43         /// <returns></returns> 44         public virtual IEnumerable<T> GetEntitiesForPaging(int pageNumber, int pageSize, Func<T, string> orderName, string sortOrder, Func<T, bool> exp) 45         { 46             using (Entities db = new Entities()) 47             { 48                 if (sortOrder == "asc") //升序排列 49                 { 50                     return db.Set<T>().Where(exp).OrderBy(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); 51                 } 52                 else 53                 { 54                     return db.Set<T>().Where(exp).OrderByDescending(orderName).Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList(); 55                 } 56             } 57  58         } 59         /// <summary> 60         /// 根据条件查找满足条件的一个entites 61         /// </summary> 62         /// <param name="exp">lambda查询条件where</param> 63         /// <returns></returns> 64         public virtual T GetEntity(Func<T, bool> exp) 65         { 66             using (Entities db = new Entities()) 67             { 68                 return db.Set<T>().Where(exp).SingleOrDefault(); 69             } 70         } 71         #endregion 72  73         #region 增改删实现 74         /// <summary> 75         /// 插入Entity 76         /// </summary> 77         /// <param name="model"></param> 78         /// <returns></returns> 79         public virtual bool Insert(T entity) 80         { 81             using (Entities db = new Entities()) 82             { 83                 var obj = db.Set<T>(); 84                 obj.Add(entity); 85                 return db.SaveChanges() > 0; 86  87             } 88  89         } 90         /// <summary> 91         /// 更新Entity(注意这里使用的傻瓜式更新,可能性能略低) 92         /// </summary> 93         /// <param name="model"></param> 94         /// <returns></returns> 95         public virtual bool Update(T entity) 96         { 97             using (Entities db = new Entities()) 98             { 99                 var obj = db.Set<T>();100                 obj.Attach(entity);101                 db.Entry(entity).State = System.Data.EntityState.Modified;102                 return db.SaveChanges() > 0;103             }104 105 106         }107         /// <summary>108         /// 删除Entity109         /// </summary>110         /// <param name="entity"></param>111         /// <returns></returns>112         public virtual bool Delete(T entity)113         {114             using (Entities db = new Entities())115             {116                 var obj = db.Set<T>();117                 if (entity != null)118                 {119                     obj.Attach(entity);120                     db.Entry(entity).State = System.Data.EntityState.Deleted;121                     obj.Remove(entity);122                     return db.SaveChanges() > 0;123                 }124                 return false;125             }126 127         }128         #endregion129     }130 }

EFDAO

  可以看到,代码中都是使用的泛型。根据传入的实体类型决定访问莫一数据实体。

  倘若,我们有一个数据实体类叫做Admin,IDAO,EFDAO中可以分别添加Admin对应的DAL层文件: 

IAdminDao

1 namespace YTJWGL_EFDao2 {3     public class AdminEFDao : BaseEFDao<YTJWGL_Admin>, IAdminDao<YTJWGL_Admin>4     {5     }6 }
AdminEFDao

   IAdminDao继承我们上面定义的 公共接口,AdminEFDao继承IAdminDao接口以及BaseEFDao基类,这样我们可以在IAdminDao中定义该数据实体特有的查询方 法,同时复用了我们常用的查询以及增加、删除、编辑代码。至于为什么要使用接口,是为了满足面向对象原则的依赖倒转原则——抽象不依赖细节,细节应该依赖 抽象。

  BLL层代码结构与DAL类似。

  一个简单的多层架构就是这样,各层之间引用关系从顶层向下调用底层,将各层之间耦合尽量降低。


 

  然后,谈谈配置autofac。

  这里,发现这工具很好,很强大,至于有多强大,我也不清楚,因为我也很菜(/ □ \)……

  autofac配置园里相关文章也很多,我这里就初略的说说。

  First step:nuget上加入我们autofac的程序集引用:

  

  注意,根据你所使用的.net环境选择相应的程序集,目前最新的版本是3.1.0,低版本的autofac是不支持.net4.0的。我们这里使用了MVC4.0所以选择第二个。

  Second step:配置依赖注入,说白了就是告诉autofac你要将哪个类与接口“发生关系”。

  

  在这个框架中,我们将配置信息在图示类中完成:

namespace YTJWGL_WebUI.RegisterAutofac{    public static class RegisterAutofacForSingle    {        public static void RegisterAutofac()        {            ContainerBuilder builder = new ContainerBuilder();            builder.RegisterControllers(Assembly.GetExecutingAssembly());            #region IOC注册区域            //倘若需要默认注册所有的,请这样写(主要参数需要修改)            //builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())            //   .AsImplementedInterfaces();                       //Admin            builder.RegisterType<AdminService>().As<IAdminService>().InstancePerHttpRequest();                      #endregion            // then            var container = builder.Build();            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));                  }           }}
RegisterAutofacForSingle

  autofac有很多重配置方式,详询此处:http://www.cnblogs.com/hkncd/archive/2012/11/28/2792474.html

  好了,下面我们在全局文件Global.asax中调用刚才定义的方法:

1 namespace YTJWGL_WebUI 2 { 3     // Note: For instructions on enabling IIS6 or IIS7 classic mode,  4     // visit http://go.microsoft.com/?LinkId=9394801 5     public class MvcApplication : System.Web.HttpApplication 6     { 7         protected void Application_Start() 8         { 9             AreaRegistration.RegisterAllAreas();10 11             WebApiConfig.Register(GlobalConfiguration.Configuration);12             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);13             RouteConfig.RegisterRoutes(RouteTable.Routes);14 15             //autofac注册16             RegisterAutofacForSingle.RegisterAutofac();         18 19             //automapper注册20             RegisterAutomapper.Excute();21         }22     }23 }
Global.asax

  至此,autofac的配置就基本OK。其是用也比较的方便,autofac是使用构造函数注入:

 1 namespace YTJWGL_WebUI.Areas.Admin.Controllers 2 { 3      4     public class FrameController : Controller 5     { 6         // 7         // GET: /Admin/Frame/ 8         #region Fields 9 10         private readonly IAdminService _adminService;11        12         #endregion13 14         #region Constructors15 16         public FrameController(IAdminService adminService)17         {18             this._adminService = adminService;        19         }20         #endregion21 22         #region Admin23 24         [HttpPost]25         public ActionResult Login(LoginModel model, string returnUrl)26         {27          //这样调用28            var amin = _adminService.GetAllEntities(p => p.ID != 0);29         }36     }37 }
FrameController

  这样就可以使用接口调用方法了。autofac简单配置完毕。


  接下来我们配置automapper:

  First Step:与autofac同样的方法在nuget里面安装。

  Secoud Step:

    

  我把automapper分为两部配置,第一步与autofac类似,首先注册,也就是告诉automapper组件,你要在哪两个Model之间映射:

 1 namespace YTJWGL_WebUI.Automapper 2 { 3     public static class RegisterAutomapper 4     { 5         public static void Excute() 6         { 7  8             //Admin 9             Mapper.CreateMap<LoginModel, YTJWGL_Admin>();10             Mapper.CreateMap<YTJWGL_Admin, LoginModel>().ForMember(dest => dest.ValidatorCode, sor => sor.Ignore());11      12         }13 14     }15 }
View Code
RegisterAutomapper

  代码中Formeber后面的代码可以不要,详情在这:http://www.cnblogs.com/ljzforever/archive/2011/12/29/2305500.html;

  然后看看我们第二个文件MapperExtention:

 1 namespace YTJWGL_WebUI.Automapper 2 { 3     public static class MapperExtention 4     { 5         #region Admin 6  7        public static AdminModel ToModel(this YTJWGL_Admin entity) 8         { 9             return Mapper.Map<YTJWGL_Admin, AdminModel>(entity);10         }11 12         public static YTJWGL_Admin ToEntity(this AdminModel model)13         {14             return Mapper.Map<AdminModel, YTJWGL_Admin>(model);15         }16 17         public static YTJWGL_Admin ToEntity(this AdminModel model, YTJWGL_Admin destination)18         {19             return Mapper.Map<AdminModel, YTJWGL_Admin>(model, destination);20         }21     22     }23 }
MapperExtention中定义了一个个拓展方法,添加这个文件会让我们在控制器中映射实体变得非常方便:
 public ActionResult List()2         {3             //数据库实体向ViewModel转换4             var model = _newsService.GetEntityByQuery(p => p.ID == 1).ToModel();5             //ViewModel向数据库实体转换6             var entity = model.ToEntity();7             return View();8         }

  就向调用ToString()方法一样的使用。

  当然,我们的automapper还需要在Global文件中调用,这一步在autofac最后一张图中已经说明。

多层架构+MVC+EF+AUTOFAC+AUTOMAPPER【转】