asp.net-core – 如何包装Web API响应(在.net核心中)以保持一致性?

我需要返回一个一致的响应,并为所有请求返回一个类似的结构.在之前的.NET web api中,我能够使用DelegatingHandler(MessageHandlers)实现此目的.我想要返回的对象将封装在Result元素中.所以基本上json响应将是这种结构:

例1:

{
    "RequestId":"some-guid-abcd-1234",
    "StatusCode":200,
    "Result":
    {
        "Id":42,
        "Todo":"Do Hello World"
    }
}

例2:

{
    "RequestId":"some-guid-abcd-1235",
    "StatusCode":200,
    "Result":
    {
        [
            {        
                "Id":42,
                "Todo":"Print Hello World"
            },
            {        
                "Id":43,
                "Todo":"Print Thank you"
            }           
        ]

    }
}

在.NET核心中,看起来我需要通过中间件来实现这一点.我尝试了但是我没有看到更好的方法来提取内容,就像在以前的Web API中一样,当你可以调用HttpResponseMessage.TryGetContentValue来获取内容并将其包装在全局/通用响应模型中时.

如何在.NET核心中实现相同的目标?

最佳答案
我创建了一个中间件来包装响应的一致性.为了方便注册这个中间件,我还为IApplicationBuilder创建了一个扩展方法.所以在Startup.cs中,注册中间件:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //code removed for brevity.
    ...
    app.UseResponseWrapper();

    //code removed for brevity.
    ...
}

这是中间件代码:

using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

namespace RegistrationWeb.Middleware
{
    public class ResponseWrapper
    {
        private readonly RequestDelegate _next;

        public ResponseWrapper(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            var currentBody = context.Response.Body;

            using (var memoryStream = new MemoryStream())
            {
                //set the current response to the memorystream.
                context.Response.Body = memoryStream;

                await _next(context);

                //reset the body 
                context.Response.Body = currentBody;
                memoryStream.Seek(0, SeekOrigin.Begin);

                var readToEnd = new StreamReader(memoryStream).ReadToEnd();
                var objResult = JsonConvert.DeserializeObject(readToEnd);
                var result = CommonApiResponse.Create((HttpStatusCode)context.Response.StatusCode, objResult, null);
                await context.Response.WriteAsync(JsonConvert.SerializeObject(result));
            }
        }

    }

    public static class ResponseWrapperExtensions
    {
        public static IApplicationBuilder UseResponseWrapper(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ResponseWrapper>();
        }
    }


    public class CommonApiResponse
    {
        public static CommonApiResponse Create(HttpStatusCode statusCode, object result = null, string errorMessage = null)
        {
            return new CommonApiResponse(statusCode, result, errorMessage);
        }

        public string Version => "1.2.3";

        public int StatusCode { get; set; }
        public string RequestId { get; }

        public string ErrorMessage { get; set; }

        public object Result { get; set; }

        protected CommonApiResponse(HttpStatusCode statusCode, object result = null, string errorMessage = null)
        {
            RequestId = Guid.NewGuid().ToString();
            StatusCode = (int)statusCode;
            Result = result;
            ErrorMessage = errorMessage;
        }
    }
}

转载注明原文:asp.net-core – 如何包装Web API响应(在.net核心中)以保持一致性? - 代码日志