代码之家  ›  专栏  ›  技术社区  ›  Lemex

C#DotNet核心中间件Wrap响应

  •  11
  • Lemex  · 技术社区  · 8 年前

    我有一个简单的控制器动作,看起来像:

        public Task<IEnumerable<Data>> GetData()
        {
            IEnumerable<Data> data = new List<Data>();
            return data;
        }
    

    我希望能够检查中间件中的返回值,使JSON看起来像

    {
      "data": [
      ],
      "apiVersion": "1.2",
      "otherInfoHere": "here"
    }
    

    所以我的有效载荷总是在 data . 我知道我可以在控制器级别这样做,但我不想在每一个动作上都这样做。我宁愿在中间件中一劳永逸地完成它。

    以下是我的中间件示例:

    public class NormalResponseWrapper
    {
        private readonly RequestDelegate next;
    
        public NormalResponseWrapper(RequestDelegate next)
        {
            this.next = next;
        }
    
        public async Task Invoke(HttpContext context)
        {                
            var obj = context;
            // DO something to get return value from obj
            // Create payload and set data to return value
    
            await context.Response.WriteAsync(/*RETURN NEW PAYLOAD HERE*/);
        }
    

    有什么想法吗?

    现在已经得到了价值,但现在归还已经太晚了

            try
            {
                using (var memStream = new MemoryStream())
                {
                    context.Response.Body = memStream;
                    await next(context);
                    memStream.Position = 0;
                    object responseBody = new StreamReader(memStream).ReadToEnd();
                    memStream.Position = 0;
                    await memStream.CopyToAsync(originalBody);
                    // By now it is to late, above line sets the value that is going to be returned
                    await context.Response.WriteAsync(new BaseResponse() { data = responseBody }.toJson());
                }
    
            }
            finally
            {
                context.Response.Body = originalBody;
            }
    
    2 回复  |  直到 8 年前
        1
  •  7
  •   Nkosi    8 年前

    查看评论,了解如何包装回复。

    public async Task Invoke(HttpContext context) {
        //Hold on to original body for downstream calls
        Stream originalBody = context.Response.Body;
        try {
            string responseBody = null;
            using (var memStream = new MemoryStream()) {
                //Replace stream for upstream calls.
                context.Response.Body = memStream;
                //continue up the pipeline
                await next(context);
                //back from upstream call.
                //memory stream now hold the response data
                //reset position to read data stored in response stream
                memStream.Position = 0;
                responseBody = new StreamReader(memStream).ReadToEnd();
            }//dispose of previous memory stream.
            //lets convert responseBody to something we can use
            var data = JsonConvert.DeserializeObject(responseBody);
            //create your wrapper response and convert to JSON
            var json = new BaseResponse() { 
                data = data, 
                apiVersion = "1.2",
                otherInfoHere = "here"
            }.toJson();
            //convert json to a stream
            var buffer = Encoding.UTF8.GetBytes(json);
            using(var output = new MemoryStream(buffer)) {
                await output.CopyToAsync(originalBody);
            }//dispose of output stream
        } finally {
            //and finally, reset the stream for downstream calls
            context.Response.Body = originalBody;
        }
    } 
    
        2
  •  5
  •   Xavier John    5 年前

    在里面NET Core 3.1或。净额5

    1. 创建响应信封对象。例子:

      internal class ResponseEnvelope<T>
      {
        public T Data { set; get; }
        public string ApiVersion { set; get; }
        public string OtherInfoHere { set; get; }
      }
      
    2. 从ObjectResultExecutor派生类

      internal class ResponseEnvelopeResultExecutor : ObjectResultExecutor
      {
       public ResponseEnvelopeResultExecutor(OutputFormatterSelector formatterSelector, IHttpResponseStreamWriterFactory writerFactory, ILoggerFactory loggerFactory, IOptions<MvcOptions> mvcOptions) : base(formatterSelector, writerFactory, loggerFactory, mvcOptions)
       {
       }
      
       public override Task ExecuteAsync(ActionContext context, ObjectResult result)
       {
           var response = new ResponseEnvelope<object>();
           response.Data = result.Value;
           response.ApiVersion = "v1";
           response.OtherInfoHere = "OtherInfo";
      
           TypeCode typeCode = Type.GetTypeCode(result.Value.GetType());
           if (typeCode == TypeCode.Object)
                result.Value = response;
      
           return base.ExecuteAsync(context, result);
        }
      }
      
    3. 注入DI-like

      public void ConfigureServices(IServiceCollection services)
       {
           services.AddSingleton<IActionResultExecutor<ObjectResult>, ResponseEnvelopeResultExecutor>();
      

    回复应该有一个信封。 这不适用于基元类型。