[英]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.