ASP Core 3.1 多/备用数据库上下文



我有一个问题,关于如何为多个客户设置一个项目。我们目前正在开发一个ASP Core应用程序。所有客户端都使用相同的数据库结构,因此它们具有相同的数据库,只是填充了不同的用户,...我们目前使用一个发布,在 IIS 上设置两个测试网站,每个发布都有一个包含数据库上下文的不同 JSON 配置文件(在 Startp.cs 中读出(。

我们的问题是,如果我们有多个客户端,我们必须多次复制我们的发布,以维护 IIS 的多个网站。我们没有找到一种方法来只使用一个发布并根据连接的客户端的 URL/端口定义要使用的配置文件。我们尝试了ASP Core下的租赁教程,但在用户管理器中失败了。

有人可以指出我,这种 Web 项目的最佳解决方案是什么,它需要一个共享网站/在 IIS 下发布,每个客户端(URL/端口(的不同数据库上下文,用户身份验证(我们为此使用了 Identity(。我们尝试了几个星期,但未能使其正常工作。我们的主要问题是,数据库上下文是在构建主机之前在 Startup 中创建的.cs因此我们没有任何来自请求的 URL,并且无法在应用程序启动时创建特定的数据库上下文。这意味着,我们无法填充用户商店,也无法使登录工作。我们知道我们可以制作一个包含所有用户和域的主表,但我们真的想避免这种方法,因为我们不确定网站是否会在同一台服务器上运行,或者一个客户端是否可以使用他自己的内部公司服务器。

编辑:我需要更具体,因为我犯了一个小错误。数据库是相同的。所以我实际上不需要不同的上下文类,而只需要不同的连接字符串。但它们是在启动中设置的.cs在 AddDbContext 函数中......

编辑2:我现在尝试了一些解决方案,但我总是在身份上失败。当在启动期间没有直接创建 DbContext 时,它似乎不起作用并崩溃。

编辑3:由于到目前为止我失败了,这里有一些来自我们项目的代码片段

在我们的 Startup.cs/ConfigureServices(IServiceCollection services(

  • 我们正在从配置文件加载数据库设置
IConfigurationSection DbSection = Configuration.GetSection("Database");
  • 我们正在添加数据库上下文
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(MyDbContext.createConnectionString(DbSection), b => b.MigrationsAssembly("MyNamespace.DB").EnableRetryOnFailure()));
  • 并设置身份
services.AddScoped<Microsoft.AspNetCore.Identity.SignInManager<MyUser>, MySignInManager>();
services.AddScoped<Microsoft.AspNetCore.Identity.IUserStore<MyUser>, MyUserStore>();
services.AddScoped<Microsoft.AspNetCore.Identity.UserManager<MyUser>, Services.LogIn.MyUserManager>();
services.AddIdentity<MyUser, MyRole>()
.AddUserManager<MyUserManager>()
.AddUserStore<MyUserStore>()
.AddRoleStore<MyRoleStore>()
.AddDefaultTokenProviders();
  • 我们正在添加授权
services.AddAuthorization(options =>
{ options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});

在我们的启动.cs/配置(...( - 我们设置使用授权

app.UseAuthentication();
app.UseAuthorization();

在我们的 MyDbContext 类中,我们正在创建连接字符串

public static string createConnectionString(IConfigurationSection configurationSection)
{
return @"server=" + configurationSection.GetSection("Server").Value +
";database=" + configurationSection.GetSection("Database").Value +
";persist security info=True;user id=" + configurationSection.GetSection("User").Value +
";password=" + configurationSection.GetSection("Password").Value + ";multipleactiveresultsets=True;";
}

所以基本上我们想要实现的只是为不同的 url 建立不同的连接。假设我们有 2 个古人:

clientone.mysite.com:123 -> database_clientone
clienttwo.mysite.com:456 -> database_clienttwo

这是行不通的,因为我们在创建 DbContext 时没有域。但是我们需要让每个数据库存储它自己的登录凭据,而不是使用包含每个现有用户/数据库的所有登录名的主表......

而标识似乎也不适用于这种情况。

如果您通过调用向 Core 的 DI 注册数据库上下文AddDbContext则可以利用它的重载,从而为您提供对IServiceProvider的访问:

public void ConfigureServices(IServiceCollection services)
{
services
.AddEntityFrameworkSqlServer()
.AddDbContext<MyContext>((serviceProvider, options) =>
{
var connectionString = serviceProvider.GetService // get your service 
// which can determine needed connection string based on your logic
.GetConnectionString();
options.UseSqlServer(connectionString);
});
}

同样在这里,Autofac 也实现了类似的事情。

您可以有多个 appsettings.json 文件,并根据客户端加载适当的 json 文件。 在上述情况下,您仍将创建 Db 启动中的上下文.cs

public class ConfigurationService : IConfigurationService
{

public IConfiguration GetConfiguration()
{
var env = GetCurrentClient();//You can also set environment variable for client
CurrentDirectory = CurrentDirectory ?? Directory.GetCurrentDirectory();
return new ConfigurationBuilder()
.SetBasePath(CurrentDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
.AddJsonFile($"appsettings.{env}.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables()
.Build();

}
}

不要使用AddDbContext,而是尝试懒惰地使用 inject DBContext。 添加一个将实现DBContext的类DataContext

public class DataContext : DbContext
{
public DataContext(IConfigurationService configService)
: base(GetOptions( GetConnectionString())
{
this.ChangeTracker.LazyLoadingEnabled = true;
}

private static DbContextOptions GetOptions(string connectionString)
{
return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
}

public static string GetConnectionString()
{
//Your logic to read connection string by host
// This method will be called while resolving your repository
}
}

启动中.cs删除 AddDbContext(( 调用 而是使用

public void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddScoped<DbContext, YourDBContext>();
//likewise Addscope for your repositories and other services
//Code to build your host
}

控制器构造函数或服务构造函数中的 DI DbContext

由于您的 DBContext 现在正在延迟加载,您将能够根据主机决定连接字符串。

希望这对你有用!!

我尝试通过web.config创建一个环境变量,并在我们的应用程序中读出它。但是我找不到一种方法,如何在IIS7中使用相同的发布/文件夹设置多个网站,但使用不同的web.config文件。这也不起作用,或者至少我不知道如何实现这一目标......

最新更新