.NET Core 2 下Ioc容器Autofac使用
2018-03-29

Autofac基本使用

  Autofac是一款轻量级的IOC框架,使用率上还是挺高的,官方网站http://autofac.org,源码下载地址https://github.com/autofac/Autofac。

  下面以狗的列子来介绍autofac,nuget搜索Autofac进行安装

public interface IDog

    {

        /// <summary>

        /// 品种

        /// </summary>

        string Breed { get; }


        /// <summary>

        /// 名称

        /// </summary>

        string Name { get; }

    }


    /// <summary>

    /// 萨摩耶

    /// </summary>

    public class Samoyed : IDog

    {

        /// <summary>

        /// 品种

        /// </summary>

        public string Breed

        {

            get

            {

                return "Samoyed(萨摩耶)";

            }

        }


        /// <summary>

        /// 名称

        /// </summary>

        public string Name

        {

            get

            {

                return "小黄";

            }

        }

    }


    /// <summary>

    /// 藏獒

    /// </summary>

    public class TibetanMastiff : IDog

    {

        /// <summary>

        /// 品种

        /// </summary>

        public string Breed

        {

            get

            {

                return "Mastiff Class(獒犬类)";

            }

        }


        /// <summary>

        /// 名称

        /// </summary>

        public string Name

        {

            get

            {

                return "小黑";

            }

        }

    }

1.RegisterType 

public static void Register()

{

    var builder = new ContainerBuilder();

    //注册Samoyed指定为IDog实现

    builder.RegisterType<Samoyed>().As<IDog>();

    builder.RegisterType<TibetanMastiff>().As<IDog>();

    using (var container = builder.Build())

    {

        var dogs = container.Resolve<IEnumerable<IDog>>();

        foreach (var dog in dogs)

        {

             Console.WriteLine($"名称:{dog.Name},品种:{dog.Breed}");

        }

    }

}


2.RegisterAssemblyTypes

public static void RegisterAssemblyTypes()

{

    var builder = new ContainerBuilder();

    //注册程序集下所有类型

    builder.RegisterAssemblyTypes(typeof(Program).Assembly).AsImplementedInterfaces();

    using (var container = builder.Build())

    {

        var dogs = container.Resolve<IEnumerable<IDog>>();

        foreach (var dog in dogs)

        {

            Console.WriteLine($"名称:{dog.Name},品种:{dog.Breed}");

        }

    }

}

直接注册程序集下的所有类型,AsImplementedInterfaces(让具体实现类型,可以该类型继承的所有接口类型找到该实现类型)

  3.RegisterInstance

TibetanMastiff d = new TibetanMastiff();
builder.RegisterInstance(d).As<IDog>();

  4.RegisterModule

  这种模式需要使用配置文件进行注册,个人更喜欢代码直接注册的方式,毕竟配置文件修改容易遗忘和出错。这里就不介绍该方式了。 

      

  遗留问题:上面的注册代码,自己写写demo的时候没啥问题。但是运用到项目里面就很繁琐了,需要自己一个个类型注册,后面会提供解决方案。

 

.net core MVC与Autofac

  1.首先nuget下载AutofacAutofac.Extensions.DependencyInjection引用

  2.替换mvc自带的DI框架

  将Startup.cs中的ConfigureServices返回类型改为IServiceProvider

public IServiceProvider ConfigureServices(IServiceCollection services)

{

    services.AddMvc();


    var builder = new ContainerBuilder();

    builder.Populate(services);

    builder.RegisterAssemblyTypes(typeof(Startup).Assembly).AsImplementedInterfaces();

    var Container = builder.Build();

    return new AutofacServiceProvider(Container);

}

属性注入

Autofac默认是构造函数注入

[Route("api/[controller]")]

public class ValuesController : Controller

{

    private readonly IEnumerable<IDog> dogs;


    public ValuesController(IEnumerable<IDog> _dogs)

