You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET5下Json自定义ContractResolver的ShouldSerialize谓词内获取请求查询字符串问题

问题根因

你遇到的ObjectDisposedException本质不是IHttpContextAccessor注入错误,而是你在CreateProperties方法执行时就提前捕获了当时的Request对象存入闭包:CreateProperties仅会在对应类型首次序列化时执行一次,闭包中存储的是第一次请求的Request实例,后续该实例被回收释放,再次调用就会抛出已释放异常。

低开销解决方案

不需要每次请求重建合约,仅需调整两处逻辑即可,整体额外开销几乎可以忽略:

1. 调整ShouldSerialize的上下文获取时机

将HttpContext的访问逻辑推迟到ShouldSerialize委托执行时触发,该委托每次序列化属性时都会执行,此时拿到的永远是当前请求的上下文实例,不会缓存旧对象。

protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
    var properties = base.CreateProperties(type, memberSerialization);
    foreach (var property in properties)
    {
        // 不要提前捕获HttpContext/Request实例
        property.ShouldSerialize = p =>
        {
            // 委托执行时才取当前请求的上下文
            var currentContext = _httpContextAccessor.HttpContext;
            // 非请求场景(后台任务、单元测试等)下的兜底逻辑
            if (currentContext == null)
            {
                return true;
            }
            var targetQueryValue = currentContext.Request.Query["你的查询参数名"];
            // 原有判断逻辑,返回是否序列化该属性
            return /* 你的业务判断结果 */;
        };
    }
    return properties;
}

2. 修正注册逻辑,避免手动构建根容器

你原来在配置委托中调用services.BuildServiceProvider()是错误实践,会生成和应用运行容器隔离的冗余容器,改为通过PostConfigure从应用根容器获取服务即可:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpContextAccessor();
    // 注册自定义合约解析器
    services.AddSingleton<MyContractResolver>();

    services.AddControllers()
        .AddNewtonsoftJson();
    
    // 配置NewtonsoftJson选项,从容器获取依赖
    services.PostConfigure<MvcNewtonsoftJsonOptions>((sp, opt) =>
    {
        opt.SerializerSettings.ContractResolver = sp.GetRequiredService<MyContractResolver>();
    });
}
方案优势
  • CreateProperties仍仅会在每个类型首次序列化时执行一次,无重复创建合约的额外开销
  • ShouldSerialize中访问HttpContext是从AsyncLocal存储中读取当前上下文,属于轻量操作,性能损耗极低
  • 天然兼容后续请求参数变化的场景,每次执行都会读取最新的查询字符串

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:06:03