【发布时间】:2021-03-12 16:17:51
【问题描述】:
所以我们有一个中间件,它获取我们 API 响应的响应主体并将其包装在“数据”属性下的 ApiResult 类中。
namespace Web.Api.ApiResult
{
public class ApiResultMiddleware
{
private readonly RequestDelegate next;
public ApiResultMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
var originalBody = context.Response.Body;
var responseBody = string.Empty;
try
{
CsWebException exception = null;
using (var stream = new MemoryStream())
{
context.Response.Body = stream;
try
{
await next.Invoke(context);
}
catch (CsWebException e)
{
exception = e;
}
stream.Position = 0;
responseBody = new StreamReader(stream).ReadToEnd();
}
object result = null;
if (exception != null)
{
result = new ApiResultResponse(null)
{
ErrorCode = exception.ErrorCode,
ErrorData = exception.ErrorData,
};
context.Response.StatusCode = (int)ApiResultHttpStatusCodeConverter.ConvertToHttpStatusCode(exception.ErrorCode);
}
else
{
var data = JsonConvert.DeserializeObject(responseBody);
result = new ApiResultResponse(data);
}
var buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(
result,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }));
if (context.Response.StatusCode != StatusCodes.Status204NoContent)
{
using (var output = new MemoryStream(buffer))
{
var test = JsonConvert.DeserializeObject<ApiResultResponse>(new StreamReader(output).ReadToEnd());
await output.CopyToAsync(originalBody);
}
}
}
catch (JsonReaderException)
{
var result = new ApiResultResponse(responseBody);
var buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(
result,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }));
using (var output = new MemoryStream(buffer))
{
await output.CopyToAsync(originalBody);
}
}
finally
{
context.Response.Body = originalBody;
}
}
}
public static class ApiResultMiddlewareExtensions
{
public static IApplicationBuilder UseApiResultMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ApiResultMiddleware>();
}
}
}
它在 .NET core 2.2 中运行良好,甚至在迁移到 3.1 并使用 Sytem.Text.Json 中的构建之后,但因为我们在补丁端点中需要 newtonsoft。通过添加它
services.AddControllers().AddNewtonsoftJson();
返回的 JSON 在中间某处被剪切。我在编写它之前添加了测试变量并反序列化了 JSON,它看起来很好,但是在我们的前端解析 i 时它不是。
一个例子是写入正文的 jsonbeeing 如下所示:
"{\"errorCode\":0,\"errorData\":null,\"data\":{\"previousWorkingDayWorkOrders\":[],\"nextWorkingDayWorkOrders\":[],\"todaysWorkOrders\":[],\"nonInvoicedWorkOrders\":[{\"workOrderId\":1232753.0,\"employeeNumber\":5000000037.0,\"employeeName\":\"VERKADM, VERKADM\",\"vehicleRegistrationNumber\":\"PXG948\",\"dealerOrderNumber\":null,\"bookingNumber\":null,\"preplannedDate\":null,\"workOrderStatus\":7,\"shortageIndicator\":true,\"customerWaiting\":false,\"vehicleDescriptionShort\":\"Volvo V40 Cross Country\",\"vehicleModelYear\":2018,\"colorDescription\":\"Blå\",\"fuelDescription\":\"Diesel\",\"email\":null,\"customer\":{\"customerNumber\":null,\"name\":\"Volvo Bil I Göteborg AB\",\"telephone\":null,\"email\":null,\"customerType\":1},\"mainPayerCustomerType\":1,\"notes\":null,\"vehicleIdentificationNumber\":\"YV1MZ79L0J2139968\"}],\"webWorkOrders\":[]}}"
当在邮递员中收到相同的响应时,它无法解析为 json,因为它被切断了,在计划文本中它看起来像:
{"errorCode":0,"errorData":null,"data":{"previousWorkingDayWorkOrders":[],"nextWorkingDayWorkOrders":[],"todaysWorkOrders":[{"workOrderId":1229253.0,"employeeNumber":5000000037.0,"employeeName":"VERKADM, VERKADM","vehicleRegistrationNumber":"PXG948","dealerOrderNumber":null,"bookingNumber":"349","preplannedDate":"2020-02-06T07:00:00","workOrderStatus":5,"shortageIndicator":true,"customerWaiting":false,"vehicleDescriptionShort":"Volvo V40 Cross Country","vehicleModelYear":2018,"colorDescription":"Blå","fuelDescription":"Diesel","email":null,"customer":{"customerNumber":null,"name":"Volvo Bil I Göteborg AB","telephone":null,"email":null,"customerType":1},"mainPayerCustomerType":1,"notes":null,"vehicleIdentificationNumber":"YV1MZ79L0J2139968"}],"nonInvoicedWorkOrders":[{"workOrderId":1232753.0,"employeeNumber":5000000037.0,"employeeName":"VERKADM, VERKADM","vehicleRegistrationNumber":"PXG948","dealerOrderNumber":null,"bookingNumber":null,"preplannedDate":null,"workOrderStatus":7,"shortageIndicator":true,"customerWaiting":false,"vehicleDescriptionShort":"Volvo V40 Cross Country","vehicleModelYear":2018,"colorDescription":"Blå","fuelDescription":"Diesel","email":null,"customer":{"customerNumber":null,"name":"Volvo Bil I Göteborg AB","telephone":null,"email":null,"customerType":1},"mainPayerCustomerType":1,"notes":null,"vehicleIdentificationNumber":"Y
知道为什么这不起作用吗?
编辑:我还应该指出,通过删除中间件 app.UseApiResultMiddleware();
一切正常,但我们仍然想包装我们的回复
编辑 2。感谢 dbc 的回复,我设法解决了这个问题。通过将响应内容的长度设置为缓冲区的长度,它可以完美地工作。
context.Response.ContentLength = buffer.Length;
让我感到困惑的是,在没有使用 System.Text.Json 设置长度以及我们使用 .Net core 2.2 时,这一事实仍然有效
【问题讨论】:
-
欢迎您!您是否尝试过刷新响应流?
-
谢谢。我试过冲洗它,但这似乎不是问题。
-
只是一个简短的说明,你知道
{{}}作为json无效吗? -
您的 json 无效
-
对不起,我贴出来的json其实是代码中test变量中解析出来的实际json到匿名对象的解析值。我更新为使用序列化的 json 发布