游刃于MVC、WCF中的Autofac

为了程序的健壮性、扩展性、可维护性,依赖抽象而不是具体实现类等等,于是我选择了Autofac依赖注入容器 就是这个工厂来降低耦合。之前买东西是自己去超市,现在呢 我需要什么东西,他们给送过来直接拿到了。

 本例中将会分享

1.Autofac在Mvc的Controller控制器、Filter过滤器的使用

2.WCF中的使用

3.用Autofac来完成Unit Of Work工作单元模式 即同一个界限上下文内可以共享同一个工作单元实例。这样就可以统一提交,起到事务作用、数据统一性。一个http请求只有一个上下文实例也算是性能优化吧, 在这里只用到工作单元的一些皮毛。

Demo全貌如下

游刃于MVC、WCF中的Autofac

  •  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配置文件两种方式指定接口、实现类来完成注入实例。

这里用的是xml配置的方式,需要用到Autofac.Configuration程序集。这样做有个明显的好处:文件不需要编译;不会扰乱各层关系。为什么这么说呢?如果用代码来完成,web层就需要其他层的接口和实现类 也就是引用Repository、UnitOfWork、CoreService层,很明显web层只需要引用Autofac.Controllers  就足够了。而通过xml配置文件可以在bin目录下找到具体的程序集如:Autofac.CoreService.dll

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

你可能感兴趣的:(auto)