    {

        dogs = _dogs;

    }


    // GET api/values

    [HttpGet]

    public IEnumerable<string> Get()

    {

        List<string> list = new List<string>();

        foreach (var dog in dogs)

        {

            list.Add($"名称:{dog.Name},品种:{dog.Breed}");

        }

        return list.ToArray(); ;

    }

}


 

使用过mef的可能更喜欢属性注入的方式,那么使用autofac怎么实现属性注入呢?

1.注册系统所有Controller,由Autofac创建

var IControllerType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(assembly).Where(t => 
                IControllerType.IsAssignableFrom(t) && t != IControllerType).PropertiesAutowired();

 上面这段代码的解释:注册所有程序集下继承ControllerBase的类型,PropertiesAutowired 允许属性注入。

2.替换系统默认Controller创建器

services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());services.AddMvc();

注意:Replace代码放在AddMvc之前

Replace代码的意思:使用ServiceBasedControllerActivator替换DefaultControllerActivator(意味着框架现在会尝试从IServiceProvider中解析控制器实例,也就是return new AutofacServiceProvider(Container);

3.使用属性注入

[Route("api/[controller]")]

    public class ValuesController : Controller

    {

        public IEnumerable<IDog> dogs { get; set; }

        [HttpGet]

        public IEnumerable<string> Get()

        {

            List<string> list = new List<string>();

            foreach (var dog in dogs)

            {

                list.Add($"名称:{dog.Name},品种:{dog.Breed}");

            }

            return list.ToArray(); ;

        }

    }

至此完成了使用Autofac实现属性注入

Autofac+Castle实现AOP

1.首先nuget下载Autofac.Extras.DynamicProxy引用

2.编写拦截器


public class LogInterceptor : IInterceptor

{

    public void Intercept(IInvocation invocation)

    {

        Console.WriteLine("你正在调用方法 \"{0}\"  参数是 {1}... ",

           invocation.Method.Name,

           string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));


        invocation.Proceed();

        if (invocation.ReturnValue != null && invocation.ReturnValue is string)

        {

            //在返回接口上拼上LogInterceptor

            invocation.ReturnValue += " LogInterceptor";

        }

        Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);


        Console.WriteLine("开始记录日志....");

    }

}

3.开启拦截(接口拦截器  类拦截器

builder.RegisterType<LogInterceptor>();

builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces()

    .EnableInterfaceInterceptors();

var IControllerType = typeof(ControllerBase);

builder.RegisterAssemblyTypes(assembly).Where(t => IControllerType.IsAssignableFrom(t) && t != IControllerType).PropertiesAutowired()

    .EnableClassInterceptors();

var Container = builder.Build();

开启接口拦截器:EnableInterfaceInterceptors  开启类拦截器:EnableClassInterceptors
[Intercept(typeof(LogInterceptor))]
[Route("api/[controller]")]public class ValuesController : Controller
{
}
[Intercept(typeof(LogInterceptor))]public class Samoyed : IDog
{
}

这种使用方式需要自己指定在哪个类上使用,还有一种全局拦截器

builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().EnableInterfaceInterceptors()    .InterceptedBy(typeof(LogInterceptor));

 


代码封装简单使用

先列出使用过程中遇到的几个问题,然后再给出解决方案

1:如何简单注册代码里面的所有类型

2.如何注册单例和普通对象

3.封装好的代码怎么支持用户特殊化注册需求

为了解决上述问题,这里给出了几个约束

单例对象需继承的接口:ISingletonDependency  普通对象需继承的接口:ITransientDependency 特殊化注册接口:IDependencyRegistrar

通过这几个约束,在初始化时找所有程序集 继承ISingletonDependency ,ITransientDependency 接口的对象进行类型注册

/// <summary>
    /// 单例接口    /// </summary>
    public interface ISingletonDependency
    {
    }

/// <summary>

    /// 所有接口的依赖接口,每次创建新实例

    /// </summary>

    /// <remarks>

    /// 用于Autofac自动注册时,查找所有依赖该接口的实现。

    /// 实现自动注册功能

    /// </remarks>

    public interface ITransientDependency

    {

    }

/// <summary>

    /// 依赖注册接口

    /// </summary>

    public interface IDependencyRegistrar

    {

        /// <summary>

        /// Register services and interfaces

        /// </summary>

        /// <param name="builder">Container builder</param>

        /// <param name="config">Config</param>

        void Register(ContainerBuilder builder,List<Type> listType);


        /// <summary>

        /// Order of this dependency registrar implementation

        /// </summary>

        int Order { get; }

    }

public interface IIocManager

    {

        IContainer Container { get; }


        bool IsRegistered(Type serviceType, ILifetimeScope scope = null);

        object Resolve(Type type, ILifetimeScope scope = null);

        T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class;

        T Resolve<T>(params Parameter[] parameters) where T : class;

        T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null);

        object ResolveOptional(Type serviceType, ILifetimeScope scope = null);

        object ResolveUnregistered(Type type, ILifetimeScope scope = null);

        T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class;

        ILifetimeScope Scope();

        bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance);

    }

