JSON response breaks in ASP.NET Core 3.1 Web API with custom response wrapper

Viewed 2354

I'm working on an ASP.NET 2.2 Web API project which uses a wrapper for producing consistent responses. After some searching, I found that the team followed the implementation from the article, “A Custom Wrapper For Managing Exceptions And Consistent Responses”.

This works as expected. Now we are planning to upgrade to ASP.NET Core 3.1. After upgrading, this doesn't work as expected. I think it was due to breaking changes between ASP.NET Core 2.2 and 3.1. I fixed all these following Microsoft’s Migrate from ASP.NET Core 2.2 to 3.0 guide.

Now my JSON response from the API breaks.

Here is the code that gets executed when the response is successful:

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);  
}  

I debugged until it hit the return context.Response.WriteAsync(jsonString); inside the HandleSuccessRequestAsync() method. Everything is fine. But the JSON response breaks.

Expected Response:

{  
    "Version": "1.0.0.0",  
    "StatusCode": 200,  
    "Message": "Request successful.",  
    "Result": [  
        "value1",  
        "value2"  
    ]  
}  

Actual Response:

{  
    "Version": "1.0.0.0",  
    "StatusCode": 200,  
    "Message": "Request successful.",  
    "Result":   

Please assist me on where I'm going wrong? Is this because of theASP.NET Core 3.1 upgrade?

1 Answers

We were having this same problem in an application where we use custom middleware to change the response body. This page was helpful:

Content Injection with Response Rewriting in ASP.NET Core 3.x

We didn't have to create a wrapper like in the above page for the HttpResponse.Body as long as we changed the ContentLength to null before writing our altered body to the Response. It was helpful though to learn what while ASP.NET Core 2.2 does not set ContentLength when the controller action returns its value and the response body is written, ASP.NET Core 3.1 does set the ContentLength. As a result, when we altered the response body, the content became longer than the set ContentLength.

We have code that replaces the response body with a memory string before the controller action is awaited. This is to be able to capture the response from any controller method. Then the response was altered and the original stream restored to the response object. Then the altered response was written to the body with its original stream in place.

What was happening was that when the middleware awaited the controller response, the response set the ContentLength. Then, when we wrote the altered response body, that ContentLength was not updated. So the received json string was truncated. We were able to change ContentLength to the length of the altered content (or use null, both worked), IF we change the length before writing the altered body to the response.

Related