Rozwiązywanie zależności atrybutów w net core mvc

Random image, hand drawn

Dobry .net core

Core wprowadza milusie rozwiązania ułatwiające życie programistów, jednym z nim jest rozwiązanym problem zależności w atrybutach w .net core mvc. Otóż jest sposób na wstrzykiwania zależności do atrybutów mvc. Łot? Już nie będzie bolało? Nie trzeba więcej bleh-bleh-BLEH service-locatora, aby dostać się z miejsca gdzie dzieje się magia do mięska.

Jak? Odrobinę inaczej niż standardowym .net mvc.

Zależności

Zacznę od zdefiniowania prostej zależności oraz jej implementacji:

public interface ILogger
{
void Log(string text);
}
public class DebugTraceLogger : ILogger
{
public void Log(string text)
{
System.Diagnostics.Trace.WriteLine(text);
}
}

Dobry, nowy atrybut

Następnie klasę, z której będę korzystać jako atrybutu:

public class DiagnosticsTimerLogger : IActionFilter
{
private readonly ILogger logger;
private Stopwatch timer;
public DiagnosticsTimerLogger(ILogger logger)
{
this.logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
this.timer = System.Diagnostics.Stopwatch.StartNew();
}
public void OnActionExecuted(ActionExecutedContext context)
{
this.timer.Stop();
this.logger.Log($"Action took: {this.timer.ElapsedMilliseconds} ms.");
}
}

Co ciekawego w kodzie?Zacznę od tego, że nie implementuje (@1) klasy ActionFilterAttribute, lecz poziom niżej IActionFilter. W konstruktorze (@6) definiuje zależność od ILogger. Następnie już-już gdy akcja ma się wykonać tworzę nowym timer (@11,@13) a po zakończeniu metody loguje czas trwania operacji (@18,@19).

Kontener

W startup.cs konfiguruje wbudowany w .net core mvc domyślnie IOC

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ILogger,DebugTraceLogger>();
services.AddMvc();
}

Dla ILoggera będzie to prosty DebugTraceLogger (@3)

Materializacja atrybutu

Tam gdzie potrzeba i chęć korzystam ze wcześniej zdefiniowanej klasy “atrybutu”. Piszę tak, ponieważ oficjalnie klasa sama w sobie atrybutem nie jest i wymaga lekkiego popchnięcia.

[TypeFilter(typeof(DiagnosticsTimerLogger))]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
// ... moar code here
}

Najważniejsze jest miejsce deklaracji użycia atrybutu (@1), zamiast klasycznego wywołania mojej klasy “atrybutu”, posiłkuje się klasą TypeFilterAttribute która pięknie współgra z IOC w .net core i potrafi rozwiązywać zależności dla klas, którymi się opiekuje. W moim przypadku stworzy DiagnosticsTimerLogger oraz rozwiąże jego zależności czyli ILogger, który zostanie zainstancjonowany jako DebugTraceLogger, ponieważ startup.cs

Finał

Dla mnie bomba! Koniec z ServiceLocatorem, czy innymi równie brzydkimi “rozwiązaniami” na zależności w atrybutach w mvc.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.