C# ASP Core 3.1多个/交替数据库上下文

C# ASP Core 3.1多个/交替数据库上下文,c#,asp.net-core,iis-7,C#,Asp.net Core,Iis 7,我有一个问题,关于如何为多个客户建立一个项目。我们目前正在开发一个ASP核心应用程序。所有客户端都使用相同的数据库结构,因此它们有相同的数据库,只是填充了不同的用户,。。。我们目前使用一个发布,在IIS上设置了两个测试网站,每个发布都有一个包含DB上下文的不同JSON配置文件(在Startp.cs读取) 我们这里的问题是,如果我们有多个客户端,我们必须复制我们的发布多次,以便为IIS维护多个网站。我们没有找到一种方法,仅使用一次发布,并根据所连接客户端的URL/端口定义要使用的配置文件。我们尝试

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

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

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

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

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

EDIT3:由于我到目前为止失败了,下面是我们项目中的一些代码片段

在我们的Startup.cs/ConfigureServices(IServiceCollection服务)中

  • 我们正在从配置文件加载数据库设置
  • 我们正在添加数据库上下文
在我们的Startup.cs/Configure(…) -我们设定了使用授权

    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建立不同的连接。假设我们有两位科学家:

clientone.mysite.com:123 -> database_clientone
clienttwo.mysite.com:456 -> database_clienttwo
这不起作用,因为我们在创建DbContext时没有域。但是我们需要让每个数据库存储它自己的登录凭据,而不是使用一个主表来存储每个现有用户/数据库的所有登录


而Identity似乎也不适用于此场景。

您可以有多个appsettings.json文件,并根据客户端加载相应的json文件。 在上述情况下,您仍将创建Db Startup.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
调用向Core的DI注册DB上下文,您可以利用它的重载来访问:

public void配置服务(IServiceCollection服务)
{
服务
.AddEntityFrameworkSqlServer()
.AddDbContext((服务提供者,选项)=>
{
var connectionString=serviceProvider.GetService//获取您的服务
//它可以根据您的逻辑确定所需的连接字符串
.GetConnectionString();
使用SQLServer(connectionString);
});
}

Autofac也实现了类似的功能。

不要使用AddDbContext,而是尝试惰性地使用InjectDBContext。 添加将实现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
        }

    }
在您的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
}

public void配置服务(IServiceCollection服务集合)
{
serviceCollection.addScope();
//同样,为您的存储库和其他服务添加范围
//用于构建主机的代码
}
控制器构造函数或服务构造函数中的DI DbContext

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


希望这对你有用

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

尝试将DB上下文初始化为所采取的第一个操作(使用像OnActionExecuting这样的方法)。然后,从那里你可以选择正确的数据库,使用端口/ip或任何你需要的过滤器我认为我的问题是误导。实际上,我不需要多个DB上下文类,因为它们都是相同的。我只需要不同的连接字符串到(或者相同的)数据库。在这种情况下,您可以有多个appsettings.json,并根据客户端加载适当的json。您还可以在加载appsettings.json时设置环境变量并读取相应的客户端。更新我的答案以满足您的要求。希望这有帮助!!我具体在哪里设置?到目前为止,我找不到任何对我有帮助的东西。我需要类似“if”(Request.Host.url==…)的内容,但在启动时,主机始终为空,因此我无法确定当前运行的是哪个域/端口。主机get是在启动后在host.Run()方法中创建的。但是现在注册DbContext已经太晚了,因为在Startup类中的这一行之前就已经注册了。在我的program.cs中,标识发生在host.Run()之前,这意味着它将无法工作(如果有)
clientone.mysite.com:123 -> database_clientone
clienttwo.mysite.com:456 -> database_clienttwo
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();



        }
    }
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);
               });
       }
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
        }

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