Injection de dépendances avec attributs sur l'API .NET
L’injection de dépendances est probablement l’une des meilleures fonctionnalités dont nous disposons actuellement sur .NET. Il est impossible que vous ne l’utilisiez pas, donc si vous êtes comme moi, vous voulez vraiment l’ajouter à toutes les implémentations que vous effectuez.
Filtres, selon la [documentation](https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1 officielle de Microsoft :
Les filtres dans ASP.NET Core permettent d’exécuter du code avant ou après des étapes spécifiques du pipeline de traitement des requêtes.
Les filtres intégrés gèrent des tâches telles que :
- Autorisation, empêchant l’accès aux ressources pour lesquelles un utilisateur n’est pas autorisé.
- Mise en cache des réponses, court-circuitant le pipeline de requêtes pour renvoyer une réponse mise en cache.
Des filtres personnalisés peuvent être créés pour traiter les préoccupations transversales. Des exemples de problèmes transversaux incluent la gestion des erreurs, la mise en cache, la configuration, l’autorisation et la journalisation. Les filtres évitent la duplication de code.
Je travaille beaucoup avec des API et il y a des éléments qui doivent exécuter chaque requête, ou presque toutes, donc idéalement, ce que nous voulons faire, c’est travailler avec cela plus… l’injection de dépendances !
Mais c’est parfois un peu compliqué, cela ne fonctionne pas comme nous le souhaitons si nous voulons hériter de ActionAttribute donc nous devons travailler avec TypeFilterAttribute, qui nous permet de faire des choses lors du remplacement de OnActionExecutionAsync.
Je crée habituellement ces filtres pour effectuer de la journalisation, nous allons donc l’utiliser comme exemple :
/// <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 logique est assez simple, nous obtenons le corps en accédant à l’objet context avec context.ActionArguments.First().Value, nous obtenons également l’appel de méthode avec context.HttpContext.Request.Path.Value.
Ensuite, nous appelons simplement notre méthode depuis notre service, dans ce cas est _loggingService.LogCustomEvent(call).
Ensuite, il faut appeler await next();, car le pipeline doit continuer.
C’est pour l’attribut, maintenant, nous devons effectivement inclure cet attribut dans une méthode.
[LoggedQueryTypeFilterAttribute]
public ActionResult<string> TestFilter()
{
return Ok("Hello world!");
}
J’espère que cela vous a plu, si vous avez des questions ou si vous souhaitez nous contacter, n’hésitez pas et contactez-moi !