我有一个问题,关于如何为多个客户设置一个项目。我们目前开发的是一个ASP Core应用程序。所有的客户端都使用相同的数据库结构,所以他们的数据库是相同的,只是填充的用户不同,... 我们目前使用一个publish,在IIS上设置了两个测试网站,每个publish都有一个不同的JSON配置文件,包含DB上下文(在Startp.cs处读出)。
我们这里的问题是,如果我们有多个客户端,就必须多次复制我们的publish来维护IIS的多个网站。我们没有找到一种方法,只用一个publish,并定义配置文件,以依赖连接客户端的URLport来使用。我们尝试了ASP Core下的租户教程,但在用户管理处失败了。
谁能告诉我,对于这种需要在IIS下发布一个共享的websitepublish,为每个客户端(URLport)提供不同的DB上下文,用户认证(我们使用了Identity)的webproject,什么是最好的解决方案。我们已经尝试了几个星期,但都没有成功。我们的主要问题是,DB上下文是在主机建立之前在Startup.cs中创建的,所以我们没有任何来自请求的URL,也不能在应用程序启动时创建一个特定的DB上下文。这意味着,我们无法填充UserStore,也无法让登录工作。我们知道我们可以建立一个包含所有用户和域的主表,但我们真的希望避免这种方法,因为我们不确定,如果网站将运行在同一台服务器上,或者如果一个客户可能使用他自己的公司内部服务器。
EDIT:我需要说得更具体一些,因为我犯了一个小错误。数据库是相同的。所以我实际上不需要不同的上下文类,而只是需要不同的连接字符串。但它们是在Startup.cs的AddDbContext函数中设置的。
EDIT2:我现在尝试了几个解决方案,我总是在Identity上失败。在Startup过程中没有直接创建DbContext的时候,好像就不行了,而且还崩溃了。
EDIT3: 由于我目前失败了,这里有一些来自我们项目的代码片段。
在我们的Startup.csConfigureServices(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();
});
在我们的Startup.csConfigure(...) - 我们设置了UseAuthorization
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;";
}
所以基本上我们所要实现的,就是为不同的urls建立不同的连接。比方说,我们有2个cients。
clientone.mysite.com:123 -> database_clientone
clienttwo.mysite.com:456 -> database_clienttwo
这是不可能的,因为我们在创建DbContext时没有域名。但是我们要求每个数据库都存储自己的登录凭证,而不是使用一个主表来存储每个现有用户数据库的所有登录信息......。
而且Identity似乎也不能在这种情况下工作。
如果你是在Core的DI中通过注册你的DB上下文 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文件。在上述情况下,你仍然会在Startup.cs中创建DbContext。
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,尝试使用注入DBContext lazily.Add一个类DataContext将实现DBContext。
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
}
}
在你的 的调用,而不是使用Startup.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中设置多个网站,使用相同的publishfile-文件夹,但不同的web.config文件。这也不行,至少我不知道如何实现这个目标......