博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.net core2.0下Ioc容器Autofac使用
阅读量:6968 次
发布时间:2019-06-27

本文共 19346 字,大约阅读时间需要 64 分钟。

  .net core发布有一段时间了,最近两个月开始使用.net core2.0开发项目,大大小小遇到了一些问题。准备写个系列介绍一下是如何解决这些问题以及对应技术。先从IOC容器Autofac开始该系列。

阅读目录

Autofac基本使用

  Autofac是一款轻量级的IOC框架,使用率上还是挺高的,官方网站,源码下载地址。

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

public interface IDog    {        ///         /// 品种        ///         string Breed { get; }        ///         /// 名称        ///         string Name { get; }    }    ///     /// 萨摩耶    ///     public class Samoyed : IDog    {        ///         /// 品种        ///         public string Breed        {            get            {                return "Samoyed(萨摩耶)";            }        }        ///         /// 名称        ///         public string Name        {            get            {                return "小黄";            }        }    }    ///     /// 藏獒    ///     public class TibetanMastiff : IDog    {        ///         /// 品种        ///         public string Breed        {            get            {                return "Mastiff Class(獒犬类)";            }        }        ///         /// 名称        ///         public string Name        {            get            {                return "小黑";            }        }    }
View Code

  1.RegisterType 

public static void Register(){    var builder = new ContainerBuilder();    //注册Samoyed指定为IDog实现    builder.RegisterType
().As
(); builder.RegisterType
().As
(); using (var container = builder.Build()) { var dogs = container.Resolve
>(); 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
>(); foreach (var dog in dogs) { Console.WriteLine($"名称:{dog.Name},品种:{dog.Breed}"); } }}

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

  3.RegisterInstance

TibetanMastiff d = new TibetanMastiff();builder.RegisterInstance(d).As
();

  4.RegisterModule

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

      

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

 

.net core MVC与Autofac

  1.首先nuget下载Autofac和Autofac.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
dogs; public ValuesController(IEnumerable
_dogs) { dogs = _dogs; } // GET api/values [HttpGet] public IEnumerable
Get() { List
list = new List
(); 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
());services.AddMvc();
注意:Replace代码放在AddMvc之前
Replace代码的意思:使用ServiceBasedControllerActivator替换DefaultControllerActivator(意味着框架现在会尝试从IServiceProvider中解析控制器实例,也就是return new AutofacServiceProvider(Container);
3.使用属性注入
[Route("api/[controller]")]    public class ValuesController : Controller    {        public IEnumerable
dogs { get; set; } [HttpGet] public IEnumerable
Get() { List
list = new List
(); 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
(); 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 接口的对象进行类型注册

///     /// 单例接口    ///     public interface ISingletonDependency    {    }
///     /// 所有接口的依赖接口,每次创建新实例    ///     /// 
/// 用于Autofac自动注册时,查找所有依赖该接口的实现。 /// 实现自动注册功能 ///
public interface ITransientDependency { }

 

///     /// 依赖注册接口    ///     public interface IDependencyRegistrar    {        ///         /// Register services and interfaces        ///         /// Container builder        /// Config        void Register(ContainerBuilder builder,List
listType); ///
/// Order of this dependency registrar implementation /// 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
(string key = "", ILifetimeScope scope = null) where T : class; T Resolve
(params Parameter[] parameters) where T : class; T[] ResolveAll
(string key = "", ILifetimeScope scope = null); object ResolveOptional(Type serviceType, ILifetimeScope scope = null); object ResolveUnregistered(Type type, ILifetimeScope scope = null); T ResolveUnregistered
(ILifetimeScope scope = null) where T : class; ILifetimeScope Scope(); bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance); }
///     /// Container manager    ///     public class IocManager : IIocManager    {        private IContainer _container;        public static IocManager Instance { get { return SingletonInstance; } }        private static readonly IocManager SingletonInstance = new IocManager();        ///         /// Ioc容器初始化        ///         ///         /// 
public IServiceProvider Initialize(IServiceCollection services) { var builder = new ContainerBuilder(); builder.RegisterInstance(Instance).As
().SingleInstance(); //所有程序集 和程序集下类型 var deps = DependencyContext.Default; var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package");//排除所有的系统程序集、Nuget下载包 var listAllType = new List
(); 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
(); 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); } ///
/// Gets a container /// public virtual IContainer Container { get { return _container; } } ///
/// Resolve /// ///
Type
///
key ///
Scope; pass null to automatically resolve the current scope ///
Resolved service
public virtual T Resolve
(string key = "", ILifetimeScope scope = null) where T : class { if (scope == null) { //no scope specified scope = Scope(); } if (string.IsNullOrEmpty(key)) { return scope.Resolve
(); } return scope.ResolveKeyed
(key); } ///
/// Resolve /// ///
Type
///
key ///
Scope; pass null to automatically resolve the current scope ///
Resolved service
public virtual T Resolve
(params Parameter[] parameters) where T : class { var scope = Scope(); return scope.Resolve
(parameters); } ///
/// Resolve /// ///
Type ///
Scope; pass null to automatically resolve the current scope ///
Resolved service
public virtual object Resolve(Type type, ILifetimeScope scope = null) { if (scope == null) { //no scope specified scope = Scope(); } return scope.Resolve(type); } ///
/// Resolve all /// ///
Type
///
key ///
Scope; pass null to automatically resolve the current scope ///
Resolved services
public virtual T[] ResolveAll
(string key = "", ILifetimeScope scope = null) { if (scope == null) { //no scope specified scope = Scope(); } if (string.IsNullOrEmpty(key)) { return scope.Resolve
>().ToArray(); } return scope.ResolveKeyed
>(key).ToArray(); } ///
/// Resolve unregistered service /// ///
Type
///
Scope; pass null to automatically resolve the current scope ///
Resolved service
public virtual T ResolveUnregistered
(ILifetimeScope scope = null) where T : class { return ResolveUnregistered(typeof(T), scope) as T; } ///
/// Resolve unregistered service /// ///
Type ///
Scope; pass null to automatically resolve the current scope ///
Resolved service
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
(); 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."); } /// /// Try to resolve srevice /// /// Type /// Scope; pass null to automatically resolve the current scope /// Resolved service ///
Value indicating whether service has been successfully resolved
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); } /// /// Check whether some service is registered (can be resolved) /// /// Type /// Scope; pass null to automatically resolve the current scope ///
Result
public virtual bool IsRegistered(Type serviceType, ILifetimeScope scope = null) { if (scope == null) { //no scope specified scope = Scope(); } return scope.IsRegistered(serviceType); } /// /// Resolve optional /// /// Type /// Scope; pass null to automatically resolve the current scope ///
Resolved service
public virtual object ResolveOptional(Type serviceType, ILifetimeScope scope = null) { if (scope == null) { //no scope specified scope = Scope(); } return scope.ResolveOptional(serviceType); } /// /// Get current scope /// ///
Scope
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); } } }
使用介绍
public IServiceProvider ConfigureServices(IServiceCollection services)        {            services.Replace(ServiceDescriptor.Transient
()); services.AddMvc(); return IocManager.Instance.Initialize(services); }