/// <summary>

    /// Container manager

    /// </summary>

    public class IocManager : IIocManager

    {

        private IContainer _container;


        public static IocManager Instance { get { return SingletonInstance; } }

        private static readonly IocManager SingletonInstance = new IocManager();


        /// <summary>

        /// Ioc容器初始化

        /// </summary>

        /// <param name="config"></param>

        /// <returns></returns>

        public IServiceProvider Initialize(IServiceCollection services)

        {

            var builder = new ContainerBuilder();

            builder.RegisterInstance(Instance).As<IIocManager>().SingleInstance();

            //所有程序集 和程序集下类型

            var deps = DependencyContext.Default;

            var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包

            var listAllType = new List<Type>();

            foreach (var lib in libs)

            {

                try

                {

                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));

                    listAllType.AddRange(assembly.GetTypes().Where(type => type != null));

                }

                catch { }

            }

            //找到所有外部IDependencyRegistrar实现,调用注册

            var registrarType = typeof(IDependencyRegistrar);

            var arrRegistrarType = listAllType.Where(t => registrarType.IsAssignableFrom(t) && t != registrarType).ToArray();

            var listRegistrarInstances = new List<IDependencyRegistrar>();

            foreach (var drType in arrRegistrarType)

            {

                listRegistrarInstances.Add((IDependencyRegistrar)Activator.CreateInstance(drType));

            }

            //排序

            listRegistrarInstances = listRegistrarInstances.OrderBy(t => t.Order).ToList();

            foreach (var dependencyRegistrar in listRegistrarInstances)

            {

                dependencyRegistrar.Register(builder, listAllType);

            }


            //注册ITransientDependency实现类

            var dependencyType = typeof(ITransientDependency);

            var arrDependencyType = listAllType.Where(t => dependencyType.IsAssignableFrom(t) && t != dependencyType).ToArray();

            builder.RegisterTypes(arrDependencyType)

                .AsImplementedInterfaces()

                .InstancePerLifetimeScope()

                .PropertiesAutowired().EnableInterfaceInterceptors();


            foreach (Type type in arrDependencyType)

            {

                if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))

                {

                    builder.RegisterType(type).As(type.BaseType)

                        .InstancePerLifetimeScope()

                        .PropertiesAutowired();

                }

            }



            //注册ISingletonDependency实现类

            var singletonDependencyType = typeof(ISingletonDependency);

            var arrSingletonDependencyType = listAllType.Where(t => singletonDependencyType.IsAssignableFrom(t) && t != singletonDependencyType).ToArray();

            builder.RegisterTypes(arrSingletonDependencyType)

                .AsImplementedInterfaces()

                .SingleInstance()

                .PropertiesAutowired();


            foreach (Type type in arrSingletonDependencyType)

            {

                if (type.IsClass && !type.IsAbstract && !type.BaseType.IsInterface && type.BaseType != typeof(object))

                {

                    builder.RegisterType(type).As(type.BaseType)

                        .SingleInstance()

                        .PropertiesAutowired();

                }

            }


            builder.Populate(services);

            _container = builder.Build();

            return new AutofacServiceProvider(_container);

        }


        /// <summary>

        /// Gets a container

        /// </summary>

        public virtual IContainer Container

        {

            get

            {

                return _container;

            }

        }


        /// <summary>

        /// Resolve

        /// </summary>

        /// <typeparam name="T">Type</typeparam>

        /// <param name="key">key</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            if (string.IsNullOrEmpty(key))

            {

                return scope.Resolve<T>();

            }

            return scope.ResolveKeyed<T>(key);

        }


        /// <summary>

        /// Resolve

        /// </summary>

        /// <typeparam name="T">Type</typeparam>

        /// <param name="key">key</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual T Resolve<T>(params Parameter[] parameters) where T : class

        {

            var scope = Scope();

            return scope.Resolve<T>(parameters);

        }


        /// <summary>

        /// Resolve

        /// </summary>

        /// <param name="type">Type</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual object Resolve(Type type, ILifetimeScope scope = null)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            return scope.Resolve(type);

        }


        /// <summary>

        /// Resolve all

        /// </summary>

        /// <typeparam name="T">Type</typeparam>

        /// <param name="key">key</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved services</returns>

        public virtual T[] ResolveAll<T>(string key = "", ILifetimeScope scope = null)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            if (string.IsNullOrEmpty(key))

            {

                return scope.Resolve<IEnumerable<T>>().ToArray();

            }

            return scope.ResolveKeyed<IEnumerable<T>>(key).ToArray();

        }


        /// <summary>

        /// Resolve unregistered service

        /// </summary>

        /// <typeparam name="T">Type</typeparam>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual T ResolveUnregistered<T>(ILifetimeScope scope = null) where T : class

        {

            return ResolveUnregistered(typeof(T), scope) as T;

        }


        /// <summary>

        /// Resolve unregistered service

        /// </summary>

        /// <param name="type">Type</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual object ResolveUnregistered(Type type, ILifetimeScope scope = null)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            var constructors = type.GetConstructors();

            foreach (var constructor in constructors)

            {

                try

                {

                    var parameters = constructor.GetParameters();

                    var parameterInstances = new List<object>();

                    foreach (var parameter in parameters)

                    {

                        var service = Resolve(parameter.ParameterType, scope);

                        if (service == null) throw new Exception("Unknown dependency");

                        parameterInstances.Add(service);

                    }

                    return Activator.CreateInstance(type, parameterInstances.ToArray());

                }

                catch (Exception)

                {


                }

            }

            throw new Exception("No constructor  was found that had all the dependencies satisfied.");

        }


        /// <summary>

        /// Try to resolve srevice

        /// </summary>

        /// <param name="serviceType">Type</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <param name="instance">Resolved service</param>

        /// <returns>Value indicating whether service has been successfully resolved</returns>

        public virtual bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            return scope.TryResolve(serviceType, out instance);

        }


        /// <summary>

        /// Check whether some service is registered (can be resolved)

        /// </summary>

        /// <param name="serviceType">Type</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Result</returns>

        public virtual bool IsRegistered(Type serviceType, ILifetimeScope scope = null)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            return scope.IsRegistered(serviceType);

        }


        /// <summary>

        /// Resolve optional

        /// </summary>

        /// <param name="serviceType">Type</param>

        /// <param name="scope">Scope; pass null to automatically resolve the current scope</param>

        /// <returns>Resolved service</returns>

        public virtual object ResolveOptional(Type serviceType, ILifetimeScope scope = null)

        {

            if (scope == null)

            {

                //no scope specified

                scope = Scope();

            }

            return scope.ResolveOptional(serviceType);

        }


        /// <summary>

        /// Get current scope

        /// </summary>

        /// <returns>Scope</returns>

        public virtual ILifetimeScope Scope()

        {

            try

            {

                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)

                return Container.BeginLifetimeScope();

            }

            catch (Exception)

            {

                //we can get an exception here if RequestLifetimeScope is already disposed

                //for example, requested in or after "Application_EndRequest" handler

                //but note that usually it should never happen


                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)

                return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);

            }

        }

    }

