Azure Functions隔离模式下Scoped服务依赖注入异常咨询
问题原因
Azure Functions隔离模式里,IFunctionsWorkerMiddleware的实例是单例生命周期——宿主启动时就会初始化所有中间件,构造函数里注入的服务会从根服务容器解析。而根容器不支持Scoped作用域,这里的Scoped服务会被当成Transient处理,每次解析都新建实例。
而你的函数类是在每次请求的独立作用域里被解析的,这里的Service1才是真正的Scoped实例。两边的实例来源不同,自然会出现每次请求创建两个Service1的情况。
另外你的中间件代码还有个小bug:构造函数里的service1 = service1;是无效赋值,应该是_service1 = service1;,不过这不会影响实例数量,但会导致中间件里的_service1始终为null。
修复方案
核心思路是:不在中间件构造函数注入Scoped服务,而是在请求执行时从当前作用域获取。
修改后的TestMiddleware代码
public class TestMiddleware : IFunctionsWorkerMiddleware { public TestMiddleware() { Console.WriteLine("TestMiddleware constructor"); } public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { // 从当前请求的作用域中获取Scoped的Service1实例 var service1 = context.InstanceServices.GetRequiredService<Service1>(); // 这里可以使用service1做逻辑处理 await next(context); } }
其他代码保持不变
- Service1类无需修改;
- Program.cs里的
services.AddScoped<Service1>();注册保留; - TestFunction的构造函数注入Service1的逻辑也不用改。
这样调整后,每次请求只会创建一个Service1实例,中间件和函数会复用同一个实例,符合Scoped服务的预期行为。
关键注意事项
在Azure Functions隔离模式中,所有中间件默认都是单例注册的,所以绝对不能在中间件构造函数中注入Scoped或Transient服务——这会让服务被绑定到根容器的生命周期,完全失去Scoped的特性。正确的做法是在Invoke方法里通过FunctionContext.InstanceServices获取当前请求作用域内的服务。
内容的提问来源于stack exchange,提问作者Kadir Alan
相关产品推荐
相关产品推荐

