所以,我的问题是,“是否可以根据过滤器中的meta更改每个请求的连接?
我的问题与此one有点类似,但附加的扭曲是每个数据库是相同的。
谢谢你, 斯蒂芬
编辑:如果内存正确地为我服务,我认为mythz之前我已经讨论过这个问题,并且发现即使我们能够改变ADO连接,那么IAuthRepository也是如此破碎。所以这不可行。
答案 0 :(得分:4)
我添加了一个示例Multi Tenant test,显示了我首选的方法,我将使用自定义IDbConnectionFactory
包装器,以便更好地查看和控制正在创建的Db连接,即:
public class MultiTenantDbFactory : IDbConnectionFactory
{
private readonly IDbConnectionFactory dbFactory;
public MultiTenantDbFactory(IDbConnectionFactory dbFactory)
{
this.dbFactory = dbFactory;
}
public IDbConnection OpenDbConnection()
{
var tenantId = RequestContext.Instance.Items["TenantId"] as string;
return tenantId != null
? dbFactory.OpenDbConnectionString(GetConnectionString(tenantId))
: dbFactory.OpenDbConnection();
}
public IDbConnection CreateDbConnection()
{
return dbFactory.CreateDbConnection();
}
}
我还希望将主 dbFactory
单例实例用作非租户请求的默认值,该非租户请求还指定要使用的Dialect Provider:
var dbFactory = new OrmLiteConnectionFactory(
AppSettings.GetString("MasterDb"), SqlServerDialect.Provider);
container.Register<IDbConnectionFactory>(c =>
new MultiTenantDbFactory(dbFactory));
为了表明服务是特定于租户的,我只是创建一个自定义界面:
public interface IForTenant
{
string TenantId { get; }
}
DTO可以实施哪些请求来表明他们特定于租户的请求,即:
public class GetTenant : IForTenant, IReturn<GetTenantResponse>
{
public string TenantId { get; set; }
}
可以在整个ServiceStack's Request pipeline中轻松检测到,例如全局请求过滤器,以提取请求的租户并将其添加到RequestContext,例如:
GlobalRequestFilters.Add((req, res, dto) =>
{
var forTennant = dto as IForTenant;
if (forTennant != null)
RequestContext.Instance.Items.Add("TenantId", forTennant.TenantId);
});
然后MultiTenantDbFactory
可以读回来并打开与所需租户的Db连接:
var tenantId = RequestContext.Instance.Items["TenantId"] as string;
return new OrmLiteConnectionFactory(GetConnectionStringFor(tenantId))
.OpenDbConnection()
只要有人访问其服务或依赖项中的base.Db
,就会使用该文件。
答案 1 :(得分:3)
此方法使用全局请求筛选器来确定发出请求的人,并将连接字符串设置为请求项。然后,当IoC尝试解析IDbConnectionFactory
时,它将检索该请求的连接字符串并建立数据库连接。
public override void Configure(Container container)
{
// Tell the IoC to get the database connection factory on each request
container.Register<IDbConnectionFactory>(c => GetDatabaseConnectionFactory()).ReusedWithin(ReuseScope.Request);
// Create a filter that will determine the tenant and set the appropriate connection string
GlobalRequestFilters.Add((req,res,obj) => {
// Determine the connection string based on the some parameter you know about the tenant.
var dbConnectionString = ...
// Use a default value if the tenant was unknown
var defaultConnectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
// Save the connection string to the RequestContext.Items collection, so we can read it later
HostContext.RequestContext.Items.Add("ConnectionString", dbConnectionString ?? defaultConnectionString);
});
}
// This method returns the correct database connection to the request
public static IDbConnectionFactory GetDatabaseConnectionFactory()
{
// Read the connection string from our Items
var dbConnectionString = HostContext.RequestContext.Items["ConnectionString"];
if(dbConnectionString == null)
throw new Exception("Connection string has not been set");
// Return the connection factory for the given connection string
return new OrmLiteConnectionFactory(dbConnectionString, SqlServerOrmLiteDialectProvider.Instance));
}
如果您还使IoC在每个请求上动态解析连接字符串,那么在进行身份验证时将使正确的存储库可用。
container.Register<IUserAuthRepository>(c =>
new OrmLiteAuthRepository(GetDatabaseConnectionFactory())).ReusedWithin(ReuseScope.Request);
我希望有所帮助。