使用介绍

<IControllerActivator, ServiceBasedControllerActivator>

特殊场景介绍

通过上面的封装后,我们可以把Controller的注册单独出来

/// <summary>

    /// 

    /// </summary>

    public class ControllerRegistrar : IDependencyRegistrar

    {

        /// <summary>

        /// 

        /// </summary>

        public int Order

        {

            get

            {

                return 0;

            }

        }


        /// <summary>

        /// 

        /// </summary>

        /// <param name="builder"></param>

        /// <param name="listType"></param>

        public void Register(ContainerBuilder builder, List<Type> listType)

        {

            builder.RegisterType(typeof(LogInterceptor));

            //注册Controller,实现属性注入

            var IControllerType = typeof(ControllerBase);

            var arrControllerType = listType.Where(t => IControllerType.IsAssignableFrom(t) && t != IControllerType).ToArray();

            builder.RegisterTypes(arrControllerType).PropertiesAutowired().EnableClassInterceptors();

        }

    }

下面介绍几种特殊使用方式

1.创建实例时给指定参数赋值

builder.RegisterType(typeof(TestDemo)).AsSelf();

  

public class TestDemo

    {

        private readonly string _name;


        private readonly string _sex;


        private readonly int _age;


        public TestDemo(string name, string sex, int age)

        {

            _name = name;

            _age = age;

            _sex = sex;

        }

        public string Sex

        {

            get

            {

                return _sex;

            }

        }


        public string Name

        {

            get

            {

                return _name;

            }

        }


        public int Age

        {

            get

            {

                return _age;

            }

        }

    }

