19

Ho un repository generico nel mio progetto. Si consideri il seguente frammento di codice di controlloRepository generico in ASP.NET Core senza avere una riga AddScoped separata per tabella in Startup.cs?

public class Lookup1Controller : Controller 
{ 
    readonly MyDbContext _db; 

    public Lookup1Controller(MyDbContext dataContext) 
    { 
     _db = dataContext; 
    } 

    public async Task<IActionResult> Index() 
    { 

     IGenericRepository<Lookup1> _repository = new GenericRepository<Lookup1>(_db); 
     var lookup1s = await _repository.SelectAll(); 

     return View(lookup1s); 
    } 

non vedo la necessità di avere il mio riferimento del database sia nel mio repository generico così come ciascuno dei miei controllori.

ho refactoring a:

public class Lookup1Controller : Controller 
{ 
    private IGenericRepository<Lookup1> _repository; 

    public Lookup1Controller(IGenericRepository<Lookup1> repository) 
    { 
     _repository = repository; 
    } 

    public async Task<IActionResult> Index() 
    { 
     var lookup1s = await _repository.SelectAll(); 

     return View(lookup1s); 
    } 

} 

che è molto più ordinato e ASP.NET 5 migliori pratiche da quanto ho letto. ma mi metterò il seguente errore se accedo quell'itinerario controllore in mio browser:

InvalidOperationException: Unable to resolve service for type 'MyProject.Data.IGenericRepository`1[MyProject.Models.Lookup1]' while attempting to activate 'MyProject.Controllers.Lookup1. 

a causa della non ho iniettato il GenericRepository utilizzare l'interfaccia.

aggiungo alla mia Startup.cs una linea AddScoped per ogni dei miei tavoli nel ConfigureServices metodo

services.AddScoped<IGenericRepository<Lookup1>,GenericRepository<Lookup1>>(); 
services.AddScoped<IGenericRepository<Lookup2>,GenericRepository<Lookup2>>(); 
services.AddScoped<IGenericRepository<Lookup3>,GenericRepository<Lookup3>>(); 
services.AddScoped<IGenericRepository<Lookup4>,GenericRepository<Lookup4>>(); 
etc 

modo che il mio codice viene eseguito senza un'eccezione.

Tuttavia il mio database ha circa 100 tabelle di ricerca semplici. Quando guardo le 100 linee di codice di cui sopra, non sembra giusto.

Sembra un codice copia e incolla. Ogni volta che aggiungo una nuova tabella aggiungendo un nuovo modello e controller con vista il mio codice verrà compilato senza darmi un errore. Ma se eseguo il programma e vado a quella vista, potrei ottenere l'errore di esecuzione del controller se ho dimenticato di aggiungere la riga AddScoped al mio Startup.cs. Non proprio buono per la mantenibilità.

La mia domanda:

  1. E 'davvero le migliori pratiche per avere una services.AddScoped per ogni tabella di ricerca nel metodo di Startup.csConfigureServices?

  2. È un repository generico, quindi non c'è un modo per scrivere quelle 100 righe copia e incolla in una riga?

  3. In caso contrario, qual è il modo migliore per farlo utilizzando il mio codice?

+0

Si utilizza il costruttore di 'Lookup1Controller' con' IGenericRepository '* come parametro *:' public Lookup1Controller (repository IGenericRepository ) '. Quindi ti aspetti che * MVC chiami * il costruttore di controller 'Lookup1Controller' con il parametro corrispondente.Chi dovrebbe rendere 'new GenericRepository >()'? Si dovrebbe fare questo una volta o ad ogni chiamata di azione 'Index'? Quindi avete scelta tra 'services.AddTransient',' services.AddScoped', 'services.AddSingleton' e' services.AddInstance'. – Oleg

+0

È un sistema CRUD di base. Quindi c'è Crea. Aggiorna, elimina i metodi che ho omesso. Usare AddScoped sembra essere il modo standard per farlo Vedi: http: //wildermuth.com/2015/3/17/A_Look_at_ASP_NET_5_Part_3_-_EF7. Se c'è un modo migliore per favore condividi. – devc2

risposta

39

basta usare la sovraccarichi di registrazione non generici poi fornire la open generic types sia l'interfaccia e l'implementazione (quelli in cui è necessario passare i 2 Type oggetti.):

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>)); 

Nella tua Controller aggiungere una dipendenza per un repository di un tipo specifico (un tipo generico chiuso)

public HomeController(IGenericRepository<Lookup1> repository) 
{ 
    ... 
} 
+0

Grazie. La modifica della riga di codice funziona. Aspetterò per vedere se altri danno input se è una buona pratica o no per un'app ASP.net 5 o fornisce alterantives – devc2

+0

Il modo in cui sono registrati è lo stesso di altri contenitori DI come [Ninject] (http://stackoverflow.com)/a/10243699/1836935) o [Unity] (https://msdn.microsoft.com/en-us/library/ff660936 (v = pandp.20) .aspx # Anchor_0). Vediamo se qualcuno è a conoscenza di qualche trucco con il contenitore integrato in ASP .Net 5 –

+3

Questo non funziona per me. Ho ricevuto questo errore: fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [0] Si è verificata un'eccezione non gestita: impossibile risolvere il servizio per tipo 'SqlExpress.Repository.Interfaces.IChatRepository' durante il tentativo di attivare 'SqlExpress.Helpers.LessonTagHelper'. System.InvalidOperationException: impossibile risolvere il servizio per il tipo 'SqlExpress.Repository.Interfaces.IChatRepository' durante il tentativo di attivare 'SqlExpress.Helpers.LessonTagHelper'. a ... – Beetlejuice

Problemi correlati