【问题标题】:如何从 ASP.Net Core 中的 SqlServerDBContextOptionsExtensions 获取连接字符串
【发布时间】:2017-05-01 08:44:47
【问题描述】:

我正在构建一个 ASP.Net Core API,但我无法找到从 DBContextOptions 获取连接字符串的方法。

我的 startup.cs 中有 DBContext,如下所示;

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddEntityFrameworkSqlServer()
        .AddDbContext<MainContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MainConnection")));

    services.AddMvc()
       .AddJsonOptions(opt =>
        {
            opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        });
}

在我的 Context 类中,我有以下构造函数;

public MainContext(DbContextOptions<MainContext> options) : base(options)
{

}

但是除非我在DBContext类,OnConfiguring方法中添加一个实际的连接字符串,否则它不起作用,如下图;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    //TODO Move connection string to a secure location
    optionsBuilder.UseSqlServer(@"Server= .....");

}

当我调试并检查 Configuration.GetConnectionString("MainConnection") 中的值时,我可以看到 Startup.cs 正在从 appsettings.json 文件中获取正确的连接字符串。

我认为通过 DI 将选项传递给 DbContext 类会传递连接字符串,但 DbContect 类不起作用,除非我在 OnConfiguring 方法中有 optionBuilder.UseSqlServer()。

我发现了这个 SO 帖子 https://stackoverflow.com/questions/33532599/asp-net-5-multiple-dbcontext-problems,它谈到了使用以下代码从选项属性中提取连接字符串

public ResourceDbContext(DbContextOptions options) : base(options)
{
    _connectionString = ((SqlServerOptionsExtension)options.Extensions.First()).ConnectionString;
}


protected override void OnConfiguring(DbContextOptionsBuilder options)
{
    options.UseSqlServer(_connectionString);
}  

但是当我尝试使用它时,发现options.Extensions中已经没有First()方法了

所以,我的第一个问题是……

为什么不用在 OnConfiguring 方法中添加连接字符串,DBContext 类就不能工作

我的第二个问题是……

如果 OnCONfiguring 方法中需要连接字符串,我如何从 DbContextOptions 选项对象中获取它,而不必在 OnConfiguring 方法中显式提供它 --> optionsBuilder.UseSqlServer(@"Server= .... .");

【问题讨论】:

    标签: c# asp.net-core asp.net-core-mvc entity-framework-core asp.net-core-middleware


    【解决方案1】:

    在您的appsettings.json 中,您将创建以下内容:

    {
         "Database" : {
              "ConnectionString" : "..."
          }
    }
    

    然后在您的ConfigureServices 中,您将执行以下操作:

    services.AddSingleton(_ => Configuration);
    

    这基本上会填充IConfigurationRoot 属性。您可以在任何地方注入,并可以通过以下方式访问连接字符串:

    private readonly IConfigurationRoot configuration;
    private IDbConnection dbConnection { get; }
    
    public Example(IConfigurationRoot configuration)
    {
         this.Configuration = configuration;
         dbConnection = new SqlConnection(this.configuration.GetConnectionString("..."));
    }
    

    我的结构有点奇怪,您实际上只需将ConnectionString 传递给另一个类或注入方法,但这为您演示。但我相信 Entity Framework 7 有一个工厂可以直接接受连接字符串。希望这对您有所帮助。

    在实体框架中,您的ConfigureServices 中应该是这样的:

    services.AddSingleton<dbContext>(_ => new dbContext(Configuration.GetConnectionString("...")));
    public class dbContext : DbContext
    {
         public dbContext(string dbConnection) : base(dbConnection)
         {
    
         }
    }
    

    一些额外的documentation

    【讨论】:

      【解决方案2】:

      至少对于 EF Core 1.1,你需要使用FindExtension&lt;SqlServerOptionsExtension&gt;()

      using Microsoft.EntityFrameworkCore;
      using Microsoft.EntityFrameworkCore.Infrastructure.Internal;
      
      namespace MyNamespace
      {
          public class MyContext : DbContext
          {
              public MyContext(DbContextOptions<MyContext> options) : base(options)
              {
                  var sqlServerOptionsExtension = 
                         options.FindExtension<SqlServerOptionsExtension>();
                  if(sqlServerOptionsExtension != null)
                  {
                      string connectionString = sqlServerOptionsExtension.ConnectionString;
                  }
              }
          }
      }
      

      如果您在 Startup.cs 中使用 opt.UseInMemoryDatabase(),则会进行空检查

      【讨论】:

        【解决方案3】:

        对于EntityFrameworkCore 2.1.4,您的连接字符串在appsettings.json中应该是这样的

          "ConnectionStrings": {
            "Connection1": "....",
            "Connection2": "..."
          },
        

        Startup.cs 中的ConfigureServices 方法中添加以下行

         services.AddSingleton(provider => Configuration);
        

        在这几行之后,

         services.AddDbContext<MyContextContext>
                    (options => options.UseSqlServer(Configuration.GetConnectionString("Connection1")));
         services.AddScoped<DbContext, MyContext>();
        

        你的数据库上下文类应该修改如下。

        public partial class MyContext : DbContext
            {
                private readonly IConfiguration _configuration;
                private IDbConnection DbConnection { get; }
        
                public MyContext(DbContextOptions<MyContext> options, IConfiguration configuration)
                    : base(options)
                {
                    this._configuration = configuration;
                    DbConnection = new SqlConnection(this._configuration.GetConnectionString("Connection1"));
                }
        
                protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
                {
                    if (!optionsBuilder.IsConfigured)
                    {
                        optionsBuilder.UseSqlServer(DbConnection.ToString());
                    }
                }
            }
        

        【讨论】:

        • 如果上下文类也有这样的构造函数 public pixelleContext() { } 和使用上下文的代码如下 using (var context = new pixelleContext()) { return context.Specsheet.ToList() ; }
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-17
        • 1970-01-01
        • 2017-08-18
        • 1970-01-01
        • 1970-01-01
        • 2020-04-17
        相关资源
        最近更新 更多