包装所有回复

时间:2016-10-15 10:41:00

标签: c# asp.net-core asp.net-core-mvc asp.net5

我想要回复所有的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核心中没有TryGetContentValueHttpError和其他内容。所以,我试图首先阅读回复正文:

 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,我收到无法读取流的错误。如何正确包装回复?

1 个答案:

答案 0 :(得分:0)

我建议使用ExceptionHandlerMiddleware作为模板/示例,说明应该如何实现中间件。

例如,您应该了解案例,当响应已经开始时

.cb-input {
  width: 100%;
  min-height: 45px;
  max-height: 80px;
}

.cb-form {
  overflow: hidden;
  width: 100%;
  height: 100%;
}

.cb-input textarea{
  -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
  padding: 6px 14px 2px 10px;
  width: 100%;
  height: 100%;
  font-family: Roboto;
  font-size: 14px;
  border: none;
  resize: none;
  overflow-y: auto;
}

或者如果要替换它,请不要忘记清除当前的响应:

// 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;
}

此外,也许您会发现只是为了重用它,并实现自己的错误处理程序而不是完整的中间件。这样您就可以向客户端发送自定义JSON错误。为此,请定义一个代表您的自定义错误的类:

context.Response.Clear();

然后在public class ErrorDto { public int Code { get; set; } public string Message { get; set; } // other fields public override string ToString() { return JsonConvert.SerializeObject(this); } } 方法中注册异常处理程序中间件。注意中间件的注册顺序,并确保它在MVC之前注册,例如:

Configure