2 votes

Comment injecter un service dans ma classe DbContext et faire en sorte que host.MigrateDatabase() continue de fonctionner ?

J'ai une application EFCore, .NET5, Blazor WASM qui fonctionne. J'appelle await host.MigrateDatabase(); dans mon Program.Main() pour que ma base de données soit toujours à jour.

public static async Task<IHost> MigrateDatabase(this IHost host)
{
    using var scope = host.Services.CreateScope();
    try
    {
        // Get the needed context factory using DI:
        var contextFactory = scope.ServiceProvider.GetRequiredService<IDbContextFactory<AppDbContext>>();
        // Create the context from the factory:
        await using var context = contextFactory.CreateDbContext();
        // Migrate the database:
        await context.Database.MigrateAsync();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        throw;
    }
    return host;
}

Dans mon AppDbContext J'ai pris le dessus SaveChangesAsync() pour ajouter et mettre à jour CreatedOn at UpdatedOn . Je l'ai mentionné dans Les surcharges de DbContext.SaveChanges se comportent de manière inattendue avant. Je veux aussi remplir CreatedBy y UpdatedBy avec l'identifiant de l'utilisateur.

J'ai un IdentityOptions pour contenir les données de l'utilisateur :

public class IdentityOptions
{
    public string UserId => User.FindFirst(ClaimTypes.NameIdentifier)?.Value; 
    public ClaimsPrincipal User { get; set; }
}

J'ai enregistré cette classe dans StartUp comme ceci :

services.AddScoped(sp =>
{
    var context = sp.GetService<IHttpContextAccessor>()?.HttpContext;
    var identityOptions = new IdentityOptions();

    if (context?.User.Identity != null && context.User.Identity.IsAuthenticated)
    {
        identityOptions.User = context.User;
    }
    return identityOptions;
});

J'injecte ceci IdentityOptions dans plusieurs autres services, sans aucun problème.
Mais quand je l'injecte dans mon AppDbContext :

public AppDbContext(DbContextOptions<AppDbContext> options, IdentityOptions identityOptions)
    : base(options)
{
    ...
}

Je reçois une erreur dans MigrateDatabase() :
"Cannot resolve scoped service 'IdentityOptions' from root provider."

J'ai essayé de nombreuses options que j'ai trouvées sur Google, mais je n'ai pas trouvé de solution qui me convienne. Veuillez me conseiller.

Mise à jour :

services.AddDbContextFactory<AppDbContext>(
    options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection"),
            b => b.MigrationsAssembly("DataAccess"))
#if DEBUG
        .LogTo(Console.WriteLine, new [] {RelationalEventId.CommandExecuted})
        .EnableSensitiveDataLogging()
#endif
);

1voto

Paul Meems Points 604

Grâce à l'aide précieuse de @IvanStoev (encore une fois), j'ai trouvé la réponse.
Ajout de lifetime: ServiceLifetime.Scoped à AddDbContextFactory en Startup a résolu mon problème.
Maintenant, je peux utiliser ma classe IdentityOptions en SaveChanges et mettre automatiquement à jour mon Created* y Updated* propriétés.

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