web-dev-qa-db-fra.com

Migration Entity Framework Core - chaîne de connexion

Je rencontre un problème pour gérer la chaîne de connexion à la base de données conjointement avec les migrations. J'ai 2 projets:

  • Domaine
  • Application

La DbContext étant dans le projet de domaine, il s'agit donc du projet sur lequel je lance les migrations. Le concept de migration m'oblige à implémenter OnConfiguring dans ma DbContext et à spécifier le fournisseur de base de données, par exemple:

protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
    builder.UseSqlServer("<connection string>");
}

Mon problème est que je ne souhaite pas utiliser une chaîne de connexion codée en dur, pour des raisons évidentes, et que je ne peux pas utiliser ConfigurationManager pour la lire à partir du fichier de configuration car celui-ci se trouve dans le projet d'application. 

7
Robert

Tous les exemples que j'ai vus impliquent soit de coder en dur la chaîne de connexion, soit de la placer dans les fichiers de paramètres de mon application ASP.NET Core.

Si vous n'utilisez pas ASP.NET Core, ou peut-être, je ne sais pas, ne souhaitez pas que les détails de la base de données de votre environnement local soient enregistrés dans le contrôle de source, vous pouvez utiliser une variable d'environnement temporaire.

Commencez par implémenter IDesignTimeDbContextFactory comme ceci (notez que IDbContextFactory est maintenant obsolète):

public class AppContextFactory: IDesignTimeDbContextFactory<AppContext>
{
    public AppContextFactory()
    {
        // A parameter-less constructor is required by the EF Core CLI tools.
    }

    public AppContext CreateDbContext(string[] args)
    {
        var connectionString = Environment.GetEnvironmentVariable("EFCORETOOLSDB");
        if (string.IsNullOrEmpty(connectionString))
            throw new InvalidOperationException("The connection string was not set " +
            "in the 'EFCORETOOLSDB' environment variable.");

         var options = new DbContextOptionsBuilder<AppContext>()
            .UseSqlServer(connectionString)
            .Options;
        return new AppContext(options);
    }
}

Ensuite, vous pouvez inclure la variable d'environnement lorsque vous appelez Update-Database ou l'un des autres outils EF Core:

$env:EFCORETOOLSDB = "Data Source=(local);Initial Catalog=ApplicationDb;Integrated Security=True"; Update-Database
1
Rory MacLeod

Nous avons eu le même problème et il y a une solution. :)

Vous devez implémenter IDbContextFactory <TContext> Ce faisant, vous pouvez lire les chaînes de connexion à partir de votre appsettings.json. Vous pouvez également utiliser Add-Migration sans erreur, car écraser OnConfigure() est alors obsolète.

Exemple de mise en œuvre:

public class DomainContextFactory : IDbContextFactory<DomainContext>
{
    public string BasePath { get; protected set; }

    public DomainContext Create()
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        var basePath = AppContext.BaseDirectory;

        return Create(basePath, environmentName);
    }

    public DomainContext Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);

    private DomainContext Create(string basePath, string environmentName)
    {
        BasePath = basePath;
        var configuration = Configuration(basePath, environmentName);
        var connectionString = ConnectionString(configuration.Build());
        return Create(connectionString);
    }

    private DomainContext Create(string connectionString)
    {
        if (string.IsNullOrEmpty(connectionString))
        {
            throw new ArgumentException($"{nameof(connectionString)} is null or empty", nameof(connectionString));
        }
        var optionsBuilder = new DbContextOptionsBuilder<DomainContext>();
        return Configure(connectionString, optionsBuilder);
    }

    protected virtual IConfigurationBuilder Configuration(string basePath, string environmentName)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("constr.json")
            .AddJsonFile($"constr.{environmentName}.json", true)
            .AddEnvironmentVariables();
        return builder;
    }

    protected virtual string ConnectionString(IConfigurationRoot configuration)
    {
        string connectionString = configuration["ConnectionStrings:DefaultConnection"];
        return connectionString;
    }

    protected virtual DomainContext Configure(string connectionString, DbContextOptionsBuilder<DomainContext> builder)
    {
        builder.UseSqlServer(connectionString, opt => opt.UseRowNumberForPaging());

        DomainContext db = new DomainContext(builder.Options);
        return db;
    }


    DomainContext IDbContextFactory<DomainContext>.Create(DbContextFactoryOptions options)
        => Create(options.ContentRootPath, options.EnvironmentName);
}

Comment nous l'utilisons:

    public override IServiceResult<IList<Datei>> LoadAllData()
    {
        using (var db = this.DomainContextFactory.Create())
        {
            var files = db.Datei
                .ToListAsync<Datei>();

            return new ServiceResult<IList<Datei>>(files.Result, files.Result.Count);
        }
    }

exemple de configuration

{
  "ConnectionStrings": {
    "DefaultConnection": "Put your connectionstring here"
  }
}
1
user743414

Voici comment je le fais, sans beaucoup de code supplémentaire ni de folie.

Structure du projet:

  • AspNetCoreProject.Web

  • AspNetCoreProject.Data <- DbContext ici

Mon DbContext est configuré avec le constructeur qui vous permet d’injecter les DbContextOptions

AspNetCoreProject.Data

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }
}

Dans votre application ou application Web, vous configurez votre ConfigureServices normalement.

AspNetCoreProject.Web/Startup.cs/ConfigureServices ()

services.AddDbContext<MyContext>(options => 
            options.UseSqlServer(Configuration.GetConnectionString("connection"))

Maintenant, qu'en est-il des migrations? Eh bien, je "trompe" l'interface utilisateur de Visual Studio pour qu'elle fonctionne comme prévu.

  • Tout d'abord, assurez-vous que votre application est le projet de démarrage.

  • Deuxièmement, ouvrez votre console Nuget Package Manager. En haut de la console Nuget PM>, vous trouverez un menu déroulant pour "Définir le projet par défaut", pointez-le sur votre AspNetCoreProject.Data ou votre projet avec la classe DbContext.

  • Exécutez vos commandes de migration normalement. add-migration init puis update-database

0
Adam Vincent