Wstrzykiwanie usług do widoków Razor w ASP.NET Core

Widoki Razor w ASP.NET Core udostępniają nam niezwykle ważną funkcjonalność  –  wstrzykiwanie zależności (dependency injection). Dzięki niej możemy wstrzykiwać usługi nie tylko do kontrolerów czy też chociażby warstwy Middleware, ale także widoków. Poniższy wpis pokazuje krok po kroku, jak możemy taką funkcjonalność wykorzystać w praktyce.

Rejestracja usługi (Service Registration)
Aplikacje pisane w ASP.NET Core rejestrują swoje zależności w metodzie ConfigureServices, która znajduje się w klasie Startup. Metoda ta pozwala nam dodawać dowolne usługi, które będą potem używane w naszej aplikacji. W poniższym przykładzie będziemy rejestrować usługę CatService.
Najpierw musimy stworzyć nasz projekt. Otwieramy Visual Studio 2019 i wybieramy opcję Create a new project:

Tworzenie nowego projektu w Visual Studio 2019

Spośród dostępnych szablonów wybieramy ten o nazwie ASP.NET Core Web App (Model-View-Controller) i klikamy przycisk Next:

Wybranie szablonu dla projektu

Nadajemy nazwę naszemu projektowi, wskazujemy lokalizację i klikamy przycisk Next:

Nadanie nazwy projektowi

Wybieramy .NET 5.0 (Current) jako Target Framework, dla uproszczenia projektu odznaczamy wszystkie pozostałe checkbox’y i klikamy przycisk Create:

Wybór framework'a

Poniżej widok utworzonego projektu:

Utworzony projekt

Prawym przyciskiem myszy klikamy na folderze Models, potem wybieramy Add –> New Item… –> Class. Zmieniamy nazwę klasy na Cat i klikamy przycisk Add:

Dodanie klasy Cat

Do naszej klasy dodajemy właściwość Name:

Dodanie właściwości

Prawym przyciskiem myszy klikamy na projekcie i wybieramy opcję New Folder. Zmieniamy nazwę folderu na Services:

Dodanie folderu Services

Prawym przyciskiem myszy klikamy na folderze Services, potem wybieramy Add –> New Item… –> Interface. Zmieniamy nazwę interfejsu na ICatService i klikamy przycisk Add:

Dodanie interfejsu ICatService

Do interfejsu dodajemy referencję do folderu Models:

Dodanie przycisku do interfejsu

Zmieniamy modyfikator dostępu w interfejsie na public, a potem w interfejsie dodajemy sygnaturę metody GetName:

Dodanie sygnatury metody do interfejsu

Prawym przyciskiem myszy klikamy na folderze Services, potem wybieramy Add –> New Item… –> Class. Zmieniamy nazwę klasy na CatService i klikamy przycisk Add:

Dodanie klasy do folderu Services

W klasie CatService implementujemy metodę GetName jak poniżej. W metodzie tej inicjalizujemy nową instancję właściwości Name:

Implementacja interfejsu ICatService

Teraz należy zarejestrować naszą usługę w metodzie ConfigureServicesw klasie Startup.  Możemy także określić, po jakim czasie taka usługa zostanie usunięta. Możemy użyć 3 opcji: Singleton, Transient i Scoped.

  • Singleton. Ta opcja tworzy jedną instancję usługi na cały czas działania aplikacji. Wystąpienie usługi można utworzyć w momencie rejestracji za pomocą metody Add().

Alternatywnie wystąpienie usługi można utworzyć przy pierwszym żądaniu przy użyciu metody AddSingleton().

  • Transient. Korzystając z tej opcji, nowa instancja usługi będzie tworzona za każdym razem, gdy zostanie o nią poproszona. Innymi słowy: tworzy ona nową instancję za każdym razem, gdy dochodzi do wstrzyknięcia zależności (czyli np. dla każdego kontrolera, który w konstruktorze ma wstrzykniętą zależność do tej usługi). Oznacza to, że usługa wstrzyknięta do konstruktora będzie działać tak długo, jak będzie istniała ta instancja tego konstruktora. Aby utworzyć usługę z przejściowym okresem istnienia, musisz użyć metody AddTransient().

  • Scoped. Ta opcja umożliwia tworzenie instancji usługi dla każdego żądania klienta. Jest to szczególnie przydatne w kontekście ASP.NET Core, ponieważ umożliwia udostępnianie tego samego wystąpienia usługi na czas przetwarzania żądania HTTP. Aby włączyć opcję Scoped, musimy użyć metody AddScoped(). Scoped będzie współdzielić instancję w ramach tego samego zapytania. Jest to przydatne, kiedy mamy wiele klas do których wstrzykujemy ten sam typ.

  • W przypadku wielu usług nie ma potrzeby tworzenia osobnych instancji.

Podsumowując:

  • Obiekty Transientsą zawsze różne; nowa instancja jest udostępniana każdemu kontrolerowi i każdej usłudze.
  • Obiekty Scoped są takie same w żądaniu, ale różne w różnych żądaniach.
  • Obiekty Singleton są takie same dla każdego obiektu i każdego żądania.

Możemy zarejestrować naszą nowo utworzoną usługę CatService jako usługę typu Singleton. ASP.NET Core stworzy naszą usługę raz dla całej aplikacji. Możemy również wybrać rejestrację naszych usług jako Transient lub Scoped w zależności od naszych konkretnych potrzeb.

W klasie Startup dodajemy referencję do folderu Services:

Dodanie nowej przestrzeni do klasy Startup

Następnie rejestrujemy usługę CatService:

Rejestracja usługi CatService

Wstrzyknięcie usługi do widoku

ASP.NET Core dodał nowy helper @inject w ramach najnowszego silnika Razor. Ten helper wywołuje mechanizm wstrzykiwania zależności ASP.NET Core i pobiera wymaganą usługę.

Aby zobaczyć jak działa, zmodyfikujemy domyślny widokIndex dla kontrolera Home.

Najpierw w pliku _ViewImports.cshtml dodajemy referencję do folderu Services:

Dodanie przestrzeni do widoku

Teraz modyfikujemy nasz widok:

Dodanie zawartości do widoku

Poniżej dokładne informacje, jak działa helper @inject:
1. Używamy @inject w górnej części naszego widoku Razor.
2. Po @inject podajemy nazwę usługi, którą chcemy wstrzyknąć. W naszym przypadku jest to usługa ICatService.
3. Na koniec nadajemy naszej wstrzykniętej zależności nazwę, tutaj jest to CatsNames.
Gdy widok Razor ma wstrzykniętą zależność, możemy użyć tej zależności tak, jak każdego innego odwołania do zmiennej.

Po uruchomieniu aplikacji możemy zobaczyć, że widok wyświetla nazwę kota, która została pobrana z usługi:

Widok uruchomionej aplikacji
Możliwość wstrzykiwania zależności do widoków Razor to cenna funkcjonalność, którą możemy wykorzystać przy tworzeniu aplikacji internetowych.

Gotowy projekt można znaleźć na moim Githubie pod tym linkiem:

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *