4 votes

Utilisez InMemoryDatabase avec UseInternalServiceProvider. Aucun fournisseur de base de données configuré

Je rencontre des difficultés à injecter un IAsyncQueryProvider personnalisé lors de l'utilisation d'EntityFrameworkCore. Pour être plus précis.. j'ai des difficultés à injecter le fournisseur lors de l'utilisation de la fonctionnalité de base de données en mémoire fournie. En utilisant un fournisseur par défaut (SqlServer), tout fonctionne bien.

Voici mon Startup.cs global

private void ConfigureEntityFrameworkWithSecurity(IServiceCollection services)
{
    services
        .AddEntityFramework()
        .AddEntityFrameworkSqlServer()
        .AddScoped()
        .AddDbContext((sp, options) =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
                .UseInternalServiceProvider(sp);
        });
}

Cela fonctionne à merveille, et je peux mettre un point d'arrêt à l'intérieur de CustomEntityProvider pour vérifier qu'il est effectivement injecté. Pour l'instant, CustomEntityProvider implémente simplement IAsyncQueryProvider, et transmet simplement la demande. Il n'y a aucune logique contenue à l'intérieur.

Lorsque je lance un test, je configure le webhost pour utiliser un fichier Startup différent:

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env) : base(env)
    {
    }

    public override void ConfigureServices(IServiceCollection services)
    {
        services
            .AddDbContext((sp, options) =>
            {
                options.UseInMemoryDatabase()
                    .UseInternalServiceProvider(sp);
            });
        base.ConfigureServices(services);
    }
}

Lancer un test avec TestStartup génère l'erreur :

System.InvalidOperationException : Aucun fournisseur de base de données n'a été configuré pour ce DbContext. Un fournisseur peut être configuré en remplaçant la méthode DbContext.OnConfiguring ou en utilisant AddDbContext sur le fournisseur de services de l'application. Si AddDbContext est utilisé, assurez-vous également que votre type DbContext accepte un objet DbContextOptions dans son constructeur et le passe au constructeur de base pour DbContext.

Et APIContext est correctement défini:

public class APIContext : DbContext
{
    public APIContext(DbContextOptions options)
        : base(options)
    {
    }
    ...
}

Retirer UseInternalServiceProvider de TestStartup fonctionne correctement - cependant, je ne veux pas que mes tests touchent une base de données réelle. De plus, je m'attends à ce que UseInMemoryDatabase injecte automatiquement les dépendances dans le fournisseur de services - car cela fonctionne parfaitement tout seul.

L'erreur est déroutante car la base de données en mémoire est le fournisseur que je veux utiliser.

5voto

Rob Points 2095

Malheureusement, la solution est d'une simplicité déconcertante. Cependant, il semble y avoir très peu de documentation sur l'utilisation de l'injection de dépendances avec la fonctionnalité de base de données en mémoire. Il semble que ce soit l'un ou l'autre. Espérons que cette question apportera de l'aide aux futures personnes assez malchanceuses pour rencontrer ce problème.

J'ai téléchargé la source EntityFramework pour enquêter et j'ai trouvé que l'appel à UseInMemoryDatabase crée une extension InMemoryOptionsExtension qui va ajouter au fournisseur de services, à savoir :

public virtual void ApplyServices(IServiceCollection services)
{
    Check.NotNull(services, nameof(services));

    services.AddEntityFrameworkInMemoryDatabase();
}

Et la solution est aussi simple qu'elle en a l'air :

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env) : base(env)
    {
    }

    public override void ConfigureServices(IServiceCollection services)
    {
        services
            .AddEntityFrameworkInMemoryDatabase()
            .AddDbContext((sp, options) =>
            {
                options.UseInMemoryDatabase().UseInternalServiceProvider(sp);
            });
        base.ConfigureServices(services);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X