You need to enable JavaScript to run this app. .NET Framework Web API中Autofac InstancePerRequest同请求返回新实例问题
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework Web API中Autofac InstancePerRequest同请求返回新实例问题

.NET Framework Web API 下 Autofac InstancePerRequest 不生效的修复方案

核心根因

  • Autofac 集成 ASP.NET Web API 的 InstancePerRequest 生命周期,生效的前提是所有解析动作都基于当前 HttpRequestMessage 关联的请求级 LifetimeScope。
  • 你代码里手动调用DependencyResolver.BeginScope()的操作,创建的是和当前HTTP请求完全无绑定的独立顶级scope,每次调用都会生成全新scope,自然每次解析注册为InstancePerRequest的服务时,都会创建新实例。
  • 全局AutofacWebApiDependencyResolver对应的是根容器派生的Resolver,从它开出来的scope都是独立的顶级scope,和Web API框架自动为每个请求创建的请求scope没有任何关联,根本拿不到请求范围内的单例。
  • 你在过滤器中把后续请求处理逻辑包在手动创建的scope内,调用next()进入控制器阶段时,框架会使用自身绑定的请求scope解析控制器依赖,这个scope和你手动创建的scope没有父子关系,两个scope下的InstancePerRequest服务实例完全隔离,自然拿到的不是同一个对象。

代码修正点

1. 自定义过滤器修正

不要手动从全局Resolver开scope,直接从框架传入的HttpActionContext.Request对象上获取当前请求已经绑定好的scope:

public class MyCustomFilter : IAutofacContinuationActionFilter
{
    public async Task<HttpResponseMessage> ExecuteActionFilterAsync(
        HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> next)
    {
        // 直接取当前请求绑定的scope,无需手动创建新scope
        var requestScope = actionContext.Request.GetDependencyScope();
        var hs = (IHomeService)requestScope.GetService(typeof(IHomeService));
        hs.Counter++;
        // 同一scope内重复解析,拿到的是同一个实例
        var sameHs = (IHomeService)requestScope.GetService(typeof(IHomeService));
        sameHs.Counter++;
        
        return await next();
    }
}

2. 控制器代码修正

不要从全局Resolver取scope,直接用ApiController基类自带的Request属性获取当前请求绑定的scope:

[Route("home")]
public class HomeController : ApiController
{
    private readonly IHomeService _injectedHomeService;

    // 构造函数注入的服务,本身就是框架从请求scope解析的实例
    public HomeController(IHomeService homeService)
    {
        _injectedHomeService = homeService;
    }
 
    [HttpGet]
    [Route("")]
    public string Index()
    {
        var requestScope = Request.GetDependencyScope();
        var resolvedHomeService = (IHomeService)requestScope.GetService(typeof(IHomeService));
        resolvedHomeService.Counter++;
        // 此时 _injectedHomeService、resolvedHomeService、过滤器中解析的IHomeService 为同一个实例
        return "Home";
    }
}

3. 独立类链路的通用获取方案

针对无法使用构造函数注入的自动生成代码链路,可封装静态帮助类,从当前请求上下文获取统一的请求scope:

public static class RequestScopeHelper
{
    public static T GetRequestService<T>()
    {
        var currentContext = HttpContext.Current;
        // Web API框架会自动把当前请求的HttpRequestMessage存在HttpContext的Items集合中
        if (currentContext?.Items[typeof(HttpRequestMessage).FullName] is not HttpRequestMessage request)
        {
            throw new InvalidOperationException("当前代码不在Web API请求处理管道内");
        }
        var scope = request.GetDependencyScope();
        return (T)scope.GetService(typeof(T));
    }
}

注意事项

  • 所有需要获取请求级单例的解析动作,都必须从当前HttpRequestMessage绑定的scope出发,不能绕开这个scope手动创建新的独立scope。
  • 该实现效果和.NET Core 中注册Scoped生命周期服务的行为完全一致:同一请求内,无论在哪一层代码解析,拿到的都是同一个实例;请求结束后,scope会被自动释放,服务实例也会被回收。

内容的提问来源于stack exchange,提问作者g3v

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.11 23:45:03