Autofac

简介

通常我们写程序时所有的对象都由我们手动的new出来,这样项目之间互相依赖,各个模块之间耦合严重,当需要修改为其他实现类时非常麻烦。通过IOC可以解除依赖,让代码结构看起来更加合理,并能够提升项目的稳定性和可用性。
Autofac是IOC(Inversion of Control,控制反转)容器的一种,使用IOC容器一般建议基于接口编程。在使用的时候声明接口类型的变量、属性是由容器负责赋值。接口、实现类一般也是定义在单独项目中以减少相互之间的耦合。
基于接口编程:把方法定义到接口中,通过实现类实现接口的方法;

基本使用

安装Autofac:Install-Package Autofac
首先定义一个IAnimal接口和IRun接口,并分别定义Shout和Run方法:

namespace IService
{
    public interface IAnimal
    {
        void Shout();
    }
    // 应该分开写 
    public interface IRun
    {
        void Run();
    }
}

定义Dog、Student实现类实现如下接口:

namespace TestService
{
    public class Dog : IAnimal, IRun
    {
        public void Run()
        {
            Console.WriteLine("小狗在跑");
        }

        public void Shout()
        {
            Console.WriteLine("汪汪汪");
        }
    }
    // 同样要分开写
    public class Student : IRun
    {
        public void Run()
        {
            Console.WriteLine("学生在跑");
        }
    }
}

首先看看Autofac如何注册一个对象的:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType().As();  // 注册实现类Dog 当请求IAnimal接口的时候返回Dog对象

IContainer container = builder.Build();
IAnimal animal = container.Resolve();  // 创建IAnimal实现类的对象
animal.Shout();

上例中builder.RegisterType().As(); 只是将Dog注册为IAnimal接口的类型对象,无法通过container.Resolve().Run(); 方法调用Dog实现类Run方法。可以替换为builder.RegisterType().AsImplementedInterfaces(); 意思是将Dog注册为其所有实现的接口的接口类型对象。这样就可以同时调用Run的方法了。例:

IRun run = container.Resolve();
run.Run();

builder可以同时注册多个对象,如:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType().AsImplementedInterfaces();  // 注册Dog对象
builder.RegisterType().AsImplementedInterfaces();  // 注册Student对象

IContainer container = builder.Build();
IAnimal animal = container.Resolve();
animal.Shout();

IEnumerable  runs = container.Resolve>();
foreach (var run in runs)
{
    run.Run();
}

当我们需要注册的对象越多,以上写法就越显的多余,我们可以通过以下方法注册我们需要程序集中的对象:

Assembly[] assemblies = new Assembly[] { Assembly.Load("TestService") };
builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces();

如果同一个接口有多个实现类,如IRun接口,container.Resolve(); 方法只会返回其中一个类的对象。 如果想返回多个实现类的对象,使用container.Resolve>(); 获取通过foreach遍历即可。

如果一个实现类中定义了其他类型的接口属性,可以在注册的时候加上PropertiesAutowired(),PropertiesAutowired()会自动给属性进行“注入”。 如果可能有多个实现类,还可以声明IEnumerable类型的属性。被只有被Autofac 创建出来的对象才会被“属性自动注入”。

public class Dog : IAnimal
{
    public IEnumerable Runs { get; set; }

    public void Shout()
    {
        foreach (var run in Runs)
        {
            run.Run();
        }
        Console.WriteLine("汪汪汪");
    }
}
/* ================================================== */
ContainerBuilder builder = new ContainerBuilder();
Assembly[] assemblies = new Assembly[] { Assembly.Load("TestService") };
builder.RegisterAssemblyTypes(assemblies).AsImplementedInterfaces().PropertiesAutowired();

IContainer container = builder.Build();
IAnimal animal = container.Resolve();
animal.Shout();

ASP.Net MVC+Autofac

安装Autofac:Install-Package Autofac.Mvc5
首先构造一个Autofac容器的创建者:

// 构造Autofac容器的builder
var builder = new ContainerBuilder();

然后根据自己需要注册内容:

// 注入控制器
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
// 把程序集数组assemblies中所有非抽象的类型注入
Assembly[] assemblies = new Assembly[] { Assembly.Load("TestService") };
builder.RegisterAssemblyTypes(assemblies).Where(t => !t.IsAbstract).AsImplementedInterfaces()
    .PropertiesAutowired();
// 注入特性
builder.RegisterFilterProvider();
// 注入ActionFilter
builder.RegisterAssemblyTypes(typeof(MvcApplication).Assembly)
    .Where(t => typeof(ActionFilterAttribute).IsAssignableFrom(t) && !t.IsAbstract)
    .PropertiesAutowired();

通过builder创建容器,并提供给MVC:

// 创建容器
IContainer container = builder.Build();
// 提供给MVC,这样当MVC框架创建Controller等对象时都是从Autofac获取
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

在Autofac容器中注入后,在使用时只用在Controller中声明Service属性即可,Autofac会自动进行“属性注入”。

public class DefaultController : Controller
{
    public IService Service { get; set; }
}

当然,只有通过Autofac帮我们创建的对象并且PropertiesAutowired()后才能给我们自动进行属性的赋值。
有时候我们需要在没有进行注入的地方(如:TestHelper)获取注入的对象,可以通过以下方法:

public class TestHelper
{
    public static void Test()
    {
        IService service = DependencyResolver.Current.GetService();
    }
}

上面方法指的是在同一个线程中调用,当我们在Quartz等单独线程中,就无法通过DependencyResolver.Current.GetService();方式获取,需要通过下面的方式获取对象:

IService service;
var container = AutofacDependencyResolver.Current.ApplicationContainer;

using (container.BeginLifetimeScope())
{
    service = container.Resolve();
}

Autofac对象的生命周期

InstancePerDependency():每次请求Resolve都会返回一个新的、唯一的实例;
SingleInstance():单例,每次都获取相同的共享实例(返回同一个对象);
InstancePerLifetimeScope(): 每个生命周期一个实例;
InstancePerRequest(): ASP.Net MVC 专用,每个请求一个对象;

你可能感兴趣的:(Autofac)