[英]IoC DI for multitenant DbContext with .Net Core Identity
我有.Net Core应用,并想使用.Net Core Identity为DbContext设置IoC / DI:
public class DataContext : IdentityDbContext<User, IdentityRole<int>, int, IdentityUserClaim<int>, IdentityUserRole<int>, IdentityUserLogin<int>, IdentityRoleClaim<int>, IdentityUserToken<int>>, IDataContext
{
private readonly string _dbName;
public DataContext(string dbName)
{
this._dbName = dbName;
}
public virtual DbSet<Container> Containers { get; set; }
public virtual DbSet<Note> Notes { get; set; }
public virtual DbSet<Post> Posts { get; set; }
public virtual DbSet<Email> Emails { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(ConnectionStrings.DataContext.Replace(":dbname", this._dbName));
base.OnConfiguring(optionsBuilder);
}
}
接口:
public interface IDataContext
{
DbSet<Container> Containers { get; set; }
DbSet<Note> Notes { get; set; }
DbSet<Post> Posts { get; set; }
DbSet<Email> Emails { get; set; }
}
在Startup.cs
,有以下一行:
services.AddDbContext<DataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DataContext")));
但是该连接字符串不包含数据库名称。
我是否应该在界面中包含以下表格:AspNetUsers,AspNetRoles,...?
我想在Startup.cs
编写如下内容:
services.AddScoped<IDataContext, DataContext>();
并在各处使用接口,而不是整个类。
我可以那样做吗? 我该怎么办?
当您使用实体框架的AddDbContext
方法时,它将为您注册服务集合中的上下文。
services.AddDbContext<DataContext>(ServiceLifetime.Scoped);
但是您可以像下面这样注册您的界面。
services.AddScoped(typeof(IDataContext), provider => provider.GetService<DataContext>());
然后,您可以使用该界面。 但是身份服务仍将使用具体类型。
PS:您知道存储库模式吗? 它使您可以轻松地将数据层与服务层分开。 例如,这对于单元测试很有帮助。
您的DataContext
构造函数的问题在于,依赖项容器不知道如何解析构造函数中的字符串。 通常,当您在asp.net core中使用配置时,可以使用IOptions
类型及其基础结构。
在启动中,您可以添加选项并进行配置。
public class DatabaseOptions
{
public string DbName { get; set; }
}
services.AddOptions();
services.Configure<DatabaseOptions>(options => options.DbName = "myDbName");
然后,您可以将DataContext
的构造函数更改为以下内容。
public DataContext(IOptions<DatabaseOptions> options)
如果您在启动时不知道配置值,则可以编写一个在中间件或操作过滤器中配置的上下文类型。
public class DbConfigurationContext
{
public string DbName { get; set; }
}
public class DbConfigurationContextFilter : IAsyncActionFilter
{
private readonly DbConfigurationContext _dbConfiguration;
public DbConfigurationContextFilter(DbConfigurationContext dbConfiguration)
{
_dbConfiguration = dbConfiguration;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
_dbConfiguration.DbName = context.HttpContext.Request.Query["DbName"];
await next();
}
}
services.AddTransient<DbConfigurationContext>();
services.AddTransient<DbConfigurationContextFilter>();
services.AddMvc(setup =>
{
setup.Filters.AddService(typeof(DbConfigurationContextFilter));
})
然后,您可以在DbConfigurationContext
中解析此DbContext
。 当然,您也可以使用界面。
public DataContext(DbConfigurationContext configurationContext)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.