使用示例

var iocManager = app.ApplicationServices.GetService<IIocManager>();

List<Parameter> cparams = new List<Parameter>();

cparams.Add(new NamedParameter("name", "张三"));

cparams.Add(new NamedParameter("sex", "男"));

cparams.Add(new TypedParameter(typeof(int), 2));

var testDemo = iocManager.Resolve<TestDemo>(cparams.ToArray());

Console.WriteLine($"姓名:{testDemo.Name},年龄:{testDemo.Age},性别:{testDemo.Sex}");

 2.对象激活事件

 Autofac暴露五个事件接口供实例的按如下顺序调用

  1. OnRegistered

  2. OnPreparing

  3. OnActivated

  4. OnActivating

  5. OnRelease

 这些事件会在注册的时候被订阅,或者被附加到IComponentRegistration 的时候。

  builder.RegisterType(typeof(TestDemo)).AsSelf()
      .OnRegistered(e => Console.WriteLine("OnRegistered在注册的时候调用!"))
      .OnPreparing(e => Console.WriteLine("OnPreparing在准备创建的时候调用!"))
      .OnActivating(e => Console.WriteLine("OnActivating在创建之前调用!"))
      .OnActivated(e => Console.WriteLine("OnActivated创建之后调用!"))
      .OnRelease(e => Console.WriteLine("OnRelease在释放占用的资源之前调用!"));

可以在这些事件里面做些特殊场景处理

总结

      本篇介绍了Autofac在项目中的使用方式以及几种特殊使用场景。其它未介绍知识如生命周期请参考http://autofac.readthedocs.io/en/latest/getting-started/index.html。

相关文章:

原文地址:http://www.cnblogs.com/yanweidie/p/autofac.html