在 EF 上下文中使用 appsettings.json 配置

Posted

技术标签:

【中文标题】在 EF 上下文中使用 appsettings.json 配置【英文标题】:Using appsettings.json configuration in EF Context 【发布时间】:2021-11-29 18:58:27 【问题描述】:

我应该指出我是 .NET 的新手...

我有以下 appsettings.json 文件:


    "Logging": 
        "LogLevel": 
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        
    ,
    "ConnectionStrings": 
        "MyContext": "Host=localhost;Database=test;Username=user;Password=''"
    

在 MyContext.cs 文件中,我想从 appsettings.json 配置中读取连接字符串:

using Microsoft.EntityFrameworkCore;
using System;
using System.Configuration;

namespace My.Models

  public partial class MyContext : DbContext
  

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  
    Console.WriteLine(ConfigurationManager.ConnectionStrings.Count);
    if (!optionsBuilder.IsConfigured)
    
  optionsBuilder.UseNpgsql(ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
    
  

但是ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString 为空,有什么想法吗?

我通过Configuration.GetConnectionString("MyContext") 在 Startup.cs 中成功使用了配置文件,但在这里我想从该配置中读取连接字符串以用于 ASP.NET 应用程序之外的情况(即在我想要执行的 EF 迁移中) using var db = new MyContext();),但不知道为什么上面返回 null。

ConfigurationManager 没有从我的 appsettings.json 文件中读取数据吗?不知道如何判断,因为ConfigurationManager.ConnectionStrings.Count 返回 1,所以我很困惑。有什么明显的错误有人可以看到吗?

我正在使用 .NET Core 5 和 EF Core 版本 5

【问题讨论】:

如何运行迁移? @GuruStron dotnet ef 数据库更新 咆哮:如果 migrationBuilder 允许我获取刚刚插入的数据,我什至不需要这个...... 你有完整的复制品吗?运行dotnet ef database update 时,您可以添加启动项目,以便在运行迁移时使用。您还可以详细说明“migrationBuilder 允许我获取刚刚插入的数据”。 - 你想达到什么目标? 您使用的是哪种类型的项目?如果您使用的是 API 或 Worker,您可以使用依赖注入来创建您的 DbContext,并且在这种情况下,您无需将与 IConfiguration 相关的任何内容带入您的 EF Core 上下文中还有任何理由特别是在 DBContext 创建期间读取?通常对带有 Startup.cs 的项目的建议是让 EFCore 为您注入 DBContext,然后您可以在那里获取连接字符串并将其作为依赖注入的参数 【参考方案1】:

在ef core中定义连接字符串的常用方法是

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

optionsBuilder.UseNpgsql(@"Host=localhost;Database=test;Username=user;Password=password");

您可以手动访问 IConfiguration:

    将此包安装到 ef 项目中
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
    构建 IConfiguration
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();
        optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
    

如果你的 Ef 核心在一个特殊的项目中,你必须将 appsetings.json 复制到这个项目中

如果您在查找 appsetings 文件夹时遇到问题,您可以直接定义路径

// .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
   .AddJsonFile(@"C:\....\appsettings.json")

【讨论】:

是的,不幸的是我认为这是使用配置文件的唯一方法......我正在研究创建秘密。 很好,即使这样也会报错:使用了命名的连接字符串,但在应用程序的配置中找不到名称“ConnectionStrings:MyContext”。请注意,仅在使用“IConfiguration”和服务提供者时才支持命名连接字符串,例如在典型的 ASP.NET Core 应用程序中。请参阅go.microsoft.com/fwlink/?linkid=850912 了解更多信息。我不明白 .NET 为何如此受欢迎...... 最后采用了这个解决方案,谢谢【参考方案2】:

我假设您正在运行 API 或 Blazor/Razor 应用程序,因为您提到了 Startup.cs 文件:)

在这种情况下,建议 (official docs about this) 是使用 Entity Framework 自己的库在 Startup.ConfigureServices 中设置您的 MyContext。在那里,您可以访问应用程序的 IConfiguration 中的 ConnectionStrings 以及允许您使用特定连接字符串注册 DbContext 的扩展方法。

它可能看起来像这样,只需将我对 Sqlite 的调用调整为您正在使用的任何数据库驱动程序:


public class Startup 

  Startup(IConfiguration configuration)
  
    _configuration = configuration;
  

  void ConfigureServices(IServiceCollection services) 
  
    // Other dependencies go here
    string connString = _configuration.GetConnectionString("MyContext");
    services.AddDbContext<MyContext>(opt => opt.UseSqlite(connString));
    // Other dependencies, et cetera
  


这使您可以防止配置逻辑“泄漏”到您的“模型”命名空间中,因此您的MyContext 问题仅与数据的持久性有关,而不是访问系统文件和环境变量。

为了在控制器上使用 MyContext 的实例或由.NET 的依赖注入系统创建的任何其他东西,您需要做的就是在类的构造函数中请求它,比如:

public class MyAwesomeController : ControllerBase

  private readonly MyContext _context;

  // This tells .NET to inject an instance of MyContext into your controller
  public MyAwesomeController(MyContext context) 
  
    _context = context ?? throw new ArgumentNullException();
  

  // Now all you gotta do is actually use that instance - no matter where it's connecting to
  [HttpGet]
  public Task ListEverything() => _context.MySet.ToListAsync();

【讨论】:

谢谢,但我在应用程序本身中使用它没有问题,而是在应用程序和迁移中使用上下文。应用会读取配置,迁移不会。 很公平,那么您是从另一个项目运行迁移吗?这是 EFCore 的一个缺点——当你想把所有东西都放在一个地方时,它非常简单,但是当你分成不同的项目时,它会变得有点棘手。 IIRC,您需要在用于运行迁移的项目中创建某种“ContextBuilder”,以便从命令行(作为 dotnet ef database update 和其他命令的参数)或从 AppSettings 读取 ConnectionString。很高兴之前的答案可以让您畅通无阻! :D

以上是关于在 EF 上下文中使用 appsettings.json 配置的主要内容,如果未能解决你的问题,请参考以下文章

EF上下文对象线程内唯一性与优化

在 EF6 中,是不是可以使用每个调用结构的上下文跨服务调用执行事务?

LINQ 和 EF6:创建模型时无法使用上下文

EF 预生成视图和多个上下文

[EF]数据上下文该如何实例化?

EF中获取当前上下文的表名