本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的
Autofac相比.NET Core原生的注入方式提供了强大的功能,详细可以查看Autofac官方API
(1)首先看第一个例子 控制台应用(.NET Core)
通过Nuget安装两个包 => Autofac Autofac.Extensions.DependencyInjection
public static class Demo { public interface IAccount { } public interface IMessage { } public interface ITool { } public class Base : IDisposable { public Base() { Console.WriteLine($"{GetType().Name} Created"); } public void Dispose() { Console.WriteLine($"{GetType().Name} Disposed"); } } public class Account : Base, IAccount { } public class Message : Base, IMessage { } public class Tool : Base, ITool { } public static void Run() { //.NET Core 服务集合 var serviceCollection = new ServiceCollection() .AddTransient<IAccount, Account>() .AddTransient<IMessage, Message>(); var containerBuilder = new ContainerBuilder(); //将服务集合添加到Autofac containerBuilder.Populate(serviceCollection); //通过类型注册将服务添加到Autofac containerBuilder.RegisterType().As(); var container = containerBuilder.Build(); IServiceProvider provider = new AutofacServiceProvider(container); Debug.Assert(provider.GetService() is Account); } }
- 可以看到程序中 实例化一个Autofac的ContainerBuilder,通过Populate方法遍历传入的服务集合并添加到Autofac的容器中;
- RegisterType是通过类型注册将服务添加到Autofac的容器,如果RegisterType和Populate调换加载顺序,则Populate会覆盖RegisterType的服务集合;
- ContainerBuilder调用Build方法返回的是IContainer对象,该对象实现了ILifetimeScope接口;
- 在创建AutofacServiceProvider(ILifetimeScope lifetimeScope)返回的是AutofacServiceProvider实现了IServiceProvide,可以和.NET Core 的ServiceProvider一样调用GetService创建服务实例
那么使用Autofac有哪些其它优势?下面看看 属性注入和程序集注入
public static class Demo { public interface IAccount { } public interface IMessage { } public interface ITool { } public interface ITest { public IMessage Message { get; set; } } public class Base { public Base() { Console.WriteLine($"{GetType().Name} Created"); } } public class Account : Base, IAccount { } public class Message : Base, IMessage { } public class Tool : Base, ITool { } public class Test : Base, ITest { public IMessage Message { get; set; } public Test(IAccount account, ITool tool) { Console.WriteLine($"Ctor : Test(IAccount, ITool)"); } } public static void Run() { //.NET Core 服务集合 //var serviceCollection = new ServiceCollection() // .AddTransient<ITool, Tool>(); var containerBuilder = new ContainerBuilder(); //将服务集合添加到Autofac //containerBuilder.Populate(serviceCollection); //属性注入 containerBuilder.RegisterType<Test>().As<ITest>().PropertiesAutowired(); //程序集注入 containerBuilder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .Where(t => t.BaseType == typeof(Base)) .As(t => t.GetInterfaces()[0])//调用As方法,暴露服务 .InstancePerLifetimeScope();//每个生命周期作用域的组件在每个嵌套的生命周期作用域中最多只会有一个单一实例 var container = containerBuilder.Build(); IServiceProvider provider = new AutofacServiceProvider(container); Debug.Assert(provider.GetService<IAccount>() is Account); Debug.Assert(provider.GetService<IMessage>() is Message); Debug.Assert(provider.GetService<ITool>() is Tool); var test = provider.GetService<ITest>(); Debug.Assert(test.Message is Message); }
- 属性注入,<code>containerBuilder.RegisterType<Test>().As<ITest>().PropertiesAutowired()</code> 通过PropertiesAutowired 反射方式
- 程序集注册,获取当前所在程序集Assembly.GetExecutingAssembly(),查找所有基类为Base的Type,调用As暴露服务,InstancePerLifetimeScope 为每个实例创建作用域的生命周期
(2)ASP.NET Core 内置DI 与 Autofac 比较
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddTransient<IAccount, Account>(); }
内置DI 在Startup类 ConfigureServices通过AddTransient方式注册
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }) .UseServiceProviderFactory(new AutofacServiceProviderFactory());
Startup.cs // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //services.AddTransient<IAccount, Account>();//内置DI } public void ConfigContainer(ContainerBuilder containerBuilder) { //containerBuilder.RegisterType<Account>().As<IAccount>(); var assembly = Assembly.GetEntryAssembly(); containerBuilder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .Where(t => t.BaseType == typeof(Base)) .As(t => t.GetInterfaces()[0]) .InstancePerLifetimeScope(); }
Autofac 需要在Program.cs中替换 .NET Core的默认容器 UseServiceProviderFactory(new AutofacServiceProviderFactory())
在 Startup.cs 中 创建ConfigContainer方法,服务注册和 控制台应用相似;
真正在实际项目中按照以上方式注册服务会很麻烦,难以维护,可读性差;Autofac提供了一种以模块化方式进行注册
比如我们有不同的业务模块 AModule BModule...,将这些module继承 Autofac.Module 重写Load方法进行服务注册
最后在ConfigContainer中RegisterModule进行模块化注册
public class AModule : Autofac.Module { protected override void Load(ContainerBuilder builder) { var containerBaseType = typeof(ControllerBase); builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .Where(t => containerBaseType.IsAssignableFrom(t) && t != containerBaseType) .PropertiesAutowired(); } } public void ConfigContainer(ContainerBuilder containerBuilder) { containerBuilder.RegisterModule<AModule>(); }