Захватите запрос JSON при исключении из ASP.Net Core 2 Web API - PullRequest
0 голосов
/ 02 января 2019

Я создаю ASP.Net Core Web API с использованием .Net Core 2.1, и мне нужно создать собственное промежуточное программное обеспечение для глобальной обработки исключений. То, что я пытаюсь сделать, это захватить 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>();
        ...
    }

Так, кто-нибудь может дать мне просветление? Любая помощь будет оценена и благодарна.

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Видимо, эта часть кода, вызывающая запрос, не может быть получена

...
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());
    }
}

Огромное спасибо Хасану за то, что он дал мне просветление.

0 голосов
/ 02 января 2019

Кажется, запрос уже недоступен, поскольку исключение произошло внутри действия контроллеров (не в промежуточном программном обеспечении).

Во-первых, вы можете получить root-ошибку на 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}";
}

Кстати, я внес небольшие изменения, чтобы он соответствовал вашей проблеме должным образом, но кредиты переходят на эту страницу gist . Надеюсь, что это решит вашу проблему.

...