Как я могу вернуть пользовательский заголовок http в ядре asp.net? - PullRequest
0 голосов
/ 19 октября 2018

Ciao,

Я занимаюсь разработкой серии микросервисов с ядром aspnet.Я хочу вернуть пользовательский HTTP-заголовок для 500 ответов.

Я попытался создать пользовательское ASP.NET Core Middleware , которое обновляет context.Response.Headers свойство, ноон работает только при ответе 200.

Это мое пользовательское промежуточное ПО:

namespace Organizzazione.Progetto
{
    public class MyCustomMiddleware
    {
        private readonly RequestDelegate _next;

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

        public async Task InvokeAsync(HttpContext context)
        {
            context.Response.Headers.Add("X-Correlation-Id", Guid.NewGuid());
            await _next.Invoke(context);
            return;
        }
    }
}

Это мой метод настройки:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMiddleware<MyCustomMiddleware>();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseMvc();
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API");
    });
}

Как я могу вернуть свойПользовательский заголовок для ответа 500, вызванного необработанным исключением (или, возможно, для всех ответов)?

Большое спасибо

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Вы можете использовать глобальный фильтр:

public class CorrelationIdFilter : IActionFilter
    {
        /// <summary>
        /// Called after the action executes, before the action result.
        /// </summary>
        /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ActionExecutedContext" />.</param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
        }

        /// <summary>
        /// Called before the action executes, after model binding is complete.
        /// </summary>
        /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext" />.</param>
        /// <exception cref="InvalidOperationException"></exception>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            context.HttpContext.Response.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
        }
    }

Если вы делаете то же самое, но только в исключительных случаях, используйте IExceptionFilter:

public class CorrelationIdFilter : IExceptionFilter, IAsyncExceptionFilter
{
    private readonly ILogger<CorrelationIdFilter> _logger;

    /// <summary>
    /// Initialize a new instance of <see cref="CorrelationIdFilter"/>
    /// </summary>
    /// <param name="logger">A logger</param>
    public CorrelationIdFilter(ILogger<CorrelationIdFilter> logger)
    {
        _logger = logger;
    }
    /// <summary>
    /// Called after an action has thrown an <see cref="T:System.Exception" />.
    /// </summary>
    /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ExceptionContext" />.</param>
    /// <returns>
    /// A <see cref="T:System.Threading.Tasks.Task" /> that on completion indicates the filter has executed.
    /// </returns>
    public Task OnExceptionAsync(ExceptionContext context)
    {
        Process(context);
        return Task.CompletedTask;
    }

    /// <summary>
    /// Called after an action has thrown an <see cref="T:System.Exception" />.
    /// </summary>
    /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.ExceptionContext" />.</param>
    public void OnException(ExceptionContext context)
    {
        Process(context);
    }

    private void Process(ExceptionContext context)
    {
        var e = context.Exception;
        _logger.LogError(e, e.Message);

        context.HttpContext.Response.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());

        if (e is InvalidOperationException)
        {
            context.Result = WriteError(HttpStatusCode.BadRequest, e);
        }
        else if (e.GetType().Namespace == "Microsoft.EntityFrameworkCore")
        {
            context.Result = WriteError(HttpStatusCode.BadRequest, e);
        }
        else
        {
            context.Result = WriteError(HttpStatusCode.InternalServerError, e);
        }                

    }


    private IActionResult WriteError(HttpStatusCode statusCode, Exception e)
    {
        var result = new ApiErrorResult(e.Message, e)
        {
            StatusCode = (int)statusCode,               
        };

        return result;
    }

}

/// <summary>
/// Api error result
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.Mvc.ObjectResult" />
public class ApiErrorResult : ObjectResult
{
    private readonly string _reasonPhrase;

    /// <summary>
    /// Initializes a new instance of the <see cref="ApiErrorResult"/> class.
    /// </summary>
    /// <param name="reasonPhrase">The reason phrase.</param>
    /// <param name="value">The value.</param>
    public ApiErrorResult(string reasonPhrase, object value) : base(value)
    {
        _reasonPhrase = reasonPhrase;
    }

    /// <inheritdoc />
    public override async Task ExecuteResultAsync(ActionContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var reasonPhrase = _reasonPhrase;
        reasonPhrase = reasonPhrase.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)[0];
        context.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = reasonPhrase;
        await base.ExecuteResultAsync(context);
    }
}

И зарегистрируйте свой фильтр с помощью:

services.AddMvc(configure =>
            {
                var filters = configure.Filters;
                filters.Add<CorrelationIdFilter >();
            })
0 голосов
/ 19 октября 2018

Вы должны подписаться на httpContext.Response.OnStarting

public class CorrelationIdMiddleware
{
    private readonly RequestDelegate _next;

    public CorrelationIdMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.OnStarting((Func<Task>)(() =>
        {
            httpContext.Response.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString());
            return Task.CompletedTask;
        }));
        try
        {
            await this._next(httpContext);

        }
        catch (Exception)
        {
            //add additional exception handling logic here 
            //...
            httpContext.Response.StatusCode = 500;
        }

    }
}

и зарегистрировать свой Starup

 app.UseMiddleware(typeof(CorrelationIdMiddleware));
...