Autofac深入讲解

一:

Autofac配置(在控制器中拿到IOC容器

public class AutoFacConfig
{
    public static void Register()
    {
        ContainerBuilder builder = new Autofac.ContainerBuilder();

        //获取WebApp这个项目的Assembly程序集
        Assembly controllerAss = Assembly.Load("WebApp");
        //注册这个程序集中所有的IController接口的实现类(实现了IController接口的类即是控制器,所以这里是注册这个程序集中所有的控制器)
        builder.RegisterControllers(controllerAss);

        //当然,我们也可以这样写: 即注册当前项目中的所有控制器
        //builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();

        //注册NationalityDal类 (不需要以接口的形式保存,因为有的类是没有接口的,比如过滤器类,这里我们只需要将这个类进行注册即可(用IOC容器管理起来))
        builder.RegisterType<NationalityDal>()
        //或者
        builder.RegisterType(typeof(NationalityDal))



        //注册NationalityDal类,并将它转换成INationalityDal接口类型(即以NationalityDal类型的对象以INationalityDal接口的形式保存)
        builder.RegisterType<NationalityDal>().As<INationalityDal>();
        builder.RegisterType<PersonDal>().As<IPersonDal>();


        //以上两条语句是针对这个PersonDal这个类仅仅只实现了一个IPersonDal接口,和NationalityDal类接口仅仅实现了一个INationalityDal接口的写法

        //那假如PersonDal类实现了多个接口,那我们就可以这样写(假如这个PersonDal实现了5个接口,当我们需要这个5个接口的实现类的时候,都可以返回这PersonDal类的实例对象)
        builder.RegisterType<PersonDal>().AsImplementedInterfaces();

        //第四步:创建一个真正的AutoFac的工作容器  
        IContainer container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        //----------------完


        //有时候我们需要在控制器中使用这个container容器来拿某个接口的实现类对象那我们怎么做呢?有两种方式:
        //第一种:
        //我们可以将这个container工作容器类存到缓存中,然后再控制器中通过调用获取缓存的方式拿到这个工作容器类
        //拿到这个工作容器类后,可以做一下操作,获取这个接口的实现类对象

        CacheHelper.SetCache("aotufac", container);

        //第二种:
        //我们可以在控制器,或者其他地方这样写,这样就拿到了INationalityDal接口的实现类对象了
        var natDal = DependencyResolver.Current.GetService<INationalityDal>();
        //如果一个类没有接口,(只是对它进行了注册,并没有以接口的形式保存)GetService泛型参数就直接写类名即可(不一定非得是接口)
        var natDai = DependencyResolver.Current.GetService<NationalityDal>();

    }
}

既然我吧Autofac的工作容器存放到缓存中了,那我们就可以通过缓存拿到这个Autofac工作容器类

 

namespace WebApp.Controllers
{
    using Autofac;
    using BF.IDAL.EntityIDal;
    using System.Data.Entity;
    using WebApp.Filters;// 如果要在IQueryable接口中使用Include就如要引入它
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            //从缓存中获取Autofac工作容器
            IContainer container = CacheHelper.GetCache("autofac") as IContainer;

            //获取IPersonDal接口的实现类对象(假如IPersonDal接口有5个实现类,这种写法,仅仅是返回其中一个实现类的对象,具体不知道返回的是那个实现类的对象,它应该是通过Autofac的工作机制来确定返回哪个实现类对象)
            IPersonDal perdal = container.Resolve<IPersonDal>();

            //假如IPersonDal接口有5个实现类,那我们可通过以下写法获取这个5个实现类的对象集合
            IEnumerable<IPersonDal> persDal = container.Resolve<IEnumerable<IPersonDal>>();
            foreach (IPersonDal pd in persDal)
            {
                //遍历IPersonDal接口的5个实现类对象。
            }

            var ninfo = perdal.GetNationality();//调用IPersonDal接口中的GetNationality()方法


            //调用IPersonDal接口的GetList()方法
            var pList = perdal.GetList().Include("Nationality").ToList();
            return View();
        }
    }
}

 

 

二:属性自动注入

 

 

PropertiesAutowired()方法

在Autofac配置中,我们对在创建类的实例对象,并以接口的形式保存。

builder.RegisterType<PersonDal>().AsImplementedInterfaces()

我们可以在后面加上这样一个PropertiesAutowired()方法

这个方法表示:如果一个实现类中定义了其他类型的接口属性,,它会自动给属性进行“注入”

 builder.RegisterType<PersonDal>().AsImplementedInterfaces().PropertiesAutowired();

