![](/img/trans.png)
[英]How can I capture included property names in a JSON web api request with asp.net core?
[英]Capture JSON request when exception on ASP.Net Core 2 Web API
我正在使用.Net Core 2.1创建ASP.Net Core Web API,并且需要创建用于全局异常处理的自定义中间件。 我正在尝试做的是在应用程序中发生异常时捕获JSON请求。 由于我使用的是自定义中间件,因此我希望在中间件中可以使用JSON请求。 我怎样才能做到这一点?
我通过遵循Marinko Spasojevic的一篇文章尝试创建用于集中式异常处理的自定义中间件,并对其进行了少许修改以捕获json请求。 似乎该请求已不可用,因为该异常发生在控制器操作内(不在中间件中)。 这是我的代码:
这是我的错误日志模型
public class ErrorLog
{
public DateTime LogDate { get; set; }
public string URL { get; set; }
public string Request { get; set; }
public string Source { get; set; }
public string Message { get; set; }
}
这是我的项目中使用的标准响应模型
public class BaseResponse<T> : IBaseResponse where T : class
{
public bool Status { get; set; }
public string Message { get; set; }
public IEnumerable<T> Data { get; set; }
}
这是我的自定义异常中间件
public class GlobalException
{
private readonly RequestDelegate _next;
private readonly ICustomLogger _logger;
public GlobalException(RequestDelegate next, ICustomLogger logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
ErrorLog log = new ErrorLog();
log = await HandleLogError(httpContext, ex);
_logger.LogError(log); // Custom build logger
await HandleExceptionAsync(httpContext, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
BaseResponse<object> response = new BaseResponse<object>();
response.Status = false;
response.Message = "There is an exception occured.";
response.Data = new List<object>();
await context.Response.WriteAsync(response.Serialize());
}
private static async Task<ErrorLog> HandleLogError(HttpContext context, Exception exception)
{
Stream body = context.Request.Body;
context.Request.EnableRewind();
byte[] buffer = new byte[Convert.ToInt32(context.Request.ContentLength)];
await context.Request.Body.ReadAsync(buffer, 0, buffer.Length);
string requestText = Encoding.UTF8.GetString(buffer);
context.Request.Body = body;
ErrorLog log = new ErrorLog();
UriBuilder builder = new UriBuilder();
builder.Scheme = context.Request.Scheme;
builder.Host = context.Request.Host.Host;
builder.Path = context.Request.Path.ToString();
builder.Query = context.Request.QueryString.ToString();
log.LogDate = DateTime.Now;
log.URL = builder.Uri.ToString();
log.Request = requestText;
log.Source = exception.Source;
log.Message = exception.Message;
return log;
}
}
并最终注册中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseMiddleware<GlobalException>();
...
}
那么,谁能给我启发? 任何帮助将不胜感激,并在此之前感谢您。
似乎该请求已不可用,因为该异常发生在控制器操作内(不在中间件中)。
首先,如果这是您ex.InnerException
则可以通过ex.InnerException
获得根错误。
我正在尝试做的是在应用程序中发生异常时捕获JSON请求。
另外,您可以读取和记录请求和响应(在这种情况下,我假设它已序列化为json),如下所示在您的错误处理中间件中。
public async Task InvokeAsync(HttpContext context)
{
var requestAsString = await FormatRequest(context.Request);
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
await _next(context);
var responseString = await FormatResponse(context.Response);
await responseBody.CopyToAsync(originalBodyStream);
}
}
private async Task<string> FormatRequest(HttpRequest request)
{
var body = request.Body;
request.EnableRewind();
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
var bodyAsText = Encoding.UTF8.GetString(buffer);
request.Body = body;
return $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
}
private async Task<string> FormatResponse(HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
var text = await new StreamReader(response.Body).ReadToEndAsync();
response.Body.Seek(0, SeekOrigin.Begin);
return $"Response {text}";
}
顺便说一句,我做了一些小的改动以使其正确地适合您的问题,但是积分显示在这个要点页面上。 希望这能解决您的问题。
显然,导致请求无法检索的这部分代码
...
try
{
await _next(httpContext); // this will change the httpContext contents
}
...
这是我的最终代码
public class GlobalException
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public GlobalException(RequestDelegate next, ILogger logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
HttpContext tempCtx = context; // had to contain the http context
string request = await FormatRequest(context.Request);
try
{
await _next(context);
}
catch (Exception ex)
{
ErrorLog log = new ErrorLog();
UriBuilder builder = new UriBuilder();
builder.Scheme = tempCtx.Request.Scheme;
builder.Host = tempCtx.Request.Host.Host;
builder.Path = tempCtx.Request.Path.ToString();
builder.Query = tempCtx.Request.QueryString.ToString();
log.LogDate = DateTime.Now;
log.URL = builder.Uri.ToString();
log.Request = request;
log.Source = ex.Source;
log.Message = ex.Message;
await _logger.LogError(log); // custom logger
await HandleExceptionAsync(context);
}
}
private async Task<string> FormatRequest(HttpRequest request)
{
request.EnableRewind();
var body = request.Body;
byte[] buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
string requestBody = Encoding.UTF8.GetString(buffer);
body.Seek(0, SeekOrigin.Begin);
request.Body = body;
return requestBody;
}
private async Task HandleExceptionAsync(HttpContext context)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
BaseResponse<object> response = new BaseResponse<object>();
response.Status = false;
response.Message = "There is an exception occured.";
response.Data = new List<object>();
await context.Response.WriteAsync(response.Serialize());
}
}
非常感谢Hasan给我的启发。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.