我如何 return 在 asp.net 核心中自定义 http header?

How can I return custom http header in asp.net core?

再见,

我正在使用 aspnet core 开发一系列微服务。我想 return 自定义 http header 500 个响应。

我试图创建一个自定义 ASP.NET 核心中间件 来更新 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");
    });
}

我如何 return 我的自定义 header 对由未处理的异常(或可能对所有响应)引起的 500 响应?

非常感谢

您必须订阅 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;
        }

    }
}

并注册您的 Startup

 app.UseMiddleware(typeof(CorrelationIdMiddleware));

您可以使用全局过滤器:

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