如何从DbContextFactory类注入自定义服务



我试图在DbContext类中注入ICurrentUserServiceIDateTime服务:

public class BookDbContext : ApiAuthorizationDbContext<ApplicationUser>, IApplicationDbContext
{
private readonly ICurrentUserService _currentUserService;
private readonly IDateTime _dateTime;
public BookDbContext(DbContextOptions options, IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
public BookDbContext(DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions,
ICurrentUserService currentUserService,
IDateTime dateTime) : base(options, operationalStoreOptions)
{
_currentUserService = currentUserService;
_dateTime = dateTime;
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
foreach (Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<AuditableEntity> entry in ChangeTracker.Entries<AuditableEntity>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreatedBy = "b2c3196c-fbe7-473d-9a0f-b491f2918a6c";/// _currentUserService.UserId;
entry.Entity.Created = _dateTime.Now;
break;
case EntityState.Modified:
entry.Entity.LastModifiedBy = _currentUserService.UserId;
entry.Entity.LastModified = _dateTime.Now;
break;
}
}
var result = await base.SaveChangesAsync(cancellationToken);
return result;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
base.OnModelCreating(modelBuilder);
}
}

我正在实现DBContextFactory类为:

public class DBContextFactory : IDesignTimeDbContextFactory<BookDbContext>
{
public BookDbContext CreateDbContext(string[] args)
{

IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json").Build();
var builder = new DbContextOptionsBuilder<BookDbContext>();
var connectionString =
configuration.GetConnectionString("BookStoreDbConnection");
builder.UseSqlServer(connectionString);
return new BookDbContext(builder.Options, new OperationalStoreOptionsMigrations());
}
}
public class OperationalStoreOptionsMigrations : IOptions<OperationalStoreOptions>
{
public OperationalStoreOptions Value => new OperationalStoreOptions()
{
DeviceFlowCodes = new TableConfiguration("DeviceCodes"),
EnableTokenCleanup = false,
PersistedGrants = new TableConfiguration("PersistedGrants"),
TokenCleanupBatchSize = 100,
TokenCleanupInterval = 3600,
};
}

ICurrentUserService的实现,它在单独的项目中,其中Dbcontextfactory没有任何引用。

public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}

然而,我被困在如何传递另一个参数,即:ICurrentUserServiceIDateTime在运行时。

使用我当前的DbContext类实现,没有从DbContextFactory注入的其他服务将获得null。

对于这种情况有什么替代的解决方法?

如果我正确理解你的问题/请求,那么基本上你是试图设置CreatedBy和Created属性当你调用SaveChanges()时,当你添加一个实体或ModifiedBy和Modified当你更新一个实体。

就我个人而言,我觉得你可能过于复杂了,你可以通过在添加或更新时设置CreatedBy和Created属性或ModifiedBy和Modified属性来节省很多麻烦。我将保留DbContext,并实现Facade模式,这样您就可以将这些额外的服务注入构造函数或向SaveAsync()方法添加参数。

例如:

下面的实现将被注册为一个有作用域的开放通用服务,它可以被注入到任何地方,而不是另一个被注册为单例的服务。否则,您将得到一个运行时异常,通知您由于捕获的依赖关系而无法将有作用域的服务注入到Singleton中。

首先检查数据库中是否已经存在具有相同Id的实体。如果没有找到实体,那么你正在创建一个实体,否则你正在更新一个现有实体。

///Register with Dependency Injection
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IFacadeService<>), typeof(FacadeService<>));
}
///IFacadeService implementation
public interface IFacadeService<T> where T : EntityBase
{
Task<int> SaveAsync(T Entity);
///Other methods removed for brevity
}
public class FacadeService<T> : IFacadeService<T> where T : EntityBase
{
readonly DbContext ctx;
readonly DbSet<T> Dbset;
readonly IUserContext userContext;
readonly ICurrentDateTimeProvider dateTimeProvider;        
public FacadeService(
DbContext ctx,
IUserContext userContext,
ICurrentDateTimeProvider dateTimeProvider)
{
this.ctx = ctx;
Dbset = ctx.Set<T>();
this.userContext= userContext;
this.dateTimeProvider= dateTimeProvider;
}
public async Task<int> SaveAsync(T Entity)
{
var e = await Dbset
.AsNoTracking()
.FirstAsync(a => a.Id.Equals(Entity.Id));
if(e == null)
{
Entity.CreatedByUserId = userContext.CurrentUserId;
Entity.ModifiedByUserId = userContext.CurrentUserId;
Entity.CreatedDate = dateTimeProvider.CurrentDateTimeUTC;
Entity.ModifiedDate = dateTimeProvider.CurrentDateTimeUTC;
ctx.Add(Entity);
}
else
{
Entity.ModifiedByUserId = userContext.CurrentUserId;
Entity.ModifiedDate = dateTimeProvider.CurrentDateTimeUTC;
ctx.Update(Entity);
}
return ctx.SaveChanges();
}     
}

**从Repository编辑到Facade。

最新更新