特殊场景介绍

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

///     ///     ///     public class ControllerRegistrar : IDependencyRegistrar    {        ///         ///         ///         public int Order        {            get            {                return 0;            }        }        ///         ///         ///         ///         ///         public void Register(ContainerBuilder builder, List
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
();List
cparams = new List
();cparams.Add(new NamedParameter("name", "张三"));cparams.Add(new NamedParameter("sex", "男"));cparams.Add(new TypedParameter(typeof(int), 2));var testDemo = iocManager.Resolve
(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在项目中的使用方式以及几种特殊使用场景。其它未介绍知识如生命周期请参考。

  下面给出本文示例代码:

转载于:https://www.cnblogs.com/yanweidie/p/autofac.html

你可能感兴趣的文章
前端概述及网页入门
查看>>
Java Servlet web.xml 配置详解
查看>>
javascript mvc 代码
查看>>
七牛镜像存储使用手册
查看>>
iOS学习笔记之 Objective-C (二)
查看>>
eclipse提交项目到github
查看>>
小米正式开源 Istio 管理面板 Naftis
查看>>
小白们不要慌,这里为你提供免费靠谱的python学习流程图
查看>>
利用种子文件对windows7的攻击-学习笔记
查看>>
微信小程序中异步处理终极方案async/await
查看>>
Java 面向对象 之 方法的覆盖
查看>>
开发者应该了解Kubernetes对于程序的影响点
查看>>
[Spark]Spark Streaming 指南三 DStreams
查看>>
LeetCode 14 Longest Common Prefix(最长公共前缀)(String)
查看>>
关注 | 《财富》发布“改变世界”企业 阿里巴巴因农村战略位列中国第一
查看>>
[Hadoop]Hadoop本地调试
查看>>
DNS服务-主从架构搭建
查看>>
找油网获1.5亿美元融资:Rainbow Capital领投C1轮,普洛斯领投C2轮
查看>>
2017.10.1 AJAX技术对RESTful的前端实现
查看>>
流程控制(逻辑词汇)
查看>>