遊刃於MVC、WCF中的Autofac

爲了程序的健壯性、擴展性、可維護性,依賴抽象而不是具體實現類等等,因而我選擇了Autofac依賴注入容器 就是這個工廠來下降耦合。以前買東西是本身去超市,如今呢 我須要什麼東西,他們給送過來直接拿到了。html

 本例中將會分享前端

1.Autofac在Mvc的Controller控制器、Filter過濾器的使用web

2.WCF中的使用性能優化

3.用Autofac來完成Unit Of Work工做單元模式 即同一個界限上下文內能夠共享同一個工做單元實例。這樣就能夠統一提交,起到事務做用、數據統一性。一個http請求只有一個上下文實例也算是性能優化吧, 在這裏只用到工做單元的一些皮毛。ide

Demo全貌以下函數

  •  Autofac.DataModel 採用database first的實體數據模型
  •  Autofac.Repository 實體泛型的倉儲模式 ,也能夠簡單的理解是數據層
  •  Autofac.CoreService 業務邏輯處理
  •  Autofac.UnitOfWork 工做單元統一提交 
  •  Autofac.Controllers 控制器層是從Web層把全部控制器提取出來,這裏用到區域Area
  •  AutoFac.Web 前端採用的是MVVM模式的knockout.js ,還有autofac的配置
  •  Autofac.ViewModel 視圖

  其中Repository、UnitOfWork、CoreService幾者之間調用接口或對供其餘層調用接口。性能

  從nuget獲取必要的Autofac程序包 Autofac、Autofac.Configuration、Autofac.Integration.Mvc、Autofac.Integration.Wcf優化

各個層依賴的是接口而不是具體實現類,Autofac是個工廠能夠經過編譯的代碼xml配置文件兩種方式指定接口、實現類來完成注入實例。ui

這裏用的是xml配置的方式,須要用到Autofac.Configuration程序集。這樣作有個明顯的好處:文件不須要編譯;不會擾亂各層關係。爲何這麼說呢?若是用代碼來完成,web層就須要其餘層的接口和實現類 也就是引用Repository、UnitOfWork、CoreService層,很明顯web層只須要引用Autofac.Controllers  就足夠了。而經過xml配置文件能夠在bin目錄下找到具體的程序集如:Autofac.CoreService.dllthis

Autoface依賴注入在MVC裏實現

Global.cs    

