一:
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学习之三种生命周期:
- InstancePerLifetimeScope:每次都会返回一个新的实例,并且这是默认的生命周期
- SingleInstance :单例,所有服务请求都将会返回同一个实例。
- 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>();
}
}