【问题标题】:How to overwrite HTTP Response Body C#如何覆盖 HTTP 响应主体 C#
【发布时间】:2023-02-24 14:22:32
【问题描述】:

我创建了一个中间件,允许我拦截对我的 API 的每次调用。当请求是 HttpStatus.Ok 或 HttpStatus.BadRequest 时,我的代码总是返回相同类型的响应。 中间件只是“转发”响应而没有任何变化

这是我在所有情况下都拥有并希望拥有的标准回复:

{
"results": 0,
"numberOfRows": 1,
"requestGuid": "xxx",
"errors": [],
"StatusCode": 200,
"environment": "LOC"
}

我的 Api 端点需要通过 Body 获得一些属性。有些属性是强制性的。 例如,如果我通过邮递员发送呼叫并“忘记”强制属性,我会收到来自 api 的标准消息,如下所示:

{
"errors": {
"MyProp": [
"The MyProp field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "xxx"
}

正常消息,但是,这是我想使用我的标准响应来标准化的消息。

这是我的中间件的代码

public async Task InvokeAsync(HttpContext context)
{
try
{

                Stream originalBodyStream = context.Response.Body;
    
                await using (MemoryStream memoryStream = new())
                {
                    context.Response.Body = memoryStream;
    
                    await _next(context);
                    if (context.Response.StatusCode == 400)
                    {
                        //??
                    }
                    else
                    {
                        memoryStream.Seek(0, SeekOrigin.Begin);
                        string responseBodyText = await new StreamReader(memoryStream).ReadToEndAsync();
    
                       // memoryStream.Seek(0, SeekOrigin.Begin);
                        context.Response.Body = originalBodyStream;
                        await context.Response.Body.WriteAsync(memoryStream.ToArray());
    
                    }
    
                }
            }
            catch (Exception exception)
            {
                //todo
            }
        }

else 语句“转发”我创建的响应,但是当我进入 if 语句时我不知道如何发送新主体,“标准”响应是这个对象:

Response\<HttpStatusCode\> errorResponse = new()
{
StatusCode = HttpStatusCode.BadRequest,
Errors = new List\<ErrorsModel\>
{
new()
{
ErrorDetail = "test"
}
}
};

【问题讨论】:

    标签: asp.net-core exception asp.net-web-api


    【解决方案1】:

    else 语句“转发”我创建的响应,但我没有 当我进入 if 语句时知道如何发送一个新的主体, “标准”响应是这个对象

    通常,我们应该有一个全局请求主体变量,我们可以在其中保存所有传入请求的初始请求主体。要绑定新的响应主体,我们需要的只是序列化的 json 数据和一个响应类。如果您的响应类与您的请求类匹配相同的属性定义,那就太好了。

    一旦我们配置了上述步骤,然后根据条件我们可以轻松地覆盖现有的请求主体或编写新的响应主体。让我们看一下实践:

    自定义请求响应类:

    public class ApiCustomRequestResponseClass
            {
                public string? ResponseCode { get; set; }
                public string? OldRequestBody { get; set; }
                public string? ResponseMessage { get; set; }
            }
    

    笔记:我用它来举例。您可以根据您的要求对其进行自定义。

    演示控制器:

        [Route("api/[controller]")]
        [ApiController]
        public class OverrideRequestBodyController : ControllerBase
        {
           
            [HttpPost]
            public IActionResult OverrideRequestBody([FromBody] ApiCustomRequestResponseClass responseClass)
            {
                return Ok(responseClass);
            }
        }
    

    响应体覆盖中间件:

    public class OverrideResponseBodyMiddleware
        {
            private readonly RequestDelegate _next;
            public OverrideResponseBodyMiddleware(RequestDelegate next)
            {
                _next = next;
            }
            public async Task InvokeAsync(HttpContext context)
            {
                var request = context.Request;
                var stream = request.Body;// At the begining it holding original request stream                    
                var originalReader = new StreamReader(stream);
                var originalContent = await originalReader.ReadToEndAsync(); // Reading first request
               
    
                if (context.Response.StatusCode == 200)
                {
                   
                    //My Custom Response Class
                    var overringNewResponse = new ApiCustomRequestResponseClass();
                    overringNewResponse.ResponseCode = "400";
                    overringNewResponse.OldRequestBody = originalContent;
                    overringNewResponse.ResponseMessage = "Here I am overring the request body";
    
                    //converting my custom response class to jsontype
                    var json = JsonConvert.SerializeObject(overringNewResponse);
                    //Modifying existing stream
                    var requestData = Encoding.UTF8.GetBytes(json);
                    stream = new MemoryStream(requestData);
                   
                }
                else {
    
                    //Binding original data as it is
                    var requestData = Encoding.UTF8.GetBytes(originalContent);
                    stream = new MemoryStream(requestData);
                   
                }
               
                //Writing the new response body with  modified steam of custom response
                request.Body = stream;
    
                await _next(context);
            }
    
        }
    

    笔记:出于演示目的,我已经覆盖了 200 个状态条件中的响应主体。请根据您的要求进行修改。

    程序.cs 文件:

    app.UseMiddleware<OverrideResponseBodyMiddleware>();
    

    输出:

    笔记:您可以从我们的official document here.了解更多关于Request and response operations的详情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-22
      • 2014-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-10
      • 2021-10-08
      • 1970-01-01
      相关资源
      最近更新 更多