2015-05-01 37 views
18

ho iniziato ad imparare i cambiamenti in ASP.NET 5 (vNext) e non può trovare come ottenere IServiceProvider, ad esempio nel metodoIServiceProvider in ASP.NET Nucleo

public class Entity 
{ 
    public void DoSomething() 
    { 
      var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ? 
    } 
} 

lo so "Modello" 's, configuriamo i servizi all'avvio, ma dove rimane tutta la raccolta dei servizi o IServiceProvider?

risposta

1

Invece di ottenere il servizio in linea, provare a inserirlo nel costruttore.

public class Startup 
{ 
    public void ConfigureServices(IServiceCollection services) 
    { 
     services.AddTransient(typeof(DataContext)); 
    } 
} 

public class Entity 
{ 
    private DataContext _context; 

    public Entity(DataContext context) 
    { 
     _context = context; 
    } 

    public void DoSomething() 
    { 
     // use _context here 
    } 
} 

Ho anche suggerire lettura su ciò che AddTransient mezzi, in quanto avrà un impatto significativo su come le vostre azioni di applicazione istanze di DbContext. Questo è un modello chiamato Dependency Injection. Ci vuole un po 'per abituarsi, ma non vorrai mai tornare indietro una volta fatto.

+0

grazie per risposta, ma se ho molte entità ho bisogno di rewri te costruttori, e non posso usare Activator.CreateInstance, usando l'iniezione negli argomenti del metodo sembra brutto, puoi dirmi un buon patern con YAGNI che segue? – Sam

+0

Stai tentando di utilizzare Entity Framework? L'iniezione è usata nei costruttori, non nei metodi. Non sono sicuro di cosa intendi con YAGNI in questo contesto. – Anton

+0

Sì, sto utilizzando Entity Framework, ma guarda questo caso: Ho entità, ad esempio - Catalogo, e Catalogo hanno proprietà - Url, nel vecchio MVC posso solo creare wrapper httpcontext e usare l'helper dell'URL all'interno della proprietà , nel nuovo MVC non posso farlo, e non ho varianti tranne includere IUrlHelper in Method (aggiungendo il nuovo metodo wrapper su proprietà Path) per DRY, ma questo è ancora così strano – Sam

30

Dovete portare in Microsoft.Extensions.DependencyInjection namespace per ottenere l'accesso al

GetService<T>(); 

metodo di estensione generico che dovrebbe essere utilizzato su

IServiceProvider 

noti inoltre che è possibile iniettare direttamente servizi nei controller in ASP.NET 5. Vedi sotto l'esempio.

public interface ISomeService 
{ 
    string ServiceValue { get; set; } 
} 

public class ServiceImplementation 
{ 
    public ServiceImplementation() 
    { 
     ServiceValue = "Injected from Startup"; 
    } 

    public string ServiceValue { get; set; } 
} 

Startup.cs

public void ConfigureService(IServiceCollection services) 
{ 
    ... 
    services.AddSingleton<ISomeService, ServiceImplementation>(); 
} 

HomeController

using Microsoft.Extensions.DependencyInjection; 
... 
public IServiceProvider Provider { get; set; } 
public ISomeService InjectedService { get; set; } 

public HomeController(IServiceProvider provider, ISomeService injectedService) 
{ 
    Provider = provider; 
    InjectedService = Provider.GetService<ISomeService>(); 
} 

Entrambi gli approcci possono essere utilizzati per ottenere l'accesso al servizio. estensioni del servizio aggiuntivi per Startup.cs

AddInstance<IService>(new Service()) 

Una singola istanza viene dato tutto il tempo. Sei responsabile della creazione iniziale dell'oggetto.

AddSingleton<IService, Service>() 

Un'istanza singola viene creata e si comporta come un singleton.

AddTransient<IService, Service>() 

Una nuova istanza viene creata ogni volta che viene iniettata.

AddScoped<IService, Service>() 

Una singola istanza è creata all'interno della corrente richiesta HTTP portata. È equivalente a Singleton nel contesto di ambito corrente.

Aggiornato 13 ottobre 2016

See: aspnet GitHub - ServiceCollectionServiceExtensions.cs

+1

Questo non sembra funzionare in 'ASP.NET 5', che è l'OP. Forse mi manca qualcosa? –

+0

È cambiato da questo post. Se non mi sbaglio, questo era come di Beta 7? Questo è sicuramente in riferimento a ASP.NET 5. Hanno rinominato lo spazio dei nomi da Microsoft.Framework.DependencyInjection a Microsoft.Extensions.DependencyInjection. Ecco dove viene definita l'estensione GetService : https://github.com/aspnet/DependencyInjection/blob/dev/src/Microsoft.Extensions.DependencyInjection.Abstractions/ServiceProviderExtensions.cs –

+0

Hmmm ... appena provato: DNX 4.6 'utilizzando Microsoft.Extensions.DependencyInjection; 'e' GetService () '; restituisce l'errore, 'Il nome 'GetService' non esiste nel contesto corrente. –

2

Generalmente si desidera avere il DI fare la sua cosa e iniettare che per voi:

public class Entity 
{ 
    private readonly IDataContext dbContext; 

    // The DI will auto inject this for you 
    public class Entity(IDataContext dbContext) 
    { 
     this.dbContext = dbContext; 
    } 

    public void DoSomething() 
    { 
     // dbContext is already populated for you 
     var something = dbContext.Somethings.First(); 
    } 
} 

Tuttavia, Entity avrebbero dovuto essere istanziato automaticamente per te ...come un Controller o un ViewComponent. Se avete bisogno di creare un'istanza di questo da un luogo manualmente in cui questa dbContext non è disponibile per voi, allora si può fare questo:

using Microsoft.Extensions.PlatformAbstractions; 

public class Entity 
{ 
    private readonly IDataContext dbContext; 

    public class Entity() 
    { 
     this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider 
          .GetService(typeof(IDataContext)); 
    } 

    public void DoSomething() 
    { 
     var something = dbContext.Somethings.First(); 
    } 
} 

Ma proprio per sottolineare, questo è considerato un anti-modello e deve essere evitato a meno che assolutamente necessario. E ... a rischio di creare un modello che le persone siano davvero sconvolte ... se tutto il resto fallisce, è possibile aggiungere un static IContainer in una classe helper o qualcosa di simile e assegnarlo nella classe StartUp nel metodo ConfigureServices: MyHelper.DIContainer = builder.Build(); E questo è un modo davvero brutto per farlo, ma a volte hai solo bisogno di farlo funzionare.

3

Non credo sia una buona idea per un'entità (o un modello) avere accesso a qualsiasi servizio.

I controller, d'altra parte, hanno accesso a qualsiasi servizio registrato nei loro costruttori, e non devi preoccuparti di questo.

public class NotifyController : Controller 
{ 
    private static IEmailSender emailSender = null; 
    protected static ISessionService session = null; 
    protected static IMyContext dbContext = null; 
    protected static IHostingEnvironment hostingEnvironment = null; 

    public NotifyController(
       IEmailSender mailSenderService, 
       IMyContext context, 
       IHostingEnvironment env, 
       ISessionService sessionContext) 
    { 
     emailSender = mailSenderService; 
     dbContext = context; 
     hostingEnvironment = env; 
     session = sessionContext; 
    } 
} 
+0

Ora penso che sia troppo :) – Sam

3

uso GetRequiredService invece di GetService, come nell'esempio a tutorial ASP.NET core (https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql)

documentazione sul metodo:

https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_

using Microsoft.Extensions.DependencyInjection; 

     using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>())) 
Problemi correlati