Inyección de dependencia con atributos en .NET API
La inyección de dependencia es probablemente una de las mejores características que tenemos en .NET en este momento. No hay forma en ningún caso posible de que no lo estés usando, así que si eres como yo, querrás agregarlo a todas las implementaciones que hagas.
Filtros, según la [documentación] oficial de Microsoft (https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1):
Los filtros en ASP.NET Core permiten que el código se ejecute antes o después de etapas específicas en el proceso de procesamiento de solicitudes.
Los filtros integrados manejan tareas como:
- Autorización, que impide el acceso a recursos para los que un usuario no está autorizado.
- Almacenamiento en caché de respuestas, cortocircuitando la canalización de solicitudes para devolver una respuesta almacenada en caché.
Se pueden crear filtros personalizados para manejar inquietudes transversales. Ejemplos de preocupaciones transversales incluyen el manejo de errores, el almacenamiento en caché, la configuración, la autorización y el registro. Los filtros evitan duplicar código.
Trabajo mucho con API y hay algunas cosas que deben ejecutarse en cada solicitud, o prácticamente en todas, por lo que idealmente lo que queremos hacer es trabajar con ellas y además… ¡inyección de dependencias!
Pero a veces es un pequeño truco, no funciona como queremos si queremos heredar de ActionAttribute, por lo que necesitamos trabajar con TypeFilterAttribute, lo que nos permite hacer cosas al anular OnActionExecutionAsync.
Normalmente creo estos filtros para realizar algunos registros, así que los usaremos como ejemplo:
/// <summary>
/// LoggedQueryAttribute class
/// </summary>
public class LoggedQueryTypeFilterAttribute : TypeFilterAttribute
{
/// <summary>
/// Constructor for <see cref="LoggedQueryTypeFilterAttribute"/>
/// </summary>
public LoggedQueryTypeFilterAttribute() : base(typeof(LoggedQueryFilter))
{
}
/// <summary>
/// LoggedQueryFilter class
/// </summary>
private class LoggedQueryFilter : IAsyncActionFilter
{
/// <summary>
/// <see cref="_loggingService"/> object
/// </summary>
private readonly LoggingService _loggingService;
/// <summary>
/// Constructor for <see cref="LoggedQueryFilter"/>
/// </summary>
/// <param cref="LoggingService" name="loggingService">Parameter for loggingService</param>
public LoggedQueryFilter(LoggingService loggingService)
{
_loggingService = loggingService;
}
/// <summary>
/// OnActionExecutionAsync
/// </summary>
/// <param cref="ActionExecutingContext" name="context">Parameter for context</param>
/// <param cref="ActionExecutionDelegate" name="next">Parameter for next</param>
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// Get properties
var properties = (Request)context.ActionArguments.First().Value!;
// Get call from context
var call = context.HttpContext.Request.Path.Value!;
// Logging
_loggingService.LogCustomEvent(call);
// Continue call
await next();
}
}
}
La lógica es bastante simple, obtenemos el cuerpo accediendo al objeto context con context.ActionArguments.First().Value, también obtenemos la llamada al método con context.HttpContext.Request.Path.Value.
Luego simplemente llamamos a nuestro método desde nuestro servicio, en este caso es _loggingService.LogCustomEvent(call).
Luego, debemos llamar a await next();, porque el pipeline debe continuar.
Esto es para el atributo, ahora debemos incluir este atributo en un método.
[LoggedQueryTypeFilterAttribute]
public ActionResult<string> TestFilter()
{
return Ok("Hello world!");
}
Espero que te haya gustado, si tienes alguna duda o quieres ponerte en contacto, ¡no lo dudes y contacta conmigo!