Jak ręcznie rozwiązać typ za pomocą wbudowanej platformy wstrzykiwania zależności ASP.NET Core MVC?
Konfiguracja kontenera jest dość łatwa:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddTransient<ISomeService, SomeConcreteService>();
}
Ale jak mogę rozwiązać problem ISomeService
bez wykonywania zastrzyku? Na przykład chcę to zrobić:
ISomeService service = services.Resolve<ISomeService>();
Nie ma takich metod w IServiceCollection
.
ConfigureServices()
metodzie (zIServiceCollection
) czy w dowolnym miejscu aplikacji?Odpowiedzi:
IServiceCollection
Interfejs służy do budowy kontenera wtrysku zależność. Po pełnym skompilowaniu kompiluje się doIServiceProvider
instancji, której można użyć do rozwiązania usług. Możesz wstrzyknąćIServiceProvider
do dowolnej klasy. TeIApplicationBuilder
iHttpContext
klasy mogą zapewnić usługodawcy, jak również, za pośrednictwem swoichApplicationServices
lubRequestServices
właściwości odpowiednio.IServiceProvider
definiujeGetService(Type type)
metodę rozwiązania usługi:Dostępnych jest również kilka metod rozszerzania wygody, takich jak
serviceProvider.GetService<IFooService>()
(dodajusing
zaMicrosoft.Extensions.DependencyInjection
).Rozwiązywanie usług w klasie startowej
Wstrzykiwanie zależności
Hosting usługodawca środowisko wykonawcze mogą wprowadzić pewne usługi do konstruktora
Startup
klasy, takie jakIConfiguration
,IWebHostEnvironment
(IHostingEnvironment
w wersji pre-3.0),ILoggerFactory
iIServiceProvider
. Pamiętaj, że ten ostatni jest instancją zbudowaną przez warstwę hostingu i zawiera tylko niezbędne usługi do uruchomienia aplikacji .Ta
ConfigureServices()
metoda nie zezwala na wstrzykiwanie usług, przyjmuje tylkoIServiceCollection
argument. Ma to sens, ponieważConfigureServices()
rejestrujesz usługi wymagane przez aplikację. Można tu jednak skorzystać z usług wprowadzonych do konstruktora startupu, na przykład:Wszelkie zarejestrowane usługi
ConfigureServices()
można następnie wprowadzić doConfigure()
metody; możesz dodać dowolną liczbę usług poIApplicationBuilder
parametrze:Ręczne rozwiązywanie zależności
Jeśli trzeba ręcznie usług postanowienie, należy najlepiej użyć
ApplicationServices
świadczone przezIApplicationBuilder
wConfigure()
metodzie:Możliwe jest przekazanie i bezpośrednie użycie
IServiceProvider
konstruktoraStartup
klasy, ale jak wyżej, będzie on zawierał ograniczony podzbiór usług , a zatem ma ograniczoną użyteczność:Jeśli musisz rozwiązać usługi w
ConfigureServices()
metodzie, wymagane jest inne podejście. Możesz zbudować półproduktIServiceProvider
zIServiceCollection
instancji, która zawiera usługi zarejestrowane do tego momentu :Uwaga: Zasadniczo należy unikać rozwiązywania usług w ramach
ConfigureServices()
metody, ponieważ w rzeczywistości jest to miejsce, w którym konfigurujesz usługi aplikacji. Czasami potrzebujesz tylko dostępu doIOptions<MyOptions>
instancji. Możesz to zrobić, wiążąc wartości zIConfiguration
instancji z instancjąMyOptions
(co jest zasadniczo tym, co robi struktura opcji):Usługi ręcznego rozwiązywania problemów (zwane też lokalizatorem usług) są ogólnie uważane za anty-wzór . Chociaż ma swoje przypadki użycia (dla frameworków i / lub warstw infrastruktury), powinieneś unikać go w jak największym stopniu.
źródło
IServiceCollection
wstrzyknąć, jakiejś klasy, która jest tworzona ręcznie ( poza średnim zakresem zastosowania ), w moim przypadku harmonogram, który okresowo potrzebuje pewnych usług do wygenerowania i wyślij e-mail.ConfigureServices
wewnątrz i ta usługa jest singletonem, będzie to inny singleton niż ten, któregoController
używasz! Przypuszczam, że to dlatego, że używa innegoIServiceProvider
- aby tego uniknąć NIE rozwiązać poprzezBuildServiceProvider
i zamiast przenieść odnośnika z Singleton odConfigureServices
doConfigure(..other params, IServiceProvider serviceProvider)
wStartup.cs
IServiceProvider
instancja, utworzy nową instancję singleton. Można tego uniknąć, zwracając instancję usługodawcy zConfigureServices
metody, która będzie również kontenerem używanym przez aplikację.collection.BuildServiceProvider();
było to, co potrzebne, dzięki!Ręczne rozwiązywanie instancji wymaga użycia
IServiceProvider
interfejsu:Rozwiązywanie zależności w Startup.ConfigureServices
Rozwiązywanie zależności w Startup.Configure
Rozwiązywanie zależności w Startup.Configure in ASP.NET Core 3
Korzystanie ze wstrzykiwanych usług Runtime
Niektóre typy można wstrzykiwać jako parametry metody:
Rozwiązywanie zależności w działaniach kontrolera
źródło
GetService
który jest ogólny, jest metodą rozszerzenia wMicrosoft.Extensions.DependencyInjection
przestrzeni nazw.Jeśli wygenerujesz aplikację z szablonem, będziesz mieć coś takiego w
Startup
klasie:Możesz tam dodać zależności, na przykład:
Jeśli chcesz uzyskać dostęp do
ITestService
kontrolera, możesz dodaćIServiceProvider
do konstruktora i zostanie on wstrzyknięty:Następnie możesz rozwiązać dodaną usługę:
Pamiętaj, że aby użyć wersji ogólnej, musisz dołączyć przestrzeń nazw do rozszerzeń:
ITestService.cs
TestService.cs
Startup.cs (ConfigureServices)
HomeController.cs
źródło
Jeśli potrzebujesz tylko rozwiązać jedną zależność w celu przekazania jej do konstruktora innej rejestrowanej zależności, możesz to zrobić.
Załóżmy, że masz usługę, która pobierała ciąg i usługę ISomeService.
Kiedy przejdziesz do rejestracji w Startup.cs, musisz to zrobić:
źródło
ISomeService
wciąż było dla mnie nieważne.W ten sposób można wstrzykiwać zależności w atrybutach takich jak AuthorizeAttribute
źródło
Wiem, że to stare pytanie, ale jestem zdumiony, że nie ma tu raczej oczywistego i obrzydliwego hacka.
Możesz wykorzystać możliwość zdefiniowania własnej funkcji ctor, aby pobrać niezbędne wartości z twoich usług podczas ich definiowania ... oczywiście będzie to uruchamiane za każdym razem, gdy usługa zostanie zamówiona, chyba że wyraźnie usuniesz / wyczyścisz i ponownie dodasz definicję usługa ta w ramach pierwszej konstrukcji wykorzystującego ctor .
Ta metoda ma tę zaletę, że nie wymaga budowania drzewa usługi ani korzystania z niego podczas konfigurowania usługi. Nadal definiujesz sposób konfigurowania usług.
Sposobem na naprawienie tego wzorca byłoby
OtherService
jawne uzależnienieIServiceINeedToUse
, a nie pośrednio zależność od niego lub wartości zwracanej przez jego metodę ... lub jawne rozwiązanie tej zależności w inny sposób.źródło
źródło