Как установить строку подключения из appsettings.json в Entity Framework Core - PullRequest
2 голосов
/ 07 мая 2019

Я устанавливаю новую базу данных с Entityframework Core и первым подходом к коду. Я настроил класс контекста, как в приведенном ниже листинге кода, и все необходимые классы для таблиц базы данных. Теперь я хочу создать новую базу данных с

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

Но я получаю сообщение об ошибке, что строка подключения не может быть нулевой.

Моя строка подключения установлена ​​в файле appsettings.json, и я копирую ее в выходной каталог при сборке проекта.

Я пробовал разные способы получить строку подключения из файла appsettings, но все с одинаковым результатом. В свойстве Configuration в классе Startup я вижу, что файл appsettings загружен правильно, но когда я хочу получить строку с

ConnectionString = Configuration["Connectionstrings:MyConnection"];

ConnectionString всегда равно нулю.

У меня есть это в моем файле 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();
    }

со следующим в Configure - Метод

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"
  },
}

Ответы [ 3 ]

4 голосов
/ 07 мая 2019

ConnectionString всегда равно нулю, потому что есть опечатка, попробуйте это

ConnectionString = Configuration["Connnectionstrings:MyConnection"];

или исправьте имя в appsettings.json

1 голос
/ 07 мая 2019

Я могу показать вам два варианта передачи строки подключения через строго типизированный класс Settings, загруженный из appsettings.json. Для обоих вам просто нужно переместить ваши настройки конфигурации в пользовательский раздел со значения по умолчанию ConnnectionStrings one и полностью контролировать настройки вашей БД и передавать их в ваш контекст 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);
    }
}
0 голосов
/ 07 мая 2019

В следующем шаблоне используются шаблоны, которые я украл из ядра asp.net.

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