MVC5+EF+AutoFac+AutoMapper轻型架构

Posted Constructor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MVC5+EF+AutoFac+AutoMapper轻型架构相关的知识,希望对你有一定的参考价值。

今天和大家一起学习一下当前流行的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;
        }

    }
}
BaseDal

相信大家都能看懂吧,EF框架抽象出来的CRUD方法

namespace DAL
{
    public class UserInfoDal:BaseDal<UserInfo>,IUserInfoDal
    {      
    }
}
UserInfoDal

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);
    }
}
IBaseDal

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);
        }
    }
}
BaseService

同样面向接口编程,我们也要抽象出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);
        
    }
}
IBaseService

二、运用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
    }
  ]

}
json文件代码

配置方式注入代码如下:

           #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的融入写出来。

各位园友,多多指教,小僧可能有些地方有缺陷,多多留言,共同进步,谢谢!

 

以上是关于MVC5+EF+AutoFac+AutoMapper轻型架构的主要内容,如果未能解决你的问题,请参考以下文章

.NET MVC5+AUTOFAC实战

.NET MVC5+AUTOFAC实战

一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

AutoFac实现WebAPI依赖注入(EF以及Mysql)

一步一步学EF系列6IOC 之AutoFac