我试图从请求网址获取数据库名称,因为我有多个数据库
所以,我有x1.com,x2.com和x3.com我想让DbContext从运行时的url生成连接字符串
我做的是那个
public SaaSZeroDbContext()
: base(GetConnectionStringFromUrl())
{
}
//function to get the connection string
private static string GetConnectionStringFromUrl()
{
var url = HttpContext.Current.Request.Url;
string connectionString = @"Data Source=.\MSSQLSERVER2016; Database={DatabaseName}; Integrated Security=True;MultipleActiveResultSets=True";
var databaseName = ""; // you should extract the database name from url here
connectionString = connectionString.Replace("{DatabaseName}", databaseName);
return connectionString;
}
但是我收到错误HttpContext.Current为null,为什么HttpContext.Current为null?
答案 0 :(得分:1)
你的方法不符合设计。我会解释原因。
这是模板附带的DbContext:
public class AbpProjectNameDbContext : AbpZeroDbContext<Tenant, Role, User>
{
//TODO: Define an IDbSet for your Entities...
/* NOTE:
* Setting "Default" to base class helps us when working migration commands on Package Manager Console.
* But it may cause problems when working Migrate.exe of EF. If you will apply migrations on command line, do not
* pass connection string name to base classes. ABP works either way.
*/
public AbpProjectNameDbContext()
: base("Default")
{
}
/* NOTE:
* This constructor is used by ABP to pass connection string defined in AbpProjectNameDataModule.PreInitialize.
* Notice that, actually you will not directly create an instance of AbpProjectNameDbContext since ABP automatically handles it.
*/
public AbpProjectNameDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
//This constructor is used in tests
public AbpProjectNameDbContext(DbConnection existingConnection)
: base(existingConnection, false)
{
}
public AbpProjectNameDbContext(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{
}
}
ABP在这里使用第二个构造函数(AbpProjectNameDbContext(string nameOrConnectionString)
),如评论中所述。默认构造函数仅在您使用PMC时使用,例如执行update-database。
所以,你应该添加一个像
这样的构造函数public SaaSZeroDbContext(string nameOrConnectionString)
: base(GetConnectionStringFromUrl())
{
}
此ctor将由ABP调用,但您忽略nameOrConnectionString并动态生成它。没关系。但仍有问题。当您使用PMC命令(如update-database)时,HttpContext.Current将为null。因为此执行不在HTTP上下文中。另外,在单元测试中没有HttpContext.Current等等。
因此,即使HttpContext.Current为null,您的GetConnectionStringFromUrl()方法也应该能够工作。如果它为null,则可以返回默认连接字符串,例如。
虽然这种方法可行,但我不建议这样做。 ASP.NET Boilerplate已经提供了一种动态确定运行时连接字符串的方法。
创建一个实现IConnectionStringResolver的新类。您可以从DefaultConnectionStringResolver派生您的类,也可以重写GetNameOrConnectionString方法。因此,如果HttpContext.Current为null并且您的代码回退到默认实现,则可以调用base.GetNameOrConnectionString。
将IConnectionStringResolver替换为您自己的实现documented here。
答案 1 :(得分:0)
HttpContext.Current
和其他请求特定信息显然是可用的。
您很可能在没有请求处理的情况下初始化您的类,即使它显然需要按请求处理,因为它使用请求的信息来选择连接字符串。合理的解决方法是将SaaSZeroDbContext
的生命周期与控制器的生命周期保持一致(即,通过DI框架注入每个请求对象SaaSZeroDbContext
)。
当上下文不可用时,即使您认为自己正在处理请求,也有另一种选择 - 使用ConfirgureAwiat(false)
会在调用后失去对请求对象的访问权限,但它看起来还不是那么远。
安全说明:确保用户无法通过url实际提供连接字符串,而是提供代码提示要使用的现有连接字符串。允许用户控制连接字符串(如?dbname=FooBar
)是一个巨大的安全问题(有关更多信息请参阅“SQL注入”)。