protected void Application_Start()
        {
            //建立IOC容器
            AutofacRegistion.BuildMvcContainer();
            AutofacRegistion.BuildWcfContainer();
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
/// <summary>
    /// 依賴注入Controller、FilterAtrribute、WCF
    /// </summary>
    public class AutofacRegistion
    {
        /// <summary>
        /// 建立 MVC容器(包含Filter)
        /// </summary>
        public static void BuildMvcContainer()
        {
            var builder = new ContainerBuilder();
            //註冊Module方法2 在Web.config中配製方式
            builder.RegisterModule(new ConfigurationSettingsReader("autofacMvc"));
            //加載 *.Controllers 層的控制器,不然沒法在其餘層控制器構造注入,只能在web層注入
            Assembly[] asm = GetAllAssembly("*.Controllers.dll").ToArray();
            builder.RegisterAssemblyTypes(asm);
            //註冊倉儲
            Assembly[] asmRepository = GetAllAssembly("*.Repository.dll").ToArray();
            builder.RegisterAssemblyTypes(asmRepository)
               .Where(t => t.Name.EndsWith("Repository"))
               .AsImplementedInterfaces();

        //注入邏輯層也能夠經過配置實現
        //Assembly[] asmRepositoryService = GetAllAssembly("*.CoreService.dll").ToArray();
        //builder.RegisterAssemblyTypes(asmRepositoryService).AsImplementedInterfaces();


            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinderProvider();

            
            //註冊過濾器 
            builder.RegisterFilterProvider();
            builder.RegisterType<OperateAttribute>().PropertiesAutowired();
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
        /// <summary>
        ///建立WCF的容器,不存放Controller、Filter
        /// </summary>
        public static void BuildWcfContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterModule(new ConfigurationSettingsReader("autofacWcf"));
            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinderProvider();
            var container = builder.Build();
            //WCF IOC容器
            AutofacHostFactory.Container = container;
            //DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }

        #region 加載程序集
        public static List<Assembly> GetAllAssembly(string dllName)
        {
            List<string> pluginpath = FindPlugin(dllName);
            var list = new List<Assembly>();
            foreach (string filename in pluginpath)
            {
                try
                {
                    string asmname = Path.GetFileNameWithoutExtension(filename);
                    if (asmname != string.Empty)
                    {
                        Assembly asm = Assembly.LoadFrom(filename);
                        list.Add(asm);
                    }
                }
                catch (Exception ex)
                {
                    Console.Write(ex.Message);
                }
            }
            return list;
        }
        //查找全部插件的路徑
        private static List<string> FindPlugin(string dllName)
        {
            List<string> pluginpath = new List<string>();
           
                string path = AppDomain.CurrentDomain.BaseDirectory;
                string dir = Path.Combine(path, "bin");
                string[] dllList = Directory.GetFiles(dir, dllName);
                if (dllList.Length > 0)
                {
                    pluginpath.AddRange(dllList.Select(item => Path.Combine(dir, item.Substring(dir.Length + 1))));
                }
            return pluginpath;
        }
        #endregion

    }

說明:

1 web.config還須要配置 globlal代碼中對應的【autofacMvc】和【autofacWcf】節點

2 反射*.Controllers.dll獲取 Autofac.Controllers程序集,實現注入

3 反射*.Repository.dll獲取 Autofac.Repository程序集 以'Repository'結尾的類的實例注入到它所繼承的接口,這個就不須要在xml中配置

4 filter的注入和controller的注入方式不同

5 MVC和WCF注入實例分別存到兩個容器中。這就用到Autofac.Integration.Mvc、Autofac.Integration.Wcf兩個程序集。WCF注入的容器中不須要Controller、Filter,就能夠把相關的反射和註冊去掉了。

web.config

<configSections>
    <!-- autofac配置-->
    <section name="autofacMvc" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
    <section name="autofacWcf" type="Autofac.Configuration.SectionHandler, Autofac.Configuration" />
  </configSections>
  <autofacMvc>
    <files>
      <file name="configs/CoreService.config" section="autofac" />
    </files>
  </autofacMvc>
  <autofacWcf>
    <files>
      <!--<file name="configs/IocDAL.config" section="autofac" />-->
    </files>
  </autofacWcf>
  <!--↑↑↑↑autofac配置結束↑↑↑↑-->

在上述webconfig中爲了統一管理配置,具體指定接口、實現類、和注入實例的生命週期放到了configs/CoreService.config文件中

CoreService.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
    </configSections>
    <autofac>
        <components>
      <!--DbContext上下文的生命週期爲【per-lifetime-scope】即http請求的生命週期 -->
      <component type="Autofac.DataModel.VehicleCheckDBEntities, Autofac.DataModel" 
                       service="System.Data.Entity.DbContext, EntityFramework"
                       instance-scope="per-lifetime-scope"/>
            <component type="Autofac.UnitOfWork.UnitOfWork, Autofac.UnitOfWork" service="Autofac.UnitOfWork.IUnitOfWork, Autofac.UnitOfWork" />
            
            <component type="Autofac.CoreService.Impl.UserManage, Autofac.CoreService" service="Autofac.CoreService.IUserManage, Autofac.CoreService" />
            <component type="Autofac.CoreService.Impl.RoleManage, Autofac.CoreService" service="Autofac.CoreService.IRoleManage, Autofac.CoreService" />
        </components>
    </autofac>
</configuration>

說明:

1 component組件配置中type、service配置的是實現類、程序集名稱(不是命名空間)、接口、程序集名稱。

2 instance-scope 配置的是實例的生命週期。本例中用到兩種:一是默認的調用一次建立一次;二是一個http請求會共享一個實例,期間會屢次用到,但只有一個實例。這個就是工做單元的核心了。instance-scope="per-lifetime-scope"類型共享DbContext的上下文實例。

參考官網 http://docs.autofac.org/en/latest/configuration/xml.html#additional-config-files

注入方式

MVC、WCF下是經過構造方法注入,Filter過濾器是經過訪問器get set注入,下面有具體區別。

Controller和其餘層的構造注入

public class HomeController : Controller
    {
        private readonly IUserManage _userManage;
        private IRoleManage _roleManage;
        public HomeController(IUserManage userManage, IRoleManage roleManage)
        {
            _userManage = userManage;
            _roleManage = roleManage;
        }
   }

Filter過濾器的注入取得實例

public class OperateAttribute : ActionFilterAttribute
    {
        public IUserManage UserManage { get; set; }
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            //Do Something...
            var user =UserManage.LoadUser(0);
            if (user == null)
            {
                filterContext.Result = new JsonResult
                {
                    Data=new{message="不合法操做,未能進入"},
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                }; 
            }
        }
    }

WCF注入

<!-- wcf服務文件 -->
<%@ ServiceHost 
    Language="C#" 
    Debug="true" 
    Service="CypApp.VehicleWeb.Services.IAutofacService,CypApp.VehicleWeb" 
    Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf"
%>
    //契約的實現類服務
   /// <summary>
   /// Autofac wcf注入
   /// </summary>
    public class AutofacService : IAutofacService
    {
        private readonly IInspectorBc _functionBc;
        //構造函數依賴注入
        public AutofacService(IInspectorBc functionBc)
        {
            _functionBc = functionBc;
        }
        public void DoWork()
        {
            _functionBc.GetCompanyIdByInspectorId(0);
        }
    }
}
/// <summary>
    ///     EntityFramework倉儲操做基類
    /// </summary>
    /// <typeparam name="TEntity">動態實體類型</typeparam>
    public class EFRepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class,new()
    {
        public EFRepositoryBase(DbContext context)
        {
            Context = context;
        }
        public DbContext Context { get; set; }

        public void Dispose()
        {
            if (Context==null)return;
            Context.Dispose();
            Context = null;
            GC.SuppressFinalize(this);
        }
        public IQueryable<TEntity> Entities()
        {
            return Context.Set<TEntity>().AsQueryable();
        }
        //Delete、Update等等
}
public sealed class UnitOfWork : IUnitOfWork
    {
        /// <summary>
        /// The DbContext
        /// </summary>
        private DbContext _dbContext;

        /// <summary>
        /// Initializes a new instance of the UnitOfWork class.
        /// </summary>
        /// <param name="context">The object context</param>
        public UnitOfWork(DbContext context)
        {

            _dbContext = context;
        }

        /// <summary>
        /// Saves all pending changes
        /// </summary>
        /// <returns>The number of objects in an Added, Modified, or Deleted state</returns>
        public int Commit()
        {
            // Save changes with the default options
            return _dbContext.SaveChanges();
        }

        /// <summary>
        /// Disposes the current object
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Disposes all external resources.
        /// </summary>
        /// <param name="disposing">The dispose indicator.</param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_dbContext != null)
                {
                    _dbContext.Dispose();
                    _dbContext = null;
                }
            }
        }
    }

