带有自定义响应包装器的 ASP.NET Core 3.1 Web API 中的 JSON 响应中断

fin*_*s10 1 c# serialization json asp.net-core-webapi asp.net-core-3.1

我正在开发一个 ASP.NET 2.2 Web API 项目,该项目使用包装器来生成一致的响应。经过一番搜索,我发现团队遵循了文章“管理异常和一致响应的自定义包装器”中的实现。

这按预期工作。现在我们计划升级到 ASP.NET Core 3.1。升级后,这不能按预期工作。我认为这是由于 ASP.NET Core 2.2 和 3.1 之间的重大变化。我按照 Microsoft 的Migrate from ASP.NET Core 2.2 to 3.0指南修复了所有这些问题。

现在我来自 API 的 JSON 响应中断了。

这是响应成功时执行的代码:

private static Task HandleSuccessRequestAsync(HttpContext context, object body, int code)  
{  
    context.Response.ContentType = "application/json";  
    string jsonString, bodyText = string.Empty;  
    APIResponse apiResponse = null;  


    if (!body.ToString().IsValidJson())  
        bodyText = JsonConvert.SerializeObject(body);  
    else  
        bodyText = body.ToString();  

    dynamic bodyContent = JsonConvert.DeserializeObject<dynamic>(bodyText);  
    Type type;  

    type = bodyContent?.GetType();  

    if (type.Equals(typeof(Newtonsoft.Json.Linq.JObject)))  
    {  
        apiResponse = JsonConvert.DeserializeObject<APIResponse>(bodyText);  
        if (apiResponse.StatusCode != code)  
            jsonString = JsonConvert.SerializeObject(apiResponse);  
        else if (apiResponse.Result != null)  
            jsonString = JsonConvert.SerializeObject(apiResponse);  
        else  
        {  
            apiResponse = new APIResponse(code, ResponseMessageEnum.Success.GetDescription(), bodyContent, null);  
            jsonString = JsonConvert.SerializeObject(apiResponse);  
        }  
    }  
    else  
    {  
        apiResponse = new APIResponse(code, ResponseMessageEnum.Success.GetDescription(), bodyContent, null);  
        jsonString = JsonConvert.SerializeObject(apiResponse);  
    }  

    return context.Response.WriteAsync(jsonString);  
}  
Run Code Online (Sandbox Code Playgroud)

我调试,直到它击中方法return context.Response.WriteAsync(jsonString);内部HandleSuccessRequestAsync()。一切安好。但是 JSON 响应中断了。

预期回应:

{  
    "Version": "1.0.0.0",  
    "StatusCode": 200,  
    "Message": "Request successful.",  
    "Result": [  
        "value1",  
        "value2"  
    ]  
}  
Run Code Online (Sandbox Code Playgroud)

实际反应:

{  
    "Version": "1.0.0.0",  
    "StatusCode": 200,  
    "Message": "Request successful.",  
    "Result":   
Run Code Online (Sandbox Code Playgroud)

请帮我看看我哪里出错了?这是因为 ASP.NET Core 3.1 升级了吗?

小智 5

我们在使用自定义中间件更改响应正文的应用程序中遇到了同样的问题。此页面很有帮助:

ASP.NET Core 3.x 中响应重写的内容注入

只要在将更改后的正文写入响应之前将 ContentLength 更改为 null,我们就不必像上述页面中那样为 HttpResponse.Body 创建包装器。了解当控制器操作返回其值并写入响应正文时 ASP.NET Core 2.2 未设置 ContentLength 时,ASP.NET Core 3.1 确实设置了 ContentLength 是有帮助的。结果,当我们更改响应正文时,内容变得比设置的 ContentLength 长。

我们有代码在等待控制器操作之前用内存字符串替换响应主体。这是为了能够捕获来自任何控制器方法的响应。然后响应被改变,原始流恢复到响应对象。然后将更改后的响应写入到正文中,原始流就位。

发生的事情是当中间件等待控制器响应时,响应设置了 ContentLength。然后,当我们编写更改后的响应正文时,ContentLength 并未更新。所以接收到的json字符串被截断了。我们能够将 ContentLength 更改为更改内容的长度(或使用 null,两者都有效),如果我们将更改的正文写入响应之前更改长度。