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.