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

Azure App Service部署.NET7 Web API出现序列化失败的间歇性500错误

解决方案:Azure App Service上.NET7 Web API调用Cosmos DB偶发500错误

问题根源

这个System.NotSupportedException是因为Cosmos DB操作偶尔抛出异常(比如网络波动、限流、超时等),未被正确捕获处理时,ASP.NET Core框架会尝试自动序列化完整的Exception对象返回,而Exception.TargetSite是MethodBase类型,System.Text.Json不支持序列化该类型,最终导致500错误。本地测试没出现是因为本地环境下Cosmos DB操作基本无异常,或者异常被调试器捕获了。

具体解决步骤

1. 主动捕获Cosmos DB操作异常,返回可控响应

在所有调用Cosmos DB的代码层(比如Repository服务类)添加try-catch,捕获Cosmos专属异常和通用异常,返回明确的HTTP响应,避免异常冒泡到框架层触发默认序列化:

public async Task<MyEntity> GetEntityAsync(string id)
{
    try
    {
        var response = await _container.ReadItemAsync<MyEntity>(id, new PartitionKey(id));
        return response.Resource;
    }
    catch (CosmosException ex)
    {
        // 根据Cosmos返回的状态码,返回对应HTTP状态
        if (ex.StatusCode == HttpStatusCode.NotFound)
            throw new KeyNotFoundException("实体不存在");
        if (ex.StatusCode == HttpStatusCode.TooManyRequests)
            throw new HttpRequestException("请求过于频繁,请稍后再试", null, HttpStatusCode.TooManyRequests);
        // 其他Cosmos异常抛出自定义错误
        throw new ApplicationException("数据操作失败", ex);
    }
    catch (Exception ex)
    {
        // 兜底处理,不要抛出原始Exception对象
        throw new ApplicationException("服务器内部错误", ex);
    }
}

同时在全局异常处理中间件里捕获这些自定义异常,返回友好的JSON响应,而不是让框架序列化完整异常:

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.ContentType = "application/json";
        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
        var exception = exceptionHandlerPathFeature?.Error;

        var statusCode = exception switch
        {
            KeyNotFoundException => StatusCodes.Status404NotFound,
            HttpRequestException reqEx => (int)reqEx.StatusCode!,
            _ => StatusCodes.Status500InternalServerError
        };

        context.Response.StatusCode = statusCode;
        await context.Response.WriteAsJsonAsync(new
        {
            Message = exception.Message,
            StatusCode = statusCode
        });
    });
});

2. 配置Json序列化规则,禁止序列化异常的TargetSite属性

如果不想逐个捕获异常,可以通过全局配置System.Text.Json,移除Exception对象中TargetSite属性的序列化:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.TypeInfoResolverChain.Insert(0, new DefaultJsonTypeInfoResolver
        {
            Modifiers = { typeInfo =>
                {
                    if (typeof(Exception).IsAssignableFrom(typeInfo.Type))
                    {
                        var targetSiteProp = typeInfo.Properties.FirstOrDefault(p => p.Name == nameof(Exception.TargetSite));
                        if (targetSiteProp != null)
                        {
                            typeInfo.Properties.Remove(targetSiteProp);
                        }
                        // 也可以移除其他不需要序列化的异常属性,比如StackTrace、InnerException等
                    }
                }
            }
        });
    });

3. 优化Cosmos DB客户端配置,减少异常触发概率

针对Cosmos DB的限流、超时等常见偶发异常,优化客户端配置:

// 配置Cosmos客户端时增加重试次数和等待时间,应对限流
var cosmosClient = new CosmosClient(
    builder.Configuration["CosmosDB:ConnectionString"],
    new CosmosClientOptions
    {
        MaxRetryAttemptsOnRateLimitedRequests = 5,
        MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(30),
        RequestTimeout = TimeSpan.FromSeconds(10)
    });
builder.Services.AddSingleton(cosmosClient);

同时可以在Azure门户查看Cosmos DB的监控指标(比如"请求速率"、"限流次数"、"延迟"),确认是否需要调整容器的吞吐量,避免频繁触发限流。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 04:13:17