[英]Dependency Injection of services into an Entity Framework Core database context
我一直在尝试使用DI将服务注入到我的数据库上下文中。 例如,用于审核日志记录的User Resolver服务。 我对ChangeTracker进行了扩展,以审计创建,修改和删除的属性,还具有审计记录器,用于记录实体的已更改属性。 为了使它们有效且无缝地工作,我需要确定已登录的用户。 在EF Core 1.1中,我可以通过将IUserResolverService添加到构造函数中来完成此工作。
当我尝试升级到2.0时,由于工具无法处理扩展的构造函数,我开始遇到各种问题。 我最终将其删除,所有内容开始工作,但是没有确定登录用户的可靠方法。
我现在尝试在许多场合找到答案,并且搜索仅发现了大量关于将上下文本身注入到控制器之类的文章。
是否可以在EF Core中实现而无需破坏工具等? 是否有通过Startup ConfigureServices注入服务的方法?
我遇到了非常相似的情况。 我最终只是在Startup中手动注入了它,但仍然解决了依赖性。 我不喜欢这个,希望将这些服务注入DbContext构造函数中。 这是我下面的解决方案:
public interface IUserContextProvider {
User GetCurrentUser();
}
public class MvcUserContextProvider : IUserContextProvider {
protected IHttpContextAccessor Accessor { get; set; }
public MvcUserContextProvider(IHttpContextAccessor accessor) {
Accessor = accessor;
}
public User GetCurrentUser() {
// Probably need some error handling and Special case pattern when
// context is null.
return (User) Accessor.HttpContext.User.Identity;
}
}
public interface IEntityFrameworkOverrides {
void EntityInitializing(ModelBuilder modelBuilder, IMutableEntityType entity);
void EntityChanged(EntityEntry entity);
}
public abstract class UserAwareOverride : IEntityFrameworkOverrides {
protected IUserContextProvider UserProvider { get; private set; }
protected UserAwareOverride(IUserContextProvider userProvider)
{
UserProvider = userProvider;
}
public abstract void EntityInitializing(ModelBuilder modelBuilder, IMutableEntityType entity);
public abstract void EntityChanged(EntityEntry entity);
}
public class ApplicationContext : IdentityDbContext<User> {
private static bool ConfigurOverridesSet = false;
protected static readonly List<IEntityFrameworkOverrides> EFOverrides = new List<IEntityFrameworkOverrides>();
public static void ConfigureOverrides(IEnumerable<IEntityFrameworkOverrides> overrides) {
if (ConfigurOverridesSet) {
throw new NotSupportedException("Cannot set overrides on SplitFamContext More than once.");
}
EFOverrides.AddRange(overrides);
ConfigurOverridesSet = true;
}
public ApplicationContext(DbContextOptions<ApplicationContext> options)
:base(options) { }
}
然后在Startup中,我只是这样做了:
public IServiceProvider ConfigureServices(IServiceCollection services) {
services.AddMvc();
var builder = new ContainerBuilder();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IUserContextProvider, MvcUserContextProvider>();
services.AddDbContext<ApplicationContext>(options => {
options.UseNpgsql(
Configuration.GetConnectionString("ApplicationContext"));
});
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders();
builder.Populate(services);
this.ApplicationContainer = builder.Build();
// Create the IServiceProvider based on the container.
return new AutofacServiceProvider(this.ApplicationContainer);
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IApplicationLifetime appLifetime) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
var userContexProvider = app.ApplicationServices.GetService<IUserContextProvider>();
ApplicationContext.ConfigureOverrides(new List<IEntityFrameworkOverrides>(){
new SoftDeleteOverrides(userContexProvider),
new TrackCreatedOverride(userContexProvider),
new TrackModifiedOverride(userContexProvider)
});
appLifetime.ApplicationStopped.Register(() => {
this.ApplicationContainer.Dispose();
});
}
可能需要一些调整,但我不喜欢它,但是在您可以将服务注入DbContext之前,它可能是一种解决方法。
您可以使用的另一种方法是像在旧版本的MVC中那样获取静态HttpContext。 在此处找到解决方案: https : //www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/
我仍然还没有尝试过Thread.CurrentPrincipal.Identity,也不知道有什么问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.