如何在Entity Framework Core中从appsettings.json设置连接字符串

5

我正在使用Entityframework Core和code first方法设置一个新的数据库。我已经像下面代码清单中的那样设置了上下文类,还设置了所有必要的数据库表类。 现在我想使用以下代码创建新的数据库:

using (var context = new MyContext())
{
    context.Database.EnsureCreated();
}

但我得到的错误是连接字符串不能为空。

我的连接字符串设置在appsettings.json文件中,当项目构建时,我将其复制到输出目录中。

我尝试了不同的方法从appsettings文件获取连接字符串,但结果都相同。在Startup类的Configuration属性中,我可以看到appsettings文件已正确加载,但当我想要使用以下内容获取字符串时

ConnectionString = Configuration["Connectionstrings:MyConnection"];

连接字符串始终为空。

我的Startup.cs文件中有以下内容:

 public class Startup
 {
    public static string ConnectionString { get; private set; }
    public IConfigurationRoot Configuration { get; set; }

    public Startup(IHostingEnvironment _environment)
    {
        Configuration = new ConfigurationBuilder()
                        .SetBasePath(_environment.ContentRootPath)
                        .AddJsonFile("appsettings.json")
                        .Build();
    }

在“配置-方法”中,按照以下方式进行。
using (var context = new MyContext())
{
    context.Database.EnsureCreated();
}

在我的上下文类中,我有以下代码。
public class MyContext : DbContext
{
    public MyContext()
    {
    }

    public static string GetConnectionString()
    {
        return Startup.ConnectionString;
    }

protected override void OnConfiguring(DbContextOptionsBuilder _builder)
{
    _builder.UseSqlServer(GetConnectionString());
}

现在,当我启动应用程序时,在OnConfiguring方法中会出现连接字符串为空的错误。

我的appsettings.json文件如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "Connnectionstrings": {
    "MyConnection": "server=.;database=MyDatabase;trusted_connection=true;MultipleActiveResultSets=True"
  },
}

2
@ArtificialOdorlessArmpit DI是什么? - pospich0815
3个回答

6
ConnectionString 总是为 null,因为有一个打字错误,请尝试以下内容。
ConnectionString = Configuration["Connnectionstrings:MyConnection"];

或者在appsettings.json中修复名称。

1
还有一个IConfiguration.GetConnectionString(...)方法可以读取连接字符串,这只是一个简写版本。 - user743414

4
以下模板采用了我从asp.net core中抄袭的模式。

appsettings.json

{
  "ConnectionStrings": {
    "MyConnection": "Data Source=WithSqlite",
    "YourConnection": "Server=(localdb)\\mssqllocaldb;Database=WithSqlServer;Trusted_Connection=True"
  }
}

AppDbContext.cs

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    // DbSet goes here
}

Program.cs

static class Program
{
    private static readonly IConfiguration _configuration;

    static Program()
    {
        _configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .Build();
    }

    private static void ConfigureServices(IServiceCollection isc)
    {
        isc.AddSingleton(_configuration);

        isc.AddDbContext<AppDbContext>(options =>
        {

            options.UseSqlite(_configuration["ConnectionStrings:MyConnection"]);

            //options .UseSqlServer(_configuration.GetConnectionString("YourConnection"));


        });

        isc.AddSingleton<TheApp>();


    }

    public static  ServiceProvider CreateServiceProvider()
    {
        // create service collection
        IServiceCollection isc = new ServiceCollection();
        ConfigureServices(isc);

        // create service provider
        return isc.BuildServiceProvider();
    }

    private static void Main(string[] args)
    {
        // create application instance and run
        using (var scope = CreateServiceProvider().CreateScope())
        {
            scope.ServiceProvider.GetRequiredService<TheApp>().Run();
            // It is said that GetRequiredService is much better than GetService.
        }
    }
}

TheApp.cs

class TheApp
{
    private readonly AppDbContext _db;


    public TheApp(AppDbContext db)
    {
        _db = db;
    }

    public void Run()
    {

    // Your main logic goes here

    }

}

MigrationHelper.cs

class MigrationHelper: IDesignTimeDbContextFactory<AppDbContext>
{
    public AppDbContext CreateDbContext(string[] args) => 
        Program.CreateServiceProvider()
        .CreateScope()
        .ServiceProvider
        .GetService<AppDbContext>();
}

3
我可以向您展示两种方法,如何通过强类型设置类从appsettings.json加载连接字符串。 对于这两种方法,您只需要将配置设置移动到自定义部分,而不是默认的ConnnectionStrings部分,并完全控制您的DB设置并将它们传递给EntityFramework上下文。
您需要在Startup类中执行此操作:
private Settings _settings;
public Startup(IConfiguration configuration, ...)
{
    Configuration = configuration;
    ...
}

public IConfiguration Configuration { get; }
...
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddOptions()
        .Configure<Settings>(Configuration.GetSection("Settings"))
        .AddSingleton(Configuration);

    _settings = Configuration.GetSection(nameof(Settings)).Get<Settings>();

    services.AddTransient<DesignTimeDbContextFactory>();

    services.AddDbContext<MyContext>(options =>
    {
        if (_settings.DatabaseSettings.UseInMemory)
        {
            options.UseInMemoryDatabase("DummyInMemoryDatabase");
        }
        else
        {
            // Option 1
            options.UseSqlServer(_settings.DatabaseSettings.BuildConnectionString());
            // Option 2
            options.UseSqlServer(_settings.ConnectionStrings.MyConnection);
        }
    });
    ...
}

这是对应的appsettings.json文件:
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "Settings": {

    // Option 1: move connection strings to custom strong typed Settings class
    "ConnnectionStrings": {
      "MyConnection": "server=.;database=MyDatabase;trusted_connection=true;MultipleActiveResultSets=True"
    },

    // Option 2: store DB settings any custom way you like - also to get via strong typed Settings class
    "DatabaseSettings": {
      "UseInMemory": false,
      "Host": ".",
      "Name": "MyDatabase",
      "User": "qwerty",
      "Password": "@#$%*"
    }
  }
}
强类型设置类:
/// <summary> Represents settings configured in appsettings.json file </summary>
public class Settings
{
    /// <summary> Option 1: move connection strings to custom strong typed Settings class </summary>
    public Connections ConnectionStrings { get; set; }

    /// <summary> Option 2: store DB settings any custom way you like - also to get via strong typed Settings class </summary>
    public Database DatabaseSettings { get; set; }
}

public class Connections
{
    public string MyConnection { get; set; }
}

public class Database
{
    public bool UseInMemory { get; set; }
    public string Host { get; set; }
    public string Name { get; set; }
    public string User { get; set; }
    public string Password { get; set; }
    public string BuildConnectionString() => $"Server={Host};Database={Name};User Id={User};Password={Password}";
}

一个帮助进行数据库迁移和其他设计时代码生成的辅助类 - DesignTimeDbContextFactory:

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyContext>
{
    public  MyContext CreateDbContext(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
            .AddJsonFile("appsettings.json", optional: false);

        var config = builder.Build();

        var settingsSection = config.GetSection("Settings");
        var settings = new Settings();
        settingsSection.Bind(settings);

        var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
            .UseSqlServer(settings.ConnectionStrings.MyConnection); // or you can use option #2 either

        return new MyContext(optionsBuilder.Options);
    }
}

您可以通过调用我的答案中所示的Startup静态方法来简化迁移过程。 - Second Person Shooter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接