webentwicklung-frage-antwort-db.com.de

IServiceProvider in ASP.NET Core

Ich fange an, Änderungen in ASP.NET 5(vNext) .__ zu lernen und kann nicht finden, wie IServiceProvider zum Beispiel in der Methode "Model" abgerufen wird

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

Ich weiß, wir konfigurieren Dienste beim Start, aber wo bleiben alle Services oder IServiceProvider?

27
Sam

Sie müssen einen Microsoft.Extensions.DependencyInjection-Namespace hinzufügen, um Zugriff auf das Generic zu erhalten

GetService<T>();

erweiterungsmethode, die für verwendet werden soll 

IServiceProvider 

Beachten Sie auch, dass Sie Dienste direkt in Controller in ASP.NET 5 injizieren können. Siehe Beispiel unten.

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

public class ServiceImplementation : ISomeService
{
    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>();
}

Beide Ansätze können verwendet werden, um auf den Dienst zuzugreifen. Zusätzliche Serviceerweiterungen für Startup.cs

AddInstance<IService>(new Service())

Eine einzige Instanz ist immer gegeben. Sie sind für die anfängliche Objekterstellung verantwortlich.

AddSingleton<IService, Service>()

Eine einzelne Instanz wird erstellt und verhält sich wie ein Singleton.

AddTransient<IService, Service>()

Bei jeder Injektion wird eine neue Instanz erstellt.

AddScoped<IService, Service>()

Innerhalb des aktuellen HTTP-Request-Bereichs wird eine einzelne Instanz erstellt. Im aktuellen Geltungsbereich entspricht es Singleton.

Aktualisiert am 18. Oktober 2018 

Siehe: aspnet GitHub - ServiceCollectionServiceExtensions.cs

46
Jaime Still

Ich glaube nicht, dass es für eine Entität (oder ein Modell) eine gute Idee ist, auf einen Dienst zuzugreifen. 

Controller hingegen haben Zugriff auf alle registrierten Dienste in ihren Konstruktoren, und Sie müssen sich nicht darum kümmern.

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;
    }
}
4

Im Allgemeinen möchten Sie, dass der DI sein Ding macht und das für Sie injiziert:

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();
     }
}

Entity müsste jedoch automatisch für Sie instanziiert werden ... wie eine Controller oder eine ViewComponent. Wenn Sie dies manuell von einem Ort aus instanziieren müssen, an dem diese dbContext nicht verfügbar ist, können Sie Folgendes tun:

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();
     }
}

Aber nur um es zu betonen, wird dies als Anti-Muster betrachtet und sollte vermieden werden, es sei denn, es ist absolut notwendig. Und ... auf die Gefahr hin, dass einige Muster wirklich verärgert werden ... Wenn alles andere fehlschlägt, können Sie einen static IContainer in einer Hilfsklasse oder etwas hinzufügen und ihn in Ihrer StartUp-Klasse in der ConfigureServices-Methode zuordnen: MyHelper.DIContainer = builder.Build(); Und das ist ein wirklich hässliche Art, es zu tun, aber manchmal muss es nur funktionieren.

2
Serj Sagan

Anstatt Ihren Service inline zu erhalten, versuchen Sie, ihn in den Konstruktor zu injizieren.

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
    }
}

Ich schlage auch vor, etwas über die Bedeutung von AddTransient zu erfahren, da dies erhebliche Auswirkungen darauf haben wird, wie Ihre Anwendung Instanzen von DbContext gemeinsam nutzt. Dies ist ein Muster, das als Dependency Injection bezeichnet wird. Es dauert eine Weile, bis man sich daran gewöhnt hat, aber Sie werden nie wieder zurück wollen.

1
Anton

Ich denke, das OP wird verwirrt. Entitäten sollten so dünn wie möglich sein. Sie sollten versuchen, keine Logik und/oder externe Verweise außer Navigationseigenschaften zu enthalten. Suchen Sie nach gängigen Mustern wie dem Repository-Muster, das Ihre Logik von den Entitäten selbst abstrahiert

0
Robert Perry