簡體   English   中英

如何在 .NET 核心 5 Web ZDB974238714CA8DE634A7CE1D083A1 項目中自動格式化 API 響應?

[英]How to autoformat API response in .NET core 5 Web API project?

我有一個帶有格式化響應的 API,如下所示 JSON:

{
    "statusCode": 200,
    "totalRecord": 2,
    "message": "Succesfully get merchants",
    "data": [
        {
            "id": 1,
            "name": "Leo Shop",
            "address": "Flower Street 9A",
            "isComplete": false,
            "createdAt": "2021-05-30T14:16:27.654233",
            "updatedAt": "2021-05-30T14:16:28.515476"
        },
        {
            "id": 3,
            "name": "Test Shop",
            "address": "Playing Street 12A",
            "isComplete": false,
            "createdAt": "2021-05-30T14:16:27.654233",
            "updatedAt": "2021-05-30T14:16:28.515476"
        }
    ]
}

這些響應背后的代碼如下所示:

[HttpGet]
public async Task<ActionResult<IEnumerable<Merchant>>> GetMerchants()
{
    var data = await _context.Merchants.ToListAsync();
    ApiResponse res = new ApiResponse{StatusCode = 200, Message = "Succesfully get merchants", TotalRecord = data.Count, Data = data}; // Focus on this line
    return Ok(res);
}

我的問題,如何自動將默認響應轉換為ApiResponse model 而無需在每個 controller 內的每個操作返回時重復編寫new ApiResponse() model?

希望任何人都可以幫助我..提前謝謝你們

您可以在 MVC 過濾器管道中使用結果過濾器

MVC 過濾器管道

所以改變你的 controller 看起來像這樣

[HttpGet]
public Task<List<Merchant>> GetMerchants()
{
   return _context.Merchants.ToListAsync();
}

添加新的 class,名為 ResultManipulator.cs

  public class ResultManipulator : IResultFilter
        {
            public void OnResultExecuted(ResultExecutedContext context)
            {
                // do nothing
            }
    
            public void OnResultExecuting(ResultExecutingContext context)
            {
                //run code immediately before and after the execution of action results. They run only when the action method has executed successfully. They are useful for logic that must surround view or formatter execution.
                var result = context.Result as ObjectResult;
                var resultObj = result.Value;

    //change this ResultApi with your ApiResponse class
                var resp = new ResultApi
                {
                    Path = context.HttpContext.Request.Path.HasValue ? context.HttpContext.Request.Path.Value : "",
                    Method = context.HttpContext.Request.Method
                };
    
                if (resultObj is not null && resultObj is not Unit)
                    resp.Payload = resultObj;
    
//you can also change this from System.Text.Json to newtonsoft if you use newtonsoft
                context.Result = new JsonResult(resp, new JsonSerializerOptions()
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
                    Converters = { new JsonStringEnumConverter() }
                });
            }
        }

並且不要忘記在 Startup 中添加 ResultManipulator class

services.AddControllers(options =>
            {
                options.Filters.Add(new ResultManipulator());
            })

我希望它能解決你的問題

試試這個作為中間件解決方案。 它將改變響應。

public class YourResponseMiddleware
    {
        private readonly RequestDelegate _next;    
        public YourResponseMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            var existingBody = context.Response.Body;
            using (var newBody = new MemoryStream())
            {
                context.Response.Body = newBody;
                await _next(context);
                var newResponse = await FormatResponse(context.Response);
                context.Response.Body = new MemoryStream();
                newBody.Seek(0, SeekOrigin.Begin);
                context.Response.Body = existingBody;
                var newContent = new StreamReader(newBody).ReadToEnd();
             
                // Send modified content to the response body.
                //
                await context.Response.WriteAsync(newResponse);
            }
        }
    

        private async Task<string> FormatResponse(HttpResponse response)
        {
            //We need to read the response stream from the beginning...and copy it into a string...I'D LIKE TO SEE A BETTER WAY TO DO THIS
            //
            response.Body.Seek(0, SeekOrigin.Begin);
            var content= await new StreamReader(response.Body).ReadToEndAsync();    
            var yourResponse = new YourResponse (); // CREATE THIS CLASS
            yourResponse.StatusCode = response.StatusCode;
            if(!IsResponseValid(response))
            {
                yourResponse.ErrorMessage = content;
            }
            else
            {
                yourResponse.Content = content;
            }
            yourResponse.Size = response.ToString().Length;
            var json = JsonConvert.SerializeObject(yourResponse );

            //We need to reset the reader for the response so that the client an read it
            response.Body.Seek(0, SeekOrigin.Begin);    
            return $"{json}";
        }

        private bool IsResponseValid(HttpResponse response)
        {
            if ((response != null)
                && (response.StatusCode == 200
                || response.StatusCode == 201
                || response.StatusCode == 202))
            {
                return true;
            }
            return false;
        }
    }

 public static class ResponseMiddleware
    {
        public static void UseYourResponseMiddleware(this IApplicationBuilder app)
        {
            app.UseMiddleware<YourResponseMiddleware>();
        }
    }

在 Startup.cs (Configure())

 app.UseYourResponseMiddleware();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM