本文讲解在.Net5 WebApi中使用Autofac作为IOC容器(已在生产环境中使用)
安装Autofac
我是使用Nuget安装两个Autofac:
- install-package Autofac
- install-package Autofac.Extensions.DependencyInjection
创建一个独立模块来实现动态依赖注入(也可以常规使用,我这里只讲解独立模块的依赖注入)
创建一个类,继承Autofac的模块类Module,然后重写父类的Load方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Autofac;
using Levox.Framework.Core.Extensions;
using Levox.Framework.Core.Logger;
using Levox.Framework.Core.Models.Inject;
using Microsoft.AspNetCore.Mvc;
using Module = Autofac.Module;
namespace Levox.Framework.Core.ServiceInject
{
/// <summary>
/// ERP服务依赖注入 LastUpdateDate:2021-03-30 14:04:22.606 Author:Lingbug
/// </summary>
public class ErpServiceInjectModule : Module
{
/// <summary>
/// 自定义注入 LastUpdateDate:2021-03-30 15:13:34.492 Author:Lingbug
/// </summary>
/// <param name="builder"></param>
protected override void Load(ContainerBuilder builder)
{
//读取到所有需要依赖注入的程序集
var assemblys = ServiceInjectUtil.GetLevoxAssemblys().ToArray();
//注入服务
LoadServices(builder, assemblys);
//注入控制器
LoadControllers(builder, assemblys);
}
/// <summary>
/// 注入服务 LastUpdateDate:2021-03-30 14:44:15.803 Author:Lingbug
/// </summary>
/// <param name="builder"></param>
/// <param name="assemblys"></param>
private void LoadServices(ContainerBuilder builder, Assembly[] assemblys)
{
//标识类
var baseType = typeof(IErpApplicationService);
//读取到需要注入的服务类
var appServiceTypes = assemblys.SelectMany(a => a.GetTypes()).Where(r => !r.IsInterface && baseType.IsAssignableFrom(r)).ToList();
//注入记录
var records = new List<Tuple<string, string>>();
foreach (var type in appServiceTypes)
{
//读取服务实现的接口
var iServiceTypes = type.GetInterfaces().ToArray();
//注入类型
string registerTypeStr = null;
if (iServiceTypes.Contains(typeof(IErpTransientApplicationService)))
{
//瞬时注入,且允许循环依赖
builder.RegisterType(type).AsImplementedInterfaces().InstancePerDependency().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
//赋值注入类型
registerTypeStr = "Transient";
}
else if (iServiceTypes.Contains(typeof(IErpScopedApplicationService)))
{
//单次请求注入,且允许循环依赖
builder.RegisterType(type).AsImplementedInterfaces().InstancePerLifetimeScope().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
//赋值注入类型
registerTypeStr = "Scope";
}
else
{
//单例注入,且允许循环依赖
builder.RegisterType(type).AsImplementedInterfaces().SingleInstance().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
//赋值注入类型
registerTypeStr = "Singleton";
}
records.Add(new Tuple<string, string>(type.FullName, registerTypeStr));
}
//记录日志
LoggerTestUtil.SimpleLog($"注入服务接口【count = {records.Count}】:{records.SerializeToJson()}");
}
/// <summary>
/// 注入控制器 LastUpdateDate:2021-03-30 14:48:20.642 Author:Lingbug
/// </summary>
/// <param name="builder"></param>
/// <param name="assemblys"></param>
private void LoadControllers(ContainerBuilder builder, Assembly[] assemblys)
{
//控制器类
var baseControllerType = typeof(ControllerBase);
//注入控制器
builder.RegisterAssemblyTypes(assemblys).Where(r => baseControllerType.IsAssignableFrom(r)).PropertiesAutowired();
}
}
}
修改Program类,使用Autofac容器
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Autofac.Extensions.DependencyInjection;
using Levox.Framework.WebApi.Extensions;
using Levox.Framework.Model.Input;
namespace Levox.NewERP.WebApi
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
//使用Autofac容器
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureErpServices(services =>
{
//一行代码将框架注入到容器
services.AddErpInject(new AddErpInjectOption());
});
webBuilder.UseStartup<Startup>();
});
}
}
在Startup类中添加Autofac启动方法,在该方法中使用刚在自定义模块类,Autofac会自动调用
public void ConfigureContainer(ContainerBuilder builder) => builder.RegisterModule<ErpServiceInjectModule>();
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Levox.Framework.Model.Input;
using Levox.Framework.WebApi.Extensions;
using Autofac;
using Levox.Framework.Core.Logger;
using Levox.Framework.Core.ServiceInject;
namespace Levox.NewERP.WebApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
//一行代码启动日志(注意配置文件路径必须为Config/log.config,且属性改为始终复制)
LoggerInit.Init();
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//一行代码启动框架
app.UseErpConfiguration(env, new UseErpConfigurationOption());
}
/// <summary>
/// 定义此方法,框架自动调用注入所有系统服务 LastUpdateDate:2021-04-01 18:30:41.633 Author:Lingbug
/// </summary>
/// <param name="builder"></param>
public void ConfigureContainer(ContainerBuilder builder) => builder.RegisterModule<ErpServiceInjectModule>();
}
}
开发Autofac工具类,存储容器,在某些场景可以手动解析服务
开发Autofac工具类
using Autofac;
using Microsoft.AspNetCore.Http;
namespace Levox.Framework.Core.ServiceInject
{
/// <summary>
/// Autofac工具类 LastUpdateDate:2021-03-30 15:52:26.527 Author:Lingbug
/// </summary>
public static class ServiceInjectUtil
{
/// <summary>
/// IOC容器 LastUpdateDate:2021-03-30 14:53:31.530 Author:Lingbug
/// </summary>
public static ILifetimeScope Container { get; set; }
/// <summary>
/// 解析服务 LastUpdateDate:2021-03-30 14:53:11.290 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetService<T>() where T : class => Container.Resolve<T>();
/// <summary>
/// 获取服务(此次请求生命周期内) LastUpdateDate:2021-03-30 14:54:02.594 Author:Lingbug
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetScopeService<T>() where T : class
{
//解析请求上下文
var httpContextAccessor = GetService<IHttpContextAccessor>();
//解析服务
var service = httpContextAccessor.HttpContext.RequestServices.GetService(typeof(T));
//返回
return (T)service;
}
}
}
在Startup的Configure方法中拿到Autofac容器,并存储起来供工具类使用
ServiceInjectUtil.Container = app.ApplicationServices.GetAutofacRoot();//获取到容器并存储
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Levox.Framework.Model.Input;
using Levox.Framework.WebApi.Extensions;
using Autofac;
using Levox.Framework.Core.Logger;
using Levox.Framework.Core.ServiceInject;
namespace Levox.NewERP.WebApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
//一行代码启动日志(注意配置文件路径必须为Config/log.config,且属性改为始终复制)
LoggerInit.Init();
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//获取到容器并存储
ServiceInjectUtil.Container = app.ApplicationServices.GetAutofacRoot();
//一行代码启动框架
app.UseErpConfiguration(env, new UseErpConfigurationOption());
}
/// <summary>
/// 定义此方法,框架自动调用注入所有系统服务 LastUpdateDate:2021-04-01 18:30:41.633 Author:Lingbug
/// </summary>
/// <param name="builder"></param>
public void ConfigureContainer(ContainerBuilder builder) => builder.RegisterModule<ErpServiceInjectModule>();
}
}
Autofac核心Api总结
序号 | Api | 说明 |
---|---|---|
1 | builder.RegisterType(type).AsImplementedInterfaces() | 将type注入到它的所有实现类中 |
2 | InstancePerDependency() | 瞬时注入 |
4 | InstancePerLifetimeScope() | 单次请求周期内注入 |
5 | SingleInstance() | 单例注入 |
6 | PropertiesAutowired() | 支持属性注入 |
7 | PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies) | 支持属性注入且允许循环依赖 |
8 | builder.RegisterModule<ErpServiceInjectModule>() | 注入模块 |
9 | public void ConfigureContainer(ContainerBuilder builder) => builder.RegisterModule<ErpServiceInjectModule>(); | Startup定义方法模块注入,供Autofac自动调用 |
10 | ServiceInjectUtil.Container = app.ApplicationServices.GetAutofacRoot(); | Startup中获取Autofac容器,并存储 |
11 | .UseServiceProviderFactory(new AutofacServiceProviderFactory()) | Program使用Autofac |
12 | builder.RegisterAssemblyTypes(assemblys).Where(r => typeof(ControllerBase).IsAssignableFrom(r)).PropertiesAutowired(); | 注入控制器 |