2016-10-15 33 views
4

我想包裹我所有的http回覆。
比如我們有一些返回JSON數據的操作:包裝所有回覆

public IActionResult Get() 
{ 
    var res = new 
     { 
      MessageBody = "Test", 
      SomeData = 1 
     }; 

     return Ok(res); 
} 

我想我的回答是這樣的:

{  
    "StatusCode":200, 
    "Result": 
    { 
     "MessageBody ":"Test", 
     "SomeData":1   
    } 
} 

如果有錯誤,那麼響應必須包含在響應ErrorMessage場。

在mvc 5中,我使用了DelegationHandler,但是在asp.net內核中沒有實現這個類。現在,我們必須使用中間件。

這是MVC 5代碼:

public class WrappingHandler : DelegatingHandler 
{ 
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     var response = await base.SendAsync(request, cancellationToken); 

     return BuildApiResponse(request, response); 
    } 

    private static HttpResponseMessage BuildApiResponse(HttpRequestMessage request, HttpResponseMessage response) 
    { 
     object content; 
     string errorMessage = null; 

     if (response.TryGetContentValue(out content) && !response.IsSuccessStatusCode) 
     { 
      HttpError error = content as HttpError; 

      if (error != null) 
      { 
       content = null; 
       errorMessage = error.Message; 

#if DEBUG 
       errorMessage = string.Concat(errorMessage, error.ExceptionMessage, error.StackTrace); 
#endif 
      } 
     } 

     var newResponse = request.CreateResponse(response.StatusCode, new ApiResponse(response.StatusCode, content, errorMessage)); 

     foreach (var header in response.Headers) 
     { 
      newResponse.Headers.Add(header.Key, header.Value); 
     } 

     return newResponse; 
    } 
} 

,並且對於asp.net芯中間件。在asp.net核心中沒有TryGetContentValue,HttpError等東西。所以,我想先讀響應體:

public class FormatApiResponseMiddleware 
{ 
     private readonly RequestDelegate _next; 

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

     private bool IsSuccessStatusCode(int statusCode) 
     { 
      return (statusCode >= 200) && (statusCode <= 299); 

     } 

     public async Task Invoke(HttpContext context) 
     { 
      object content = null; 
      string errorMessage = null; 

      if (!IsSuccessStatusCode(context.Response.StatusCode)) 
      { 
       content = null; 
       //how to get error 
      } 

      var body= context.Response.Body; 
     } 
} 

但是,Body流具有CanRead等於false,我得到錯誤流不能被讀取。如何正確包裝回應?

+0

你究竟想要完成什麼?模型驗證?異常處理? – Tseng

+0

@Tseng我已更新問題,添加了一些細節。 – user348173

回答

0

我建議使用ExceptionHandlerMiddleware作爲你的中間件應該如何實現的模板/樣本。

例如,你應該知道有關情況,當反應已經開始

// We can't do anything if the response has already started, just abort. 
if (context.Response.HasStarted) 
{ 
    _logger.LogWarning("The response has already started, the error handler will not be executed."); 
    throw; 
} 

還是不要忘記清除電流響應,如果你要替換它:

context.Response.Clear(); 

此外,也許你會發現有用的只是重用它,並實現你自己的錯誤處理程序,而不是一個完整的中間件。這樣你可以發送一個自定義的JSON錯誤給客戶端。爲此,定義一個類,將代表您的自定義錯誤:

public class ErrorDto 
{ 
    public int Code { get; set; } 
    public string Message { get; set; } 

    // other fields 

    public override string ToString() 
    { 
     return JsonConvert.SerializeObject(this); 
    } 
} 

然後註冊在Configure方法的異常處理的中間件。注意中間件註冊的順序,並確保它在MVC之前註冊,例如:

app.UseExceptionHandler(errorApp => 
{ 
    errorApp.Run(async context => 
    { 
     context.Response.StatusCode = 500; // or another Status 
     context.Response.ContentType = "application/json"; 

     var error = context.Features.Get<IExceptionHandlerFeature>(); 
     if (error != null) 
     { 
      var ex = error.Error; 

      await context.Response.WriteAsync(new ErrorDto() 
      { 
       Code = 1, //<your custom code based on Exception Type>, 
       Message = ex.Message // or your custom message 
       // … other custom data 
      }.ToString(), Encoding.UTF8); 
     } 
    }); 
});