asp.net core - route - ¿Cómo inyectar el valor HttpHeader en el controlador?
render partial asp net core (2)
Tengo la API web desarrollada usando ASP.NET Core API. Cada solicitud entrante tiene insertado un valor de encabezado personalizado. por ejemplo, x-correlationid
. El controlador usa este valor para registrar y rastrear la solicitud. Actualmente estoy leyendo el valor en cada controlador como se muestra a continuación
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private string _correlationid = null;
public DocumentController(ILogger<DocumentController > logger)
{
_logger = logger;
_correlationid = HttpContext.Request.Headers["x-correlationid"];
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _correlationid);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _correlationid);
return result;
}
}
Creo que esto va en contra de las reglas DI.
En lugar de leer el valor dentro del constructor del controlador, quiero inyectar el valor en el constructor del controlador.
O
¿Puede el middleware leer la x-correlationid
y *somehow*
ponerla a disposición de todos los controladores para que no tengamos que inyectarla en ningún controlador?
¿Cuál sería una mejor opción aquí?
En lugar de leer el valor dentro del constructor del controlador, quiero inyectar el valor en el constructor del controlador.
No puede inyectar el valor en sí mismo en el constructor del controlador api, porque en el momento de la construcción, el HttpContext
va a ser null
.
Una opción de "estilo de inyección" sería usar FromHeaderAttribute
en sus acciones:
[HttpPost]
public async Task<int> Transform(
[FromBody]RequestWrapper request,
[FromHeader(Name="x-correlationid")] string correlationId)
{
return result;
}
¿Puede el middleware leer la x-correlación y de alguna manera ponerla a disposición de todos los controladores para que no tengamos que inyectarla en ningún controlador?
Creo que una solución de middleware probablemente sería exagerada para lo que necesita. En su lugar, puede crear una clase base personalizada derivada de Controller
y todos sus controladores Api se derivan de eso.
public class MyControllerBase : Controller
{
protected string CorrelationId =>
HttpContext?.Request.Headers["x-correlationid"] ?? string.Empty;
}
[Route("api/[controller]")]
public class DocumentController : MyControllerBase
{
private ILogger<TransformController> _logger;
public DocumentController(ILogger<DocumentController> logger)
{
_logger = logger;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation($"Start task. CorrelationId:{CorrelationId}");
// do something here
_logger.LogInformation($"End task. CorrelationId:{CorrelationId}");
return result;
}
}
Esto es lo que se me ocurrió. Creo que también puedo probarlo en una unidad.
public interface IRequestContext
{
string CorrelationId { get; }
}
public sealed class RequestContextAdapter : IRequestContext
{
private readonly IHttpContextAccessor _accessor;
public RequestContextAdapter(IHttpContextAccessor accessor)
{
this._accessor = accessor;
}
public string CorrelationId
{
get
{
return this._accessor.HttpContext.Request.Headers[Constants.CORRELATIONID_KEY];
}
}
}
luego, en el método de configuración del servicio de inicio, registre el adaptador
services.AddSingleton<IRequestContext, RequestContextAdapter>();
e inyectarlo en el controlador
[Route("api/[controller]")]
public class DocumentController : Controller
{
private ILogger<TransformController> _logger;
private IRequestContext _requestContext = null;
public DocumentController(ILogger<DocumentController > logger,IRequestContext requestContext)
{
_logger = logger;
_requestContext = requestContext;
}
[HttpPost]
public async Task<intTransform([FromBody]RequestWrapper request)
{
_logger.LogInformation("Start task. CorrelationId:{0}", _requestContext.CorrelationId);
// do something here
_logger.LogInformation("End task. CorrelationId:{0}", _requestContext.CorrelationId);
return result;
}
}