使用:在业务逻辑层,在数据层,在控制器中均可使用。

Autofac配置

public class AutoFacConfig
{
    public static void Register()
    {
        ContainerBuilder builder = new Autofac.ContainerBuilder();
        //Assembly controllerAss = Assembly.Load("WebApp");
        //builder.RegisterControllers(controllerAss);//这段可以该用以下这一段代码替换

        //把当前程序集中的Conntroller都注册
        builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();


        //把当前程序集中的所有非抽象类型的ActionFilterAttribute都注册(这样我们在所有ActionFilterAttribute及子类中都可以使用属性注入)
        //前提:注册这个过滤的时候,这个过滤器的对象不能直接new出来,而是要去IOC容器中得到这个过滤类的对象。
        //例如:需要这样注册过滤:filters.Add(DependencyResolver.Current.GetService<CheckLoginAttribute>());
        builder.RegisterFilterProvider();
        builder.RegisterAssemblyTypes(typeof(MvcApplication).Assembly).Where(r => typeof(ActionFilterAttribute).IsAssignableFrom(r) && !r.IsAbstract).PropertiesAutowired();

        //注册NationalityDal类,并将它转换成INationalityDal接口类型(即以NationalityDal类型的对象以INationalityDal接口的形式保存) 
        builder.RegisterType<NationalityDal>().As<INationalityDal>();
        builder.RegisterType<PersonDal>().As<IPersonDal>();

        //那假如PersonDal类实现了很多个接口,那我们也可以这样写
        //builder.RegisterType<PersonDal>().AsImplementedInterfaces()
        //这样写的好处是:假如这个PersonDal实现了5个接口,只要我们需要这个5个接口的实现类,都可以返回这PersonDal类的实例对象

        //PropertiesAutowired()表示如果一个实现类中定义了其他类型的接口属性,它会自动给属性进行“注入”
        builder.RegisterType<PersonDal>().AsImplementedInterfaces().PropertiesAutowired();

        //其实我们还可以在.PropertiesAutowired()方法后面在进行一些策略的配置:
        //.InstancePerDependency();表示每次请求Resovle都返回一个新的对象
        //.SingleInstance();表示每次请求都返回同一个对象(单例),但是实现类必须是无状态的,即实现类没有成员变量(属性也不行,因为属性是由成员变量组成的),只能单纯的方法。
        //.InstancePerRequest(); 这个是Asp.net MVC专用,每个请求一次,在当前的http请求范围之内返回同一个对象.它的意思就是:在一个嵌套语句块中,只会返回一个实例,例如一个for循环中,在for循环中通过autofac容器获取实例对象,那么通过这种方式,它就返回同一个对象给你;详情请参考:https://www.cnblogs.com/stulzq/p/8547277.html

        //对一个程序集中的类进行注册(管理)
        Assembly repositoryAss = Assembly.Load("ZKHKCMS.Repositorys");
        Type[] rtypes = repositoryAss.GetTypes();
        builder.RegisterTypes(rtypes)
            .AsImplementedInterfaces().PropertiesAutowired();

        //创建一个真正的AutoFac的工作容器  
        IContainer container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

    }
}

在过滤器中使用属性注入(特别注意过滤器的注册,过滤器对象最好不要直接new,而是去IOC容器中拿,否则不能直接在过滤器中使用属性注入)

 

namespace WebApp.Filters
{
    public class CheckLoginAttribute : ActionFilterAttribute
    {
        //这里会自动对INationalityDal属性进行注入(前提,需要在控制器类或者方法上打上这个[CheckLogin]特性标签的形式进入到这个特性方法中,如果不想打标签请看下面第二段代码)
        public INationalityDal nat { get; set; } 
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var natList = nat.GetList().ToList();
        }
    }
}

注意,如果这里在控制器中对属性进行注入,如果不想在控制器上打[CheckLogin]这个标签,就需要换种形式注册这个过滤器

namespace MvcApp.App_Start
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());

            //注册过滤器
            //注意:这里别使用filters.Add(new CheckLoginAttribute())这种形式来注册过滤器,否则不能直接在过滤器中使用属性注入
            //因为一个对象必须是由IOC容器创建出来的,IOC容器才会自动帮我们注入
            filters.Add(DependencyResolver.Current.GetService<CheckLoginAttribute>()); //注册过滤器,这个过滤器类对象必须得从IOC容器中得到
        }
    }
}

 

 

 

在DAL层中使用属性注入

