Z biegiem czasu kontrolery rozwijają wiele zależności, a tworzenie instancji kontrolera staje się zbyt kosztowne dla każdego żądania (szczególnie z DI). Czy istnieje jakieś rozwiązanie, które sprawi, że kontroler będzie działał jako singleton?Jak uczynić kontroler jedną instancję na aplikację w ASP.NET MVC?
Odpowiedz
Tworzenie instancji kontrolerów to dość szybka i prosta operacja. To, co staje się zbyt drogie, tworzy zależności dla każdego żądania. Tak naprawdę potrzebujemy wielu kontrolerów, które dzielą te same instancje zależności.
E.g. masz następujące kontroler
public class SalesController : Controller
{
private IProductRepository productRepository;
private IOrderRepository orderRepository;
public SalesController(IProductRepository productRepository,
IOrderRepository orderRepository)
{
this.productRepository = productRepository;
this.orderRepository = orderRepository;
}
// ...
}
Należy skonfigurować zależność ram wtrysku do korzystania z tych samych wystąpień repozytoria dla wszystkich aplikacji (należy pamiętać, możesz mieć problemy z synchronizacją). Teraz tworzenie zależności nie jest już drogie. Wszystkie zależności są tworzone tylko raz i ponownie wykorzystywane dla wszystkich żądań.
Jeśli masz wiele zależności i martwisz się kosztami uzyskania odniesienia do instancji każdej zależności i dostarczeniem tych odwołań do instancji kontrolera (co nie wydaje mi się być bardzo drogie), możesz pogrupować zależności (coś takiego jak wprowadzenie refaktoryzacji obiektu parametrycznego):
public class SalesController : Controller
{
private ISalesService salesService;
public SalesController(ISalesService salesService)
{
this.salesService = salesService;
}
// ...
}
public class SalesService : ISalesService
{
private IProductRepository productRepository;
private IOrderRepository orderRepository;
public SalesService(IProductRepository productRepository,
IOrderRepository orderRepository)
{
this.productRepository = productRepository;
this.orderRepository = orderRepository;
}
// ...
}
Teraz masz pojedynczą zależność, która zostanie szybko wstrzyknięta. Jeśli skonfigurujesz strukturę zależności wtrysku w celu użycia pojedynczej usługi SalesService, wówczas wszystkie kontrolery będą ponownie używać tego samego wystąpienia usługi. Tworzenie kontrolerów i zapewnianie zależności będzie bardzo szybkie.
Bardzo dobry i szczegółowy aswer, dzięki!To moja ostatnia deska ratunku, jeśli nie ma rozwiązania [hack], aby kontrolerów singletons ... Zbyt dużo refaktoryzacji i xml-magic (używam wiosny) – 6opuc
na pewno problemy z synchronizacją będą zbyt wysokie cena do zapłaty – user195166
Więc pierwsza odpowiedź do pierwotnego pytania:
public void ConfigureServices(IServiceCollection services) {
// put other services bindings here
// bind all Controller classes as singletons
services.AddSingleton<HomeController, HomeController>();
// tell framework to obtain Controller instances from ServiceProvider.
services.AddMvc().AddControllersAsServices();
}
Jak podano w pierwotnym pytaniu, czy kontrolery mają duże drzewa z zależnościami, na które składają się głównie z życzeniem lunetą lub Transient zależności następnie tworząc je osobno dla każdego żądania mogą mieć trochę śladu na skalowalności twojej aplikacji (w Javie na przykład instancje Servleta są domyślnie z tego powodu domyślnie). O ile zwykle procesor i czas rzeczywisty potrzebny do utworzenia nawet dużego drzewa zależności są pomijalne (chyba że masz ciężkie obliczenia lub komunikację sieciową w konstruktorach swoich komponentów, co prawie nigdy nie jest dobrym pomysłem na przejściowe lub żądane komponenty), wykorzystanie pamięci ślad jest czymś, z czym trzeba się liczyć. W przypadku typowych aplikacji sieciowych DB-Web głównym czynnikiem ograniczającym liczbę współbieżnych żądań może obsłużyć jeden komputer-węzeł. Jeśli każde żądanie ma oddzielną kopię dużego drzewa zależności, razem mogą one zużywać znaczną ilość pamięci (inną rzeczą do oglądania jest początkowy rozmiar stosu dla nowego wątku, nawiasem mówiąc).
Przyjęta odpowiedź 1220560 rozwiązuje również problem, ale uważam to za brzydkie włamanie i ma pewne wady: musisz stworzyć tę sztuczną usługę singleton, która będzie używana przez Kontrolerów jako lokalizator usług lub proxy dla innych usług. Jeśli masz tylko jeden taki obiekt singletonowy dla wszystkich kontrolerów, to skutecznie ukrywasz rzeczywiste zależności kontrolera: na przykład, jeśli ktoś chce napisać test jednostkowy dla kontrolera, musi dokładnie przeanalizować jego implementację, aby zobaczyć, które zależności faktycznie są używa, aby wiedzieć, jakie drwiny/podróbki musi dostarczyć w konfiguracji testowej. Jeśli później zmienisz kontroler, a w wyniku zmiany podzestaw usług, których kontroler używa również zmian, bardzo łatwo jest zapomnieć o zaktualizowaniu ustawień testu. Może to czasami prowadzić do błędów, które trudno jest śledzić. W przeciwieństwie do tego, jeśli twoje zależności są jawnie zadeklarowane jako parametry konstruktora, natychmiast dostaniesz błąd kompilatora w konfiguracji testowej.Inną rzeczą, którą możesz zrobić, jest posiadanie oddzielnego, takiego singletonowego proxy/service locator dla każdego kontrolera, ale w zasadzie jest to dużo kłopotów.
Bez względu na to, czy korzystasz z rozwiązania zaproponowanego przeze mnie, czy też z odpowiedzi # 1220560, musisz być ostrożny przy wstrzykiwaniu wniosku Zależności Scoped na pojedyncze obiekty zgodnie z opisem w https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services na samym końcu "rejestracji własnych usług" " Sekcja. Możesz znaleźć możliwe rozwiązania tego problemu tutaj: how to use scoped dependency in a singleton in C#/ASP Kolejną rzeczą, na którą warto zwrócić uwagę, jest problem współbieżności: pojedyncze obiekty mogą być dostępne jednocześnie przez kilka wątków obsługujących różne jednoczesne żądania, więc upewnij się, że dodałeś odpowiednią synchronizację do dowolnych zasobów, które nie są wątkowane Twój singleton używa.
edit:
Właśnie zrealizowane oryginalne pytanie była o ASP.NET i ta odpowiedź jest dla ASP.NET Rdzenia, więc prawdopodobnie nie będzie działać dla "non-core".
- 1. Kontroler asynchroniczny w ASP.NET MVC
- 2. Jak zlokalizować aplikację ASP.NET MVC?
- 3. ASP.NET MVC 3 _Layout.cshtml Kontroler
- 4. Warunkowo wyłączyć kontroler ASP.NET MVC
- 5. Jak wyśmiać żądanie na kontroler w ASP.Net MVC?
- 6. Wiele projektów ASP.NET MVC, które tworzą pojedynczą aplikację ASP.NET MVC
- 7. Znajdź kontroler ASP.NET MVC w widoku głównym
- 8. Jak uruchomić tylko jedną instancję aplikacji
- 9. asp.net MVC częściowy kontroler widoku akcja
- 10. Zezwalaj tylko na jedną instancję aplikacji
- 11. Jak wywołać kontroler z przycisku kliknij w asp.net MVC 4
- 12. ASP.NET MVC 4 asynchroniczny kontroler oddzwaniania
- 13. angularjs $ http.post, asp.net mvc kontroler dostaje zerowy
- 14. Jak uzyskać dynamiczny kontroler i metodę działania w ASP.NET MVC?
- 15. ASP.net Kontroler MVC nie zwróci widoku
- 16. Jak uzyskać adres IP użytkownika w ASP.NET Kontroler API MVC
- 17. ASP.NET MVC czek na atrybut niestandardowy kontroler lub działania
- 18. Umieść aplikację ASP.NET MVC w podkatalogu głównej aplikacji MVC?
- 19. Jak testować kontroler ASP.NET MVC bez użycia wzorca repozytorium
- 20. Jak rozgrzać aplikację ASP.NET MVC w IIS 7.5?
- 21. Jak umieścić aplikację ASP.Net MVC 4 w kontroli źródła?
- 22. Jak ozdobić kontroler ASP.NET MVC za pomocą prostego wtryskiwacza
- 23. ASP.NET MVC - Pobierz bieżący kontroler i nazwę akcji w pomocniku
- 24. ASP.NET MVC na Mono
- 25. Wiele do wielu w widoku asp.net mvc i kontroler
- 26. Dynamiczny wybór JsonView na wiosnę Kontroler MVC
- 27. wildcards w asp.net tras mvc
- 28. ASP.NET MVC: Jak ukryć ActionResult na ciąg?
- 29. Jak uzyskać instancję "MvcApplication" w kontrolerze ASP.NET?
- 30. Backbone relacyjny - nie więcej niż jedną instancję ,,,
Możesz [utworzyć własną fabrykę kontrolerów] (http://www.dotnetcurry.com/ShowArticle.aspx?ID=878) łatwo ... ale czy pytasz o możliwe wady * używania * pojedynczych kontrolerów instancji ? – bzlm
Udało mi się już utworzyć pojedynczą instancję kontrolerów dla każdej aplikacji, ale to nie działa: "..Jeżeli używana jest fabryka kontrolerów niestandardowych, upewnij się, że tworzy ona nowe wystąpienie kontrolera dla każdego żądanie.' – 6opuc
Chociaż nic nie jest niemożliwe, sugeruję, że próba wdrożenia tego spowoduje więcej problemów niż odpowiedzi. Na przykład właściwość HttpContext instancji kontrolera jest oczywiście unikalna dla tego żądania. Najpierw prawdopodobnie wiele problemów, które możesz napotkać. – Mark