web-dev-qa-db-fra.com

ASP.NET Core 2 + Obtenir une instance du contexte db

J'essaie d'obtenir une instance de DbContext (donc je peux faire un travail supplémentaire au démarrage avec lui), j'obtiens l'erreur suivante lorsque j'essaie d'obtenir une instance dans la méthode Configure:

System.InvalidOperationException: 'Impossible de résoudre le service de portée' MyApp.Data.MyDbContext 'du fournisseur racine.'

public void ConfigureServices(IServiceCollection services)
{
 services.AddDbContext<MyDbContext>(
                options => options.UseSqlServer(Configuration.GetConnectionString("MyDbContext")));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

    var dbContext = app.ApplicationServices.GetService(typeof(MyDbContext)) as MyDbContext;
}

Je peux accéder à une instance de l'amende DbContext via le contrôleur, etc.

18
TheWebGuy

Le commentaire de Paul Hiles est correct mais cette méthode fonctionne mieux dans .NET Core 1.0.

Dans ASP.NET Core 2.0, c'est généralement une mauvaise idée d'exécuter une configuration de base de données dans Startup.cs. En effet, si vous exécutez des migrations à partir de la CLI ou de Visual Studio, il exécutera tous les Startup.cs et essayez d'exécuter votre configuration qui échouera. Bien sûr, si vous n'utilisez pas Entity-Framework, ce n'est pas un problème, mais ce n'est toujours pas la manière recommandée de le faire dans 2.0. Il est maintenant recommandé de le faire dans Program.cs.

Par exemple, vous pouvez créer une méthode d'extension de IWebHost qui exécutera toute configuration dont vous avez besoin.

public static IWebHost MigrateDatabase(this IWebHost webHost)
{
    var serviceScopeFactory = (IServiceScopeFactory)webHost.Services.GetService(typeof(IServiceScopeFactory));

    using (var scope = serviceScopeFactory.CreateScope())
    {
        var services = scope.ServiceProvider;
        var dbContext = services.GetRequiredService<YourDbContext>();

        dbContext.Database.Migrate();
    }

    return webHost;
}

Et puis dans Program.cs vous pouvez ensuite appeler cette méthode avant de l'exécuter.

public static void Main(string[] args)
{
    BuildWebHost(args)
        .MigrateDatabase()
        .Run();
}
29
Travis Boatman

Mise à jour pour Core 2.1 et ultérieur

Juste pour ajouter à @ Travis Boatman excellente réponse, la syntaxe préférée de la méthode Main a légèrement modifiée à partir de Core 2.1 et la valeur par défaut Main la méthode a désormais CreateWebHostBuilder au lieu de BuildWebHost.

Le code révisé pour appeler la méthode d'extension est indiqué ci-dessous.

NB: l'ordre est important ici, la méthode Build renvoie un WebHost, qui est ce que la méthode d'extension étend, vous devez donc appeler la méthode migrate après Build() et avant Run()):

public static void Main(string[] args)
{
    CreateWebHostBuilder(args)
        .Build()
        .MigrateDatabase()
        .Run();
}

Migration de plusieurs DbContext

Nous avons plus d'un DbContext dans notre projet, j'ai donc changé la méthode d'extension en une méthode générique qui peut prendre n'importe quel type de DbContext:

public static IWebHost MigrateDatabase<T>(this IWebHost webHost) where T:DbContext
{
    var serviceScopeFactory = (IServiceScopeFactory)webHost
        .Services.GetService(typeof(IServiceScopeFactory));

    using (var scope = serviceScopeFactory.CreateScope())
    {
        var services = scope.ServiceProvider;

        var dbContext = services.GetRequiredService<T>();
        dbContext.Database.Migrate();
    }

    return webHost;
}

Vous pouvez ensuite chaîner les appels pour migrer les différents contextes:

CreateWebHostBuilder(args)
    .Build()
    .MigrateDatabase<ApiAuthDbContext>()
    .MigrateDatabase<MainDbContext>()
    .MigrateDatabase<SomeOtherDbContext>()
    .Run();
3
tomRedox