游刃于MVC、WCF中的Autofac

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

 本例中将会分享

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

2.WCF中的使用

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

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

这里用的是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();

            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

时间: 2024-10-28 09:55:35

游刃于MVC、WCF中的Autofac的相关文章

[Solution] 使用Autofac在MVC、Web API、WCF中实现IOC

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 本来想聊一下面试过程的,1个星期面了6家,4家当场给offer,2家技术通过(1家没下文,1家复试).从中也学习到一些东西,先还是继续Coding吧. 官网:http://autofac.org/ 下载:Install-Package Auto

ASP.NET MVC+WCF+NHibernate+Autofac 框架组合(一)

学习了Spring.NET+NHibernate的框架,觉得Spring.NET框架不够轻量,配置来配置去的比较头疼,所以把Spring.NET换成了Autofac框架,同时加入WCF框架整了一个组合. 本来想把NHibernate换成EF的,因为现在普通用的.net 4.0,但是.net 4.0里的EF对Oracle支持没那么好,.net4.5有了oracle新的驱动就挺好用了. 一点点心得,NHibernate也是刚熟悉,给像我一样的新手参考,一起学习,有什么不够合理的地方还请多多指教. 数

Asp.net mvc中整合autofac

创建Asp.net MVC并引入Autofac 首先,创建一个MVC站点,为方便起见,选初始带HomeController和AccountController的那种.然后通过NuGet或到Autofac官网下载来引入类库.个人推荐前者,因为从VS2010开始,已内集可视化的NuGet功能,使用起来非常方便.如下图所示: 这是vs2012的界面,点击“Manage NuGet Packages…”,弹出窗体如下,在右上角搜索框中输入“Autofac”,找到对应的库点击安装即可.这里需要应用的库有两

Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac(转)

经过上篇蜻蜓点水的介绍后,本篇通过实例快速上手autofac,展示当asp.net mvc引入了autofac之后会带来什么. 创建Asp.net MVC并引入Autofac 首先,创建一个MVC站点,为方便起见,选初始带HomeController和AccountController的那种.然后通过NuGet或到Autofac官网下载来引入类库.个人推荐前者,因为从VS2010开始,已内集可视化的NuGet功能,使用起来非常方便.如下图所示: 这是vs2012的界面,点击"Manage NuG

Autofac - MVC/WebApi中的应用

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/asp-net-core-overview.html http://www.yuanjiaocheng.net/ASPNET-CORE/asp.net-core-environment.html http://www.yuanjiaocheng.net/ASPNET-CORE/newproject.html http://www.yuanjiaocheng.net/webapi/web-api-gais

Asp.Net Web Forms/MVC/Console App中使用Autofac

本来简单介绍了Autofac在Asp.Net Web Forms中的应用,后来又添加了mvc.控制台应用程序中使用Autofac,详情请看源码. ASP.NET Web Forms使用Autofac,至少需要一下步骤: 1,引用Autofac程序集. 2,添加Autofac Web Modules 到 Web.config. 3,在Global.asax中实现IContainerProviderAccessor接口. 我们创建一个ASP.NET Web Forms项目,命名为WebFormStu

MVC + WCF + 三层架构中model的困惑

最近做一个项目有个地方比较就纠结,项目使用WCF做数据库服务,MVC5架构,三层架构(BLL,Model,DAL也就是调用WCF服务),这三者间传递数据基本是以对象为单位 如果User,但BLL调用WCF中model,和三层架构中model,还有MVC中的model,该怎么分配比较好呢,是mvc中建立model且在三层中建立model,还是三个中都只建立一个model.但mvc中显示的model不一定是bll中的model,可能只是其中的几个字段.如果分别都建立一个model,那我从BLL中传递

ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)

原文:ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用) 在上一章中主要和大家分享在MVC当中如何使用ASP.NET Core内置的DI进行批量依赖注入,本章将继续和大家分享在ASP.NET Core中如何使用Autofac替换自带DI进行批量依赖注入. PS:本章将主要采用构造函数注入的方式,下一章将继续分享如何使之能够同时支持属性注入的方式. 约定: 1.仓储层接口都以“I”开头,以“Repos

在asp.net mvc 中使用Autofac

据说.net 世界里,最强的依赖注入容器是Autofac .不管是谁,Nopcommerce2.8 用了它,所以就简单研究一下喽. 用vs 2012 创建一个Asp.net mvc3 的样例项目.然后使用NuGet(Vs2012 自带的有,版本低的话,似乎要安装插件),下载安装autofac的dll,如图1,2. 图1 NuGet 图2 ,load  autofac autofac 要加载两个dll哦,一个是autofac 的core ,另外一个是和asp.net mvc3集成的dll 然后,我