我正在尝试从请求URL获取数据库名称,因为我有多个数据库
所以,我有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?
你的方法不符合设计。我会解释原因。
这是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已经提供了一种动态确定运行时连接字符串的方法。
HttpContext.Current
和其他请求特定信息显然只有在代码处理请求时才可用。
很可能你是在没有请求处理的情况下初始化你的类,即使它显然需要按请求处理,因为它使用请求的信息来选择连接字符串。合理的解决方法是将SaaSZeroDbContext
的生命周期与控制器的生命周期保持一致(即,通过DI框架注入每个请求对象的SaaSZeroDbContext
)。
即使你认为你正在处理请求,当上下文不可用时还有另一种选择 - 使用ConfirgureAwiat(false)
将在调用后失去对请求对象的访问权限,但它看起来还不是那么远。
安全说明:确保用户无法通过url实际提供连接字符串,而是提供代码提示要使用的现有连接字符串。允许用户控制连接字符串(如?dbname=FooBar
)是一个巨大的安全问题(阅读“SQL注入”了解更多信息)。