Autofac 之二 实例

Autofac 概述

附上参考地址(http://autofac.readthedocs.io/en/latest/getting-started/index.html)
通过上文明白了什么是IOC,下面就大概具体的了解一下实现IOC的一个容器Autofac,先看代码:

//从数据库读数据接口
public interface IUserStore<T>
    where T : class
{
    List<T> List(string city);
}

//具体读数据的实现
public class MysqlUserStore : IUserStore<MUser>
{
    public List<MUser> List(string city)
    {
        //TODO

        return new List<MUser> {
            new MUser { UserID="mysql1"},
            new MUser { UserID="mysql2"}
        };
    }
}

//处理业务的接口
public interface IUserServer<T>
{
    List<T> UserList();
}

//处理业务的实现
public class UserServer : IUserServer<MUser>
{
    private IUserStore<MUser> store;

    public UserServer(IUserStore<MUser> store)
    {
        this.store = store;
    }

    public List<MUser> UserList()
    {
        var list = store.List("cd");
        //Other business

        return list;
    }
}

从上面的代码可以发现,我们在需要处理具体业务的时候,只需要关注实现了IUserServer 的实例就可以了,以MVC中的Controller为例,我们在调用UserList()方法时,在没有IOC的情况下,我们可能会这样处理:

private IUserServer<MUser> userServer;
public HomeController()
{
    IUserStore<MUser> userStore = new MysqlUserStore();
    this.userServer = new UserServer(userStore);
}

[Route("list"), HttpGet]
public IHttpActionResult UserList()
{
    var list = this.userServer.UserList();

    return Ok(list);
}

可以看出,我们在HomeController 手动的指定了IUserServer对应的实例,以及该实例的构造需要的实例,这样很明显的实例的控制权还是没有剥离开来,所以当我们使用IOC容器之后,可以向下面这样:

private IUserServer<MUser> userServer;

public HomeController()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<UserServer>().AsImplementedInterfaces();
    builder.RegisterType<MysqlUserStore>().AsImplementedInterfaces();

    var container = builder.Build();

    using (var scope = container.BeginLifetimeScope())
    {
        this.userServer = scope.Resolve<IUserServer<MUser>>();
    }
}

[Route("list"), HttpGet]
public IHttpActionResult UserList()
{
    var list = this.userServer.UserList();

    return Ok(list);
}
  1. 我们把会用到的“组件” 都注册到容器里面去,当需要使用的时候通过scope.Resolve<IUserServer>(); 就可以得到我们需要的实例,这样就把对象的创建、管理交给了第三方控制即Autofac。
  2. 当然,在真正的程序里面container 我们肯定是放到一个全局的地方,整个生命周期维护一个container,有统一注册“组件”的地方,在Controller里面只需要直接Resolve需要的实例即可,这儿只是为了方便理解,所以把容器的注册和使用放在了一起。
  3. Autofac 在创建UserServer的实例时,发现该实例的构造需要实现了IUserStore的实例,于是会在容器中找是否有该实例,因为注册了MysqlUserStore 所以在创建UserServer的实例时会自动创建MysqlUserStore实例
  4. 虽然可以使用container.Resolve 来直接获取实例,但是官网更推荐使用 BeginLifetimeScope,来防止内存泄漏
  1. 很明显现在存在几个问题:
  • container 的初始化和注册应该放在什么地方?
  • 每次需要使用实例的时候都使用Resolve 去创建实例并不方便,同时官网也不推荐这么做
  • 当我们每写好一个“组件”时都要去容器里面注册一下,有没有什么方法可以避免?
private IUserServer<MUser> userServer;

public HomeController(IUserServer<MUser> userServer)
{
    this.userServer = userServer;
}

[Route("list"), HttpGet]
public IHttpActionResult UserList()
{
    var list = this.userServer.UserList();

    return Ok(list);
}

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var builder = new ContainerBuilder();

        //iis宿主  config获取
        var config = GlobalConfiguration.Configuration;
        //注册apiControllers
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());


        builder.RegisterType<UserServer>().AsImplementedInterfaces();
        builder.RegisterType<MysqlUserStore>().AsImplementedInterfaces();


        //将依赖关系解析器设置为 Autofac
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}
  1. autofac 提供WebAPI、MVC...的集成,这儿已WebAPI2为例,首先安装 Autofac.WebApi2 NuGet package
  2. 集成后,在应用程序启动时(Global.ashx)中的Application_Start中,我们进行了组件的注册,就解决了container初始化和注册位置的问题
  3. 使用RegisterApiControllers将API的Controllers 全部注册到容器中去,同时通过设置DependencyResolver,使得我们在Controllers 中使用“组件”的时候就可以通过构造方法直接获取了,这也就解决了到处去Resolve 得问题
  4. RegisterApiControllers的用法还有很多,通常我们的Controller都是继承IHttpController 的,后缀都是Controller,那么当我们自定义了Controller了时可以使用RegisterType().InstancePerRequest()注册,同时也可以自定义后缀: RegisterApiControllers("MyCustomSuffix", Assembly.GetExecutingAssembly());
  5. 到这,我么依然需要每个“组件”都去注册,我们可以通过所有属性继承一个接口来解决这个问题
public interface IDependency
{
}


public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var builder = new ContainerBuilder();

        //iis宿主  config获取
        var config = GlobalConfiguration.Configuration;

        var assemblys = Assembly.GetExecutingAssembly();
        //注册apiControllers
        builder.RegisterApiControllers(assemblys);

        var baseType = typeof(IDependency);
        builder.RegisterAssemblyTypes(assemblys)
            .Where(sa => baseType.IsAssignableFrom(sa) && sa != baseType)
            .AsImplementedInterfaces().InstancePerLifetimeScope();

        //builder.RegisterType<UserServer>().AsImplementedInterfaces();
        //builder.RegisterType<MysqlUserStore>().AsImplementedInterfaces();


        //将依赖关系解析器设置为 Autofac
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}
posted @ 2019-01-25 09:33  Pen丶  阅读(237)  评论(0编辑  收藏  举报