Nous travaillons sur une grande application ASP.NET Core MVC 1.0 variée. Nous avons 4 niveaux pour chacune de nos applications comme suit:
Actuellement, dans nos référentiels, qui gèrent toutes les opérations de base de données, nous avons codé en dur les chaînes de connexion à la base de données dans le DbContext comme suit:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlServer("Data Source=somedatabase.database.windows.net;Initial Catalog=database;Integrated Security=False;User ID=username;Password=password;Connect Timeout=60;Encrypt=True;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;MultipleActiveResultSets=true");
}
Ce projet est en dehors du projet MVC en tant que projet autonome ASP.NET Core 1.0. Il contient également un fichier Program.cs vide qui semble nécessaire pour exécuter les lignes de commande de code à base de données (migrations dotnet ef et mise à jour de la base de données dotnet ef).
La raison pour laquelle nous avons une chaîne de connexion codée en dur dans DbConext est que lorsque nous utilisons le code suivant, nous obtenons une référence d'objet non définie sur une instance à une exception d'objet, lors de l'exécution des commandes dotnet ef.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["StandardDatabase"].ConnectionString);
}
Cependant, puisque nous avons un Program.cs, si nous ajoutons un Debug.WriteLine pour la chaîne de connexion et exécutons le projet, il renvoie la chaîne de connexions correcte et si nous définissons la chaîne de connexion dans le fichier appsettings.json dans l'interface utilisateur, l'interface utilisateur se connectera également avec succès.
THE ISSUE: La pile mentionnée ci-dessus est ce que nous utilisons pour plusieurs "Micro Apps", ce qui signifie que nous avons plusieurs projets qui se connectent à plusieurs bases de données. Nous voulons également profiter des chaînes de connexion de développement, de transfert et de production.
Si nous utilisons la chaîne de connexion de Configuration Manager, tout est bon pour les opérations quotidiennes; Cependant, chaque fois que nous souhaitons utiliser le code Entity Frameworks pour les lignes de commande de la base de données, nous devons aller dans chaque référentiel que nous voulons mettre à jour et changer le DbContext en une chaîne de connexion codée en dur, exécuter les commandes, puis les revenir à la fin , ce qui devient assez gênant.
LA QUESTION: Sommes-nous en train de mal faire, y a-t-il une pratique préférée pour configurer une pile Entity Framework Core 1.0 qui nous permet de ne pas avoir à modifier manuellement le DbContext mais de profiter des fichiers de configuration à travers le planche?
N'importe quelle direction serait appréciée!
EF Core est destiné à être configuré via l'injection de dépendances. L'injection de dépendances maintient votre DbContext propre et indépendant des détails d'implémentation de l'environnement.
Votre solution initiale de chaînes de connexion codées en dur a étroitement couplé le DbContext à la connaissance de l'emplacement de la base de données. C'est évidemment un problème. Mais la solution que vous proposez couple étroitement le DbContext à la connaissance d'un fichier de configuration particulier. Cela aussi est un problème.
Pour garder le DbContext indépendant des détails environnementaux, créez un constructeur qui prend un paramètre DbContextOptions
et appelle le constructeur de la classe de base.
public class MyContext : DbContext
{
public MyContext(DbContextOptions options) :
base(options)
{
}
}
Faites cela au lieu de remplacer OnConfiguring
. Ensuite, initialisez-le dans le Startup.cs
de votre application hôte. C'est là que la connaissance du fichier de configuration appartient.
public class Startup
{
private IConfigurationRoot _configuration;
public Startup(IHostingEnvironment env)
{
_configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json")
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfigurationRoot>(_configuration);
services.AddDbContext<MyContext>(options => options
.UseSqlServer(_configuration.GetConnectionString("MyContext")));
}
}
Vous pouvez maintenant utiliser votre DbContext de n'importe où.
REPONSE: Je rendais cela beaucoup plus difficile que ça ne l'était réellement. J'ai suivi les conseils de Juunas et ajouté le code suivant dans ma classe DbContext Repository:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// get the configuration from the app settings
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
// define the database to use
optionsBuilder.UseSqlServer(config.GetConnectionString("StandardDatabase"));
}
Ce qui fonctionne parfaitement avec les outils de ligne de commande dotnet ef et dans la mesure où la configuration d'environnement multiple va avec mon interface utilisateur MVC, le code par défaut suivant dans mon startup.cs fonctionne également très bien.
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("project.json", optional: true, reloadOnChange: true);
IDbContextFactory pourrait également aider. Les outils de ligne de commande EF et DI peuvent utiliser cette usine pour créer des instances de votre DBContext. Les services de conception (par exemple Migrations) découvriront les implémentations de cette interface qui se trouvent dans le même assembly que le contexte dérivé.
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace MyProject
{
public class BloggingContextFactory : IDbContextFactory<BloggingContext>
{
public BloggingContext Create()
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Filename=./blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
}