如何在我的 DbContext class 中注入服务并使 host.MigrateDatabase() 仍然有效
How to inject a service in my DbContext class and have host.MigrateDatabase() still working
我有一个有效的 EFCore、.NET5、Blazor WASM 应用程序。
我在 Program.Main()
中调用 await host.MigrateDatabase();
让我的数据库始终保持最新状态。
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;
}
在我的 AppDbContext
中,我覆盖了 SaveChangesAsync()
以添加和更新 CreatedOn
en UpdatedOn
。
我之前在 中提到过这个。
我还想用 userId 填充 CreatedBy
和 UpdatedBy
。
我有一个 IdentityOptions
class 来保存用户数据:
public class IdentityOptions
{
public string UserId => User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
public ClaimsPrincipal User { get; set; }
}
我已经在 StartUp 中这样注册了 class:
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;
});
我将这个 IdentityOptions
class 注入到其他几个服务中,没有任何问题。
但是当我将它注入我的 AppDbContext
:
public AppDbContext(DbContextOptions<AppDbContext> options, IdentityOptions identityOptions)
: base(options)
{
...
}
我在 MigrateDatabase()
中遇到错误:
"Cannot resolve scoped service 'IdentityOptions' from root provider."
我一直在尝试使用谷歌搜索发现的多种选择,但找不到适合我的解决方案。
请指教
更新:
services.AddDbContextFactory<AppDbContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection"),
b => b.MigrationsAssembly("DataAccess"))
#if DEBUG
.LogTo(Console.WriteLine, new [] {RelationalEventId.CommandExecuted})
.EnableSensitiveDataLogging()
#endif
);
感谢@IvanStoev(再次)的大力帮助,我找到了答案。
在 Startup
中将 lifetime: ServiceLifetime.Scoped
添加到 AddDbContextFactory
解决了我的问题。
现在我可以在 SaveChanges
中使用我的 IdentityOptions class 并自动更新我的 Created*
和 Updated*
属性。
我有一个有效的 EFCore、.NET5、Blazor WASM 应用程序。
我在 Program.Main()
中调用 await host.MigrateDatabase();
让我的数据库始终保持最新状态。
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;
}
在我的 AppDbContext
中,我覆盖了 SaveChangesAsync()
以添加和更新 CreatedOn
en UpdatedOn
。
我之前在 CreatedBy
和 UpdatedBy
。
我有一个 IdentityOptions
class 来保存用户数据:
public class IdentityOptions
{
public string UserId => User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
public ClaimsPrincipal User { get; set; }
}
我已经在 StartUp 中这样注册了 class:
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;
});
我将这个 IdentityOptions
class 注入到其他几个服务中,没有任何问题。
但是当我将它注入我的 AppDbContext
:
public AppDbContext(DbContextOptions<AppDbContext> options, IdentityOptions identityOptions)
: base(options)
{
...
}
我在 MigrateDatabase()
中遇到错误:
"Cannot resolve scoped service 'IdentityOptions' from root provider."
我一直在尝试使用谷歌搜索发现的多种选择,但找不到适合我的解决方案。 请指教
更新:
services.AddDbContextFactory<AppDbContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection"),
b => b.MigrationsAssembly("DataAccess"))
#if DEBUG
.LogTo(Console.WriteLine, new [] {RelationalEventId.CommandExecuted})
.EnableSensitiveDataLogging()
#endif
);
感谢@IvanStoev(再次)的大力帮助,我找到了答案。
在 Startup
中将 lifetime: ServiceLifetime.Scoped
添加到 AddDbContextFactory
解决了我的问题。
现在我可以在 SaveChanges
中使用我的 IdentityOptions class 并自动更新我的 Created*
和 Updated*
属性。