Sfruttare la dependency injection in un Filter di ASP.NET Core

di Marco De Sanctis, in ASP.NET Core,

Il concetto di filter è presente in fin dalle prime versioni di ASP.NET MVC ed è stato pienamente ereditato anche in ASP.NET Core. Come probabilmente sappiamo, grazie ai filter è possibile aggiungere della logica a una specifica action, a un intero controller o anche a tutta l'applicazione.

Alle volte potremmo avere la necessità di iniettare dipendenze all'interno di un custom filter. Per esempio su un custom Authorize filter, vorremmo avere accesso al database degli utenti per leggere alcune informazioni sul profilo dell'utente stesso, o in un Resource filter vorremmo avere accesso alla cache per verificare se il dato richiesto è presente.

Immaginiamo ad esempio di aver realizzato un filtro simile al seguente, in cui segnaliamo nel log l'inizio e il completamento di una action:

public class LoggerFilter : IActionFilter
{
    private ILogger<LoggerFilter> _logger;

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

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _logger.LogDebug($"Action {context.ActionDescriptor.DisplayName} completed");
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogDebug($"Action {context.ActionDescriptor.DisplayName} starting");
    }
}

Questa classe necessita di un ILogger<T> come parametro di input. Ovviamente non possiamo definirla come Attribute perchè altrimenti non avremmo modo di fornire questo parametro nel costruttore.

L'alternatica allora è creare un secondo oggetto, che implementi IFilterFactory:

public class LoggerAttribute : Attribute, IFilterFactory
{
  public bool IsReusable => true;

  public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
  {
    return serviceProvider.GetService<LoggerFilter>();
  }
}

Questa interfaccia espone un metodo CreateInstance in cui possiamo generare il filtro di cui effettivamente abbiamo bisogno, sfruttando il serviceProvider passato come parametro.

La nostra nuova classe LoggerAttribute eredita effettivamente da Attribute e può essere utilizzata direttamente sul controller o sulla action interessata.

[Route("api/[controller]")]
[ApiController]
[Logger]
public class ValuesController : ControllerBase
{ ... }

Affinchè tutto funzioni, l'ultimo passaggio è registrare LoggerFilter nell'IoC container di ASP.NET Core all'interno della classe Startup:

public void ConfigureServices(IServiceCollection services)
{
  // .. altro codice qui ..
  services.AddTransient<LoggerFilter>();
}

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi