C# 使用通用存储库和IoC在运行时更改数据库
我正在开发一个N层web应用程序,它为每个客户机使用一个数据库,带有简单的IoC注入器和通用存储库模式 当我尝试更改db连接时,我发现注入器在Glopal中的应用程序启动中运行。asax中,我仍然无法确定当前用户是谁来设置连接字符串,我需要在运行时而不是应用程序启动中进行更改,有什么想法吗C# 使用通用存储库和IoC在运行时更改数据库,c#,repository-pattern,simple-injector,C#,Repository Pattern,Simple Injector,我正在开发一个N层web应用程序,它为每个客户机使用一个数据库,带有简单的IoC注入器和通用存储库模式 当我尝试更改db连接时,我发现注入器在Glopal中的应用程序启动中运行。asax中,我仍然无法确定当前用户是谁来设置连接字符串,我需要在运行时而不是应用程序启动中进行更改,有什么想法吗 我的存储库类的示例 public class Repository<T> : IRepository<T> where T : BaseEntity { private re
我的存储库类的示例
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private readonly IDBContext _context;
private IDbSet<T> _entities;
public Repository(IDBContext context)
{
_context = context;
}
private IDbSet<T> Entities
{
get
{
if (_entities == null)
{
_entities = _context.Set<T>();
}
return _entities;
}
}
}
公共类存储库:IRepository其中T:BaseEntity
{
私有只读IDBContext _context;
私有IDbSet_实体;
公共存储库(IDBContext上下文)
{
_上下文=上下文;
}
私有IDbSet实体
{
得到
{
如果(_entities==null)
{
_实体=_context.Set();
}
返回实体;
}
}
}
DbContext类的示例
public class DBContext: DbContext, IDBContext
{
public DBContext()
: base("Name=DbConnectionString")
{
Database.SetInitializer<DBContext>(null);
}
//public DBContext(ConnectionStr connection)
// : base(connection.conn)
//{
// Database.SetInitializer<DBContext>(null);
//}
public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
{
return base.Set<TEntity>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(
type =>
type.BaseType != null && type.BaseType.IsGenericType &&
type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
base.OnModelCreating(modelBuilder);
}
}
公共类DBContext:DBContext,IDBContext
{
公共DBContext()
:base(“Name=DbConnectionString”)
{
Database.SetInitializer(null);
}
//公共DBContext(ConnectionStr连接)
//:底座(连接.连接)
//{
//Database.SetInitializer(null);
//}
public new IDbSet Set(),其中tenty:BaseEntity
{
返回base.Set();
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
var typesToRegister=Assembly.getExecutionGassembly().GetTypes()
.Where(type=>!String.IsNullOrEmpty(type.Namespace))
.在哪里(
类型=>
type.BaseType!=null&&type.BaseType.IsGenericType&&
type.BaseType.GetGenericTypeDefinition()==typeof(EntityTypeConfiguration));
foreach(TypeStoreRegister中的变量类型)
{
dynamic configurationInstance=Activator.CreateInstance(类型);
modelBuilder.Configurations.Add(configurationInstance);
}
基于模型创建(modelBuilder);
}
}
您将遇到一个问题-您如何知道用户对他们选择的任何数据库都有效 他们是否从下拉列表中选择数据库,然后输入凭据?(可能是个坏主意)您是否有具有用户名//密码//数据库映射的主数据库 一旦你明白了这一点,一种方法就是重写web.config中的连接字符串。我不太喜欢这个想法
更好的方法是在创建数据库上下文时传递连接字符串:您将遇到一个问题-您如何知道用户对他们选择的任何数据库都有效 他们是否从下拉列表中选择数据库,然后输入凭据?(可能是个坏主意)您是否有具有用户名//密码//数据库映射的主数据库 一旦你明白了这一点,一种方法就是重写web.config中的连接字符串。我不太喜欢这个想法
更好的方法是在创建DB上下文时传递连接字符串:首先,这里会有一个严重的问题,因为要这样做,您必须知道每个用户的密码,或者以某种方式使其简单明了。我不确定是否能做到。如果可以,下面的代码将为您提供一个良好的起点 如果您仍然想这样做,您需要一个UserContext服务,它从HttpContext返回当前用户。并由此构建您的连接字符串 这可能或应该是这样的:
public interface IUserContext
{
string CurrentUser { get; }
}
public class HttpUserContext : IUserContext
{
public string CurrentUser
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
public class ConnectionStringFactory
{
private readonly IUserContext userContext;
private readonly string partialConnectionString;
public ConnectionStringFactory(
IUserContext userContext,
string partialConnectionString)
{
this.userContext = userContext;
this.partialConnectionString = partialConnectionString;
}
public string GetConnectionString()
{
var builder = new SqlConnectionStringBuilder(partialConnectionString);
builder.UserID = this.userContext.CurrentUser;
return builder.ConnectionString;
}
}
//register like this
var connectionStringFactory = new ConnectionStringFactory(
new HttpUserContext(),
"yourconnectionString");
container.RegisterSingle(connectionStringFactory);
container.RegisterPerWebRequest<YourDbContext>(() =>
{
var connectionFactory = container.GetInstance<ConnectionStringFactory>();
var entityConnectionString = connectionFactory.GetConnectionString;
return new YourDbContext(entityConnectionString);
});
公共接口IUserContext
{
字符串CurrentUser{get;}
}
公共类HttpUserContext:IUserContext
{
公共字符串当前用户
{
获取{return HttpContext.Current.User.Identity.Name;}
}
}
公共类连接字符串工厂
{
私有只读IUserContext userContext;
私有只读字符串partialConnectionString;
公共连接字符串工厂(
IUserContext用户上下文,
字符串部分连接字符串)
{
this.userContext=userContext;
this.partialConnectionString=partialConnectionString;
}
公共字符串GetConnectionString()
{
var builder=new-SqlConnectionStringBuilder(partialConnectionString);
builder.UserID=this.userContext.CurrentUser;
返回builder.ConnectionString;
}
}
//像这样登记
var connectionStringFactory=新的connectionStringFactory(
新建HttpUserContext(),
“您的连接字符串”);
容器注册表单(连接字符串工厂);
container.RegisterWebRequest(()=>
{
var connectionFactory=container.GetInstance();
var entityConnectionString=connectionFactory.GetConnectionString;
返回新的YourDbContext(entityConnectionString);
});
注意:对于实体框架,您可能需要调整ConnectionFactory
更好的解决方案是将集成安全性与SQL server结合使用,并让应用程序池模拟当前用户
更好的方法是使用单个用户帐户(AppPool标识)连接到数据库,并通过向模型中添加一些额外的表来控制应用程序中的身份验证,并在
IRepository
界面上添加类似于IAuthorizedRepository
的内容。请看一下关于这个主题的讨论:首先,您在这里会遇到一个严重的问题,因为要做到这一点,您必须知道每个用户的密码,或者以某种方式使其简单明了。我不确定是否能做到。如果可以,下面的代码将为您提供一个良好的起点
如果您仍然想这样做,您需要一个UserContext服务,它从HttpContext返回当前用户。并由此构建您的连接字符串
这可能或应该是这样的:
public interface IUserContext
{
string CurrentUser { get; }
}
public class HttpUserContext : IUserContext
{
public string CurrentUser
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
public class ConnectionStringFactory
{
private readonly IUserContext userContext;
private readonly string partialConnectionString;
public ConnectionStringFactory(
IUserContext userContext,
string partialConnectionString)
{
this.userContext = userContext;
this.partialConnectionString = partialConnectionString;
}
public string GetConnectionString()
{
var builder = new SqlConnectionStringBuilder(partialConnectionString);
builder.UserID = this.userContext.CurrentUser;
return builder.ConnectionString;
}
}
//register like this
var connectionStringFactory = new ConnectionStringFactory(
new HttpUserContext(),
"yourconnectionString");
container.RegisterSingle(connectionStringFactory);
container.RegisterPerWebRequest<YourDbContext>(() =>
{
var connectionFactory = container.GetInstance<ConnectionStringFactory>();
var entityConnectionString = connectionFactory.GetConnectionString;
return new YourDbContext(entityConnectionString);
});
公共互联网