遇到一个挺典型的场景:在 ASP.NET Core 中,动态生成的 API 接口(比如那些继承了 IApplicationService 后自动转换为接口的 Service)在 Swagger 里调用原生 Controller 没问题,但一旦走动态接口,就报 LazyServiceProvider 为 null 的错误。容器用的是 Autofac,所有服务也都注册了,可属性注入偏偏不生效——这问题其实就卡在控制器实例的创建方式上。
先看一眼抽象类 ApplicationService 的代码:它继承了 IApplicationService 和 IDynamicApi,并且通过 [Autowired] 标注了 LazyServiceProvider 属性,意图用属性注入来实现懒加载。下面的 ObjectMapper、CurrentUser、PermissionChecker 也都通过 LazyServiceProvider 来获取,逻辑上没问题。

问题出在哪儿呢?
关键在于 ASP.NET Core 默认的控制器实例化方式。如果不做特殊配置,MVC 框架会直接用 ActivatorUtilities.CreateInstance 来创建控制器,这种方式只支持构造函数注入,根本不认属性注入(比如 [Autowired])。而 Autofac 等第三方容器的属性注入、拦截器等高级功能,只有在控制器实例由 DI 容器创建时才会生效。
解决方法其实就一行配置:
builder.Services.AddControllers()
.AddControllersAsServices(); // 这很重要,确保控制器由DI容器解析

AddControllersAsServices() 的作用很直接:
- 把所有控制器类注册到依赖注入容器中
- 确保控制器实例由 DI 容器创建,而不是由 MVC 框架直接实例化
这样一来,Autofac 就能接管控制器的创建过程,属性注入自然也就生效了。
加与不加的区别
不加 AddControllersAsServices()
- 创建方式:MVC 框架直接使用
ActivatorUtilities.CreateInstance创建控制器实例,只支持构造函数注入,不支持属性注入。 - 生命周期:每个请求都会创建新的控制器实例,生命周期完全由 MVC 框架管理。
- 限制:无法使用 Autofac 等第三方容器的高级功能(如属性注入),也无法自定义控制器的解析过程。
加 AddControllersAsServices()
- 创建方式:控制器实例由 DI 容器创建,支持完整的 DI 功能,包括构造函数注入和属性注入。
- 优势:可以使用第三方容器(如 Autofac)的所有功能,支持属性注入,可以自定义控制器的生命周期,还能在控制器解析前后执行自定义逻辑。
- 生命周期:默认仍然是每个请求创建新实例(Transient),但可以通过注册时指定来改变生命周期(比如改为 Scoped 或 Singleton)。
一句话总结:如果你在动态接口中用了属性注入,并且容器是 Autofac,那 AddControllersAsServices() 就是必须的。少了这一行,属性注入就不会执行,LazyServiceProvider 自然是 null。