AutoFac接管ASP.NET Core DI容器需在builder.Services.Add...前调用UseServiceProviderFactory;注册时须限定命名空间、排除抽象类/接口;不支持IServiceProviderIsService;注意InstancePerLifetimeScope在后台任务中引发ObjectDisposedException。

替换 Program.cs 中的默认 DI 容器
ASP.NET Core 6+ 默认用 Host.CreateDefaultBuilder() 注册了 Microsoft.Extensions.DependencyInjection,AutoFac 要接管它,不能只调用 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) 就完事——这个调用必须在 builder.Services 添加任何服务之前执行,否则会报错 InvalidOperationException: Unable to resolve service for type '...' while attempting to activate '...'。
实操建议:
-
UseServiceProviderFactory必须放在var builder = WebApplication.CreateBuilder(args)之后、builder.Services.Add...之前 - 如果用了
AddControllersAsServices()或AddRazorComponents().AddInteractiveServerRenderMode()等扩展方法,它们内部也会注册服务,所以得确保这些调用都在UseServiceProviderFactory之后 - 常见错误:把
UseServiceProviderFactory放在builder.Build()之后,那已经晚了,容器早就建好了
注册模块时别漏掉 RegisterAssemblyTypes 的筛选条件
直接写 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces() 很容易把第三方库里的类型也扫进来,比如 Newtonsoft.Json 的内部类、Microsoft.Data.SqlClient 的工厂类,轻则注入失败,重则覆盖关键服务(如 IHttpClientFactory)导致运行时异常。
实操建议:
- 显式限定命名空间:
.Where(t => t.Namespace?.StartsWith("MyApp.Domain") == true) - 排除抽象类和接口:
.Where(t => !t.IsAbstract && !t.IsInterface) - 避免重复注册:若已手动
RegisterType,就别再用().As () RegisterAssemblyTypes扫描同一类型,否则 AutoFac 会报ComponentActivatorException
AutofacServiceProviderFactory 不支持 IServiceProviderIsService 的自定义逻辑
原生 DI 允许通过实现 IServiceProviderIsService 来控制“某个类型是否算作可解析的服务”,比如跳过泛型开放类型(IRepository)或标记为 [NotInjectable] 的接口。但 AutofacServiceProviderFactory 在桥接时会忽略这个接口,所有 Register 过的类型都会被当作有效服务暴露给 ASP.NET Core 的 GetService 调用。
实操建议:
- 不要依赖
IServiceProviderIsService做运行时过滤,改用 AutoFac 自身机制:用RegisterConditional+When控制注册时机 - 如果必须按条件跳过某些泛型接口,注册时加
.AsSelf().AsImplementedInterfaces().Except(需配合() Autofac.Extras.AttributeMetadata或自定义IRegistrationSource) - 调试时发现某接口莫名能
GetService成功,先查ContainerBuilder里有没有它被Register过,而不是查IServiceProviderIsService
生命周期不一致会导致 ObjectDisposedException
AutoFac 默认作用域是 InstancePerDependency,而 ASP.NET Core 默认控制器/服务是 Transient,看起来一致。但实际中常有人把仓储类注册成 InstancePerLifetimeScope(即 scoped),却忘了 Web API 的 scope 是 per-request,而后台任务(如 IHostedService)没有 request scope,一用就抛 ObjectDisposedException: Cannot access a disposed object。
实操建议:
- 明确区分场景:Web 请求用
InstancePerLifetimeScope,后台任务用InstancePerDependency或手动创建独立 scope - 避免在
Startup或Program.cs里直接 resolve 服务,尤其不要在builder.Build()后立刻app.Services.GetRequiredService—— 此时 root scope 还没激活() - 检查
IDisposable类型是否被跨 scope 持有:比如把 scoped 的 DbContext 存到静态字段里,下次请求来时它早被释放了
最麻烦的不是配置不对,而是错误发生在异步任务或中间件深处,堆栈里看不到 AutoFac 字样,只看到 ObjectDisposedException —— 遇到这种,先盯住所有 InstancePerLifetimeScope 的注册点,再看它被谁持有了。











