I controller nel tempo sviluppano molte dipendenze e la creazione di un'istanza di controller diventa troppo costosa per ogni richiesta (in particolare con DI). C'è qualche soluzione per rendere single i controllori?Come rendere il controller una singola istanza per applicazione in ASP.NET MVC?
risposta
Creazione di istanze di controller è un'operazione abbastanza veloce e semplice. Ciò che diventa troppo costoso è la creazione di dipendenze per ogni richiesta. Quindi, quello di cui hai veramente bisogno sono molti controller che condividono le stesse istanze di dipendenze.
E.g. hai seguente controller
public class SalesController : Controller
{
private IProductRepository productRepository;
private IOrderRepository orderRepository;
public SalesController(IProductRepository productRepository,
IOrderRepository orderRepository)
{
this.productRepository = productRepository;
this.orderRepository = orderRepository;
}
// ...
}
Si dovrebbe configurare il quadro di iniezione di dipendenza affinché utilizzi le stesse istanze di repository per tutte le applicazioni (tenere a mente, si possono avere problemi di sincronizzazione). Ora la creazione di dipendenze non è più costosa. Tutte le dipendenze vengono create un'istanza solo una volta e riutilizzate per tutte le richieste.
Se si hanno molte dipendenze e ci si preoccupa dei costi per ottenere il riferimento all'istanza di ciascuna dipendenza e fornire questi riferimenti all'istanza del controller (che non credo sarà molto costosa), è possibile raggruppare le proprie dipendenze (qualcosa di simile a introdurre dei parametri oggetto refactoring):
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;
}
// ...
}
Ora avete dipendenza da un unico, che sarà iniettato molto rapidamente. Se si configura il framework di distribuzione delle dipendenze per utilizzare Singleton SalesService, tutti i SalesControllers riutilizzeranno la stessa istanza di servizio. La creazione di controller e la fornitura di dipendenze sarà molto veloce.
Molto buono e dettagliato, grazie!È la mia ultima risorsa se non ci sono soluzioni [hack] per rendere singleton controller ... Troppo refactoring e xml-magic (sto usando spring) – 6opuc
sicuramente i problemi di sincronizzazione saranno troppo alti per pagare – user195166
Quindi, prima una risposta alla domanda iniziale:
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();
}
Come indicato nella domanda iniziale, se i controllori hanno grandi alberi di dipendenza costituiti principalmente da richiesta Scoped o transitori dipendenze creando poi separatamente per ogni richiesta può avere un po 'di spazio sulla scalabilità della tua applicazione (in Java ad esempio le istanze Servlet sono singletons di default esattamente per questo motivo). Mentre solitamente la CPU e il tempo reale necessari per creare anche un albero di grandi dimensioni sono trascurabili (a meno che non si abbiano calcoli pesanti o comunicazioni di rete nei costruttori dei componenti, che non è quasi mai una buona idea per i componenti transitori o richiesti), l'utilizzo della memoria l'impronta è qualcosa su cui contare. Nel caso delle comuni app di DB-Web, la memoria è il principale fattore che limita il numero di richieste simultanee che un singolo nodo macchina può gestire. Se ogni richiesta ha una copia separata di un grande albero delle dipendenze, insieme possono consumare una quantità significativa di memoria (l'altra cosa da tenere in considerazione è la dimensione iniziale dello stack per un nuovo thread, a proposito).
La risposta accettata 1220560 risolve anche il problema, ma lo considero un brutto attacco e presenta alcuni inconvenienti: è necessario creare questo servizio singleton artificiale che verrà utilizzato dai controller come localizzatore di servizi o proxy per altri servizi. Se si dispone di un solo oggetto singleton per tutti i controller, si nascondono effettivamente dipendenze reali del controller: ad esempio se qualcuno desidera scrivere un test unitario per il controller, deve analizzare attentamente la sua implementazione per vedere quali dipendenze effettivamente usa, in modo che sappia quali falsi/falsi ha bisogno di fornire nella sua configurazione di prova. Se in un secondo momento si modifica il controller e, a seguito della modifica del sottoinsieme di servizi, il controller utilizza anche le modifiche, è molto facile dimenticare di aggiornare anche l'installazione di prova. Questo a volte può portare a bug difficili da tracciare. Contrariamente a ciò, se le vostre dipendenze sono dichiarate esplicitamente come parametri del costruttore, otterrete subito un errore del compilatore nella configurazione del test.Un'altra cosa che puoi fare è avere un proxy singleton/localizzatore di servizi separato per ogni controller, ma in fondo è un sacco di problemi.
Indipendentemente dal fatto che si utilizzi la soluzione proposta da me o quella dalla risposta n. 1220560, è necessario prestare attenzione durante l'iniezione della richiesta delle dipendenze scopate in oggetti singleton come descritto in https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services proprio alla fine della "registrazione dei propri servizi" " sezione. Puoi trovare le possibili soluzioni a questo problema qui: how to use scoped dependency in a singleton in C#/ASP Un'altra cosa da tenere a mente è il problema della concorrenza: è possibile accedere contemporaneamente agli oggetti singleton da più thread che gestiscono richieste concorrenti diverse, quindi assicurati di aggiungere la sincronizzazione corretta a qualsiasi risorsa non thread-safe usa il tuo singleton.
edit:
Ho appena realizzato la domanda iniziale era di circa ASP.NET e questa risposta è per ASP.NET core, in modo che probabilmente non funzionerà per "non-core".
- 1. Più progetti ASP.NET MVC che vengono creati come applicazione ASP.NET MVC singola
- 2. Controller asincrono in ASP.NET MVC
- 3. MVC 4 Pagina singola Applicazione e DateTime
- 4. asp.net mvc controller generico
- 5. Creazione di una singola istanza per system tray in java
- 6. Esempio di applicazione MS per ASP.NET MVC?
- 7. ASP.NET MVC - Mock Membership per Controller Test
- 8. pass dizionario per controller asp.net mvc
- 9. Passando serie Javascript per ASP.NET MVC controller
- 10. ASP.NET MVC controller azioni design
- 11. ASP.NET MVC 4 Applicazione chiamata WebAPI remota
- 12. ASP.NET MVC Controller aggiungendo disabilitato
- 13. Esempio di applicazione aziendale per ASP.NET MVC?
- 14. librerie utili per asp.net mvc applicazione
- 15. Test controller unità ASP.NET MVC con HttpContext
- 16. Impossibile ottenere il controller ASP.NET MVC 6 per restituire JSON
- 17. ASP.Net MVC Controller Namespace array
- 18. ASP.NET MVC 3 _Layout.cshtml Controller
- 19. Passing informazioni tra controller in ASP.Net MVC-
- 20. Fabbrica controller ASP.NET MVC 6
- 21. Come si chiude una pagina MVC ASP.NET dal controller?
- 22. modifica convenzione nome controller in ASP.NET MVC
- 23. Asp.net MVC controller per accettare il valore o null
- 24. Deserializzare oggetti JSON in controller MVC Asp.Net
- 25. Come impostare il timeout della richiesta per un'azione del controller in un'applicazione asp.net mvc
- 26. Applicazione multilingue in ASP.NET MVC: best practice?
- 27. ASP.NET MVC - Respository/Service/Controller
- 28. Controller MVC IoC e ASP.NET
- 29. Visualizzare una vista da un altro controller in ASP.NET MVC
- 30. StructureMap fabbrica controller e istanza di controllo nullo in MVC
È possibile [creare il proprio factory controller] (http://www.dotnetcurry.com/ShowArticle.aspx?ID=878) facilmente ... ma si stanno chiedendo i possibili svantaggi di * utilizzando * controller a istanza singola ? – bzlm
In effetti, ho già realizzato la "istanza singola per controller" dei miei controllori, ma non funziona: "..Se è in uso un controller personalizzato, assicurati che crei una nuova istanza del controller per ogni richiesta.' – 6opuc
Mentre nulla è impossibile, suggerisco che provare ad implementare ciò causerebbe più problemi che risposte. Ad esempio, la proprietà HttpContext di un'istanza di un controller è ovviamente unica per quella richiesta. Innanzitutto probabilmente molti problemi che potresti incontrare. – Mark