Как я могу захватить HttpContext.Response.Заголовки для всех ответов веб-api?

#c# #asp.net-core

#c# #asp.net-core

Вопрос:

Я пытаюсь захватить все заголовки ответов для всех ответов в веб-API, но HttpContext.Response .Коллекция заголовков всегда пуста. В настоящее время я использую .NET Core и ASP.Net Ядро 3.1.

Реализация начинается с Startup.cs, куда добавляется промежуточное программное обеспечение.

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
  
    app.UseMiddleware<CaptureResponseHeaders>();
   
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

}
 

Далее класс промежуточного программного обеспечения

 public class CaptureResponseHeaders
{
    public CaptureResponseHeaders(RequestDelegate next)
    {
        _next = next;
    }
    private readonly RequestDelegate _next;

    public async Task Invoke(HttpContext httpContext)
    {
     
        if(httpContext.Response.Headers.Count > 0) //this is always zero.
 

И запрос, простая конечная точка Get API

 [ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
   
private readonly ILogger<WeatherForecastController> _logger;

public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
    _logger = logger;
}

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
    
    var rng = new Random();
    
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    })
    .ToArray();
   
}
 

И заголовки ответов, которые я ожидаю захватить

 content-type: application/json; charset=utf-8
date: Mon, 14 Dec 2020 18:47:43 GMT
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
 

Комментарии:

1. Хотя ответ от Питера Расмуссена звучит неплохо, мне кажется, что все, что вам нужно сделать, это убедиться, что ваше промежуточное программное обеспечение сначала добавлено в конвейер, чтобы оно было последним в ответе, разверните и используйте await _next() перед любой вашей логикой Invoke(...) для получения заголовков.

Ответ №1:

Вы можете сделать следующее в своем методе invoke:

 public async Task Invoke(HttpContext context)
{
    context.Response.OnStarting(state => {
        var httpContext = (HttpContext)state;

        if (httpContext.Response.Headers.Count > 0)
            CaptureHeaders(); //TODO your implementation

        return Task.CompletedTask;
    }, context);

    await _next(context);
}
 

Это позволяет захватить ответ прямо перед его отправкой клиенту. Вы также можете использовать OnCompleted для получения ответа после его отправки.

Изображение заголовков можно увидеть ниже:

введите описание изображения здесь

Комментарии:

1. Заголовок ‘Content-Length’ никогда не существует для меня, я думаю, это потому, что ответ передается потоком, поэтому на данный момент он недоступен… есть идеи, как получить его, не читая поток?

Ответ №2:

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

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    // here 
    app.UseMiddleware<CaptureResponseHeaders>();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

}
 

Что касается нуля, который вы продолжаете видеть, попробуйте поместить свою логику захвата после выполнения остальной части конвейера.

 public async Task Invoke(HttpContext httpContext)
    {
        await _next();

        if(httpContext.Response.Headers.Count > 0) 
        {
            // do responsive things
        }
    }