namespace BF.DAL.EntityDal
{
    public class PersonDal : BaseDal<Person>, IPersonDal
    {
        //如果加了这个PropertiesAutowired()方法方法,这里会对INationalityDal接口注入实现类对象
        //但是这样有个前提,那就是PersonDal类是被Autofac工作容器类所管理的类
        public INationalityDal natDal { get; set; }//在PersonDal类中定义一个接口类属性(会自动进行注入)

        public Nationality GetNationality()
        {
            //这里可以拿到这个INationalityDal接口的实现类对象进行操作
            var nat = natDal.GetList().FirstOrDefault();
            return nat;
        }
    }
}

在控制器中使用属性注入

namespace WebApp.Controllers
{
    [CheckLogin]
    public class HomeController : Controller
    {
        //IPersonDal属性会被自动进行注入
        public IPersonDal perDal { get; set; }

        public ActionResult Index()
        {
            var list = perDal.GetList(); //调用成功
            return View();
        }
    }
}

解释下在注释里面说的实现类是什么意思:

例如:IPersonDal perdal = container.Resolve<IPersonDal>(); 这段代码。 Autofac工作容器的Resolve泛型方法获取IPersonDal接口的实现类对象 即获取PersonDal 类的对象

在Autofac配置中有这样一段代码:

builder.RegisterType<PersonDal>().AsImplementedInterfaces()

这段代码就表示注册(创建)PersonDal类的实例对象以接口的形式保存在Autofac的工作容器中。实际上PersonDal类就已经被Autofac管理起来了。

 

-------------------------------下面提供下项目的数据层

 

IDAL

IBaseDal<T>

namespace BF.IDAL
{
    public interface IBaseDal<T> where T : class
    {
        /// <summary>
        /// 获取数据集合
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetList();
    }
}

IPersonDal

namespace BF.IDAL.EntityIDal
{
    public interface IPersonDal: IBaseDal<Person>
    {
    }
}

 

DAL

 

baseDal<T> 

namespace BF.DAL
{
    public class BaseDal<T> : IBaseDal<T> where T : class
    {
        BFDbContext db = new BFDbContext();
        /// <summary>
        /// 获取数据集合
        /// </summary>
        /// <returns></returns>
        public IQueryable<T> GetList()
        {
            return db.Set<T>();
        }
    }
}

PersonDal

namespace BF.DAL.EntityDal
{
    public class PersonDal : BaseDal<Person>, IPersonDal
    {
        //如果加了这个PropertiesAutowired()方法方法,这里会对INationalityDal接口注入实现类对象
        //但是这样有个前提,那就是PersonDal类是被Autofac工作容器类所管理的类对象
        public INationalityDal natDal { get; set; }//在PersonDal类中定义一个接口类属性(会自动进行注入)

        public Nationality GetNationality()
        {
            //这里可以拿到这个INationalityDal接口的实现类对象进行操作
            var nat = natDal.GetList().FirstOrDefault();
            return nat;
        }
    }
}

 

在一些单独的线程中通过Autofac容器来获取对象

例如:在Quartz定时框架中使用Autofac来获取接口的实例对象

如果在Quartz等单独的线程中,无法通过DependencyResolver.Current.GetService<ICityService>()获取对象,就要通过下面的方式来获取接口的实例对象 

 

namespace WebApp
{
    using Quartz;
    using Autofac;
    using Autofac.Integration.Mvc;
    using BF.IDAL.EntityIDal;
    public class MyQuartz : IJob
    {
        public void Execute(IJobExecutionContext context)
        {
            var container = AutofacDependencyResolver.Current.ApplicationContainer;//获取Autofac工作容器类对象
            using (container.BeginLifetimeScope())
            {
                //注意:这里使用Resolve需要手动using Autofac;
                var perdal = container.Resolve<IPersonDal>(); //获取IPersonDal接口的实现类对象

                var a = perdal.GetList();
            }
        }
    }
}

 

 

Autofac学习之三种生命周期:

  1. InstancePerLifetimeScope:每次都会返回一个新的实例,并且这是默认的生命周期
  2. SingleInstance :单例,所有服务请求都将会返回同一个实例。
  3. InstancePerDependency:在一个嵌套语句块中,只会返回一个实例。

关于InstancePerDependency详解:即在解决每个生命周期实例作用域组件时,每个嵌套作用域将获得一个实例(例如,每个工作单元)

using(var scope1 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    // 每次从这里解析它
    // 你会得到相同的实例。
    var w1 = scope1.Resolve<Worker>();
  }
}

using(var scope2 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    //每次从这里解析它
    //每次解析都会得到一个同样的实例,但是这个示例和上面的循环的实例不是同一个
    var w2 = scope2.Resolve<Worker>();
  }
}

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值