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的融入寫出來。

各位園友,多多指教,小僧可能有些地方有缺陷,多多留言,共同進步,謝謝!

 


免責聲明!

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



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