//業務邏輯處理
public
class UserManage : IUserManage { private readonly IUserRepository _userRepository; private readonly IUserRoleRepository _userRoleRepository; private IUnitOfWork _unitOfWork; public UserManage(IUserRepository userRepository, IUserRoleRepository userRoleRepository,IUnitOfWork unitOfWork) { _userRepository = userRepository; _userRoleRepository = userRoleRepository; _unitOfWork = unitOfWork; } /// <summary> /// 添加、修改 User /// </summary> /// <param name="userModel"></param> /// <param name="message"></param> /// <returns></returns> public bool SaveUser(UserModel userModel , out string message) { message = null; var userEntity = new Sys_User { UserName = userModel.UserName, Password = userModel.Password, UserTrueName = userModel.UserTrueName, CreateDate = DateTime.Now, }; //添加用戶 if (userModel.Id < 1) { _userRepository.Insert(userEntity); _unitOfWork.Commit(); if (userEntity.Id < 1) { message = "添加用戶失敗"; return false; } } //修改操做 else { //刪除用戶角色關係 var userRoleIdArray = _userRoleRepository.Entities() .Where(m => m.UserId == userModel.Id) .Select(s => s.Id).ToList(); foreach (var roleId in userRoleIdArray) { _userRoleRepository.Delete(new Sys_User_Roles {Id = roleId}); } } var userRoles = new List<Sys_User_Roles>(); foreach (var roleId in userModel.Role) { userRoles.Add(new Sys_User_Roles { UserId = userModel.Id, RoleId = roleId }); } //添加用戶角色關係 _userRoleRepository.Insert(userRoles); return _unitOfWork.Commit() > 0; }

 批量刪除、批量添加操做只是映射,並未提交,只有Commit後纔會保存數據。各個類拿到的DbContext是同一個實例,所以統一提交整個上下文狀態才起到了做用。

倉儲和工做單元都有銷燬方法, 每次調用倉儲類和工做單元類, 都會從IOC容器取到共享實例Dbcontext,當處理完業務後會把這些拿到的Dbcontext實例銷燬掉。

 

共享Demo

AutoFac.7z

相關文章
相關標籤/搜索