Ho un ASP.Net Core 2.1 che utilizza il framework Entity con un front-end angolare 5 e un controller Web Api per il back-end.
Funziona bene così com'è ma ora voglio cambiarlo in modo che la stringa di connessione al database NON sia codificata.
Sto seguendo questo: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings
Ma non funziona. Ottengo:
Si è verificata un'eccezione non gestita durante l'elaborazione della richiesta. InvalidOperationException: nessun provider di database è stato configurato per questo DbContext. Un provider può essere configurato eseguendo l'override del metodo DbContext.OnConfiguring o utilizzando AddDbContext sul provider del servizio dell'applicazione. Se si utilizza AddDbContext, assicurarsi inoltre che il tipo DbContext accetti un oggetto DbContextOptions nel suo costruttore e lo passi al costruttore di base per DbContext.
'((Microsoft.EntityFrameworkCore.Internal.InternalDbSet) db.TblEmployee) .Local' ha generato un'eccezione di tipo 'System.InvalidOperationException'
I percorsi logici sono:
La mia classe di contesto del database è:
namespace Angular5NetcoreEF.Models
{
public partial class DBAngular5NetcoreEFContext : DbContext
{
public DBAngular5NetcoreEFContext()
{
}
public DBAngular5NetcoreEFContext(DbContextOptions<DBAngular5NetcoreEFContext> options)
: base(options)
{
}
public virtual DbSet<TblCities> TblCities { get; set; }
public virtual DbSet<TblEmployee> TblEmployee { get; set; }
//protected override void OnConfiguring(DbContextOptionsBuilder
optionsBuilder)
//{
// if (!optionsBuilder.IsConfigured)
// {
// optionsBuilder.UseSqlServer("Server=
// (localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;
// Trusted_Connection=True; MultipleActiveResultSets=true");
// }
//}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TblCities>(entity =>
{
entity.HasKey(e => e.CityId);
entity.ToTable("tblCities");
entity.Property(e => e.CityId).HasColumnName("CityID");
entity.Property(e => e.CityName)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
});
modelBuilder.Entity<TblEmployee>(entity =>
{
entity.HasKey(e => e.EmployeeId);
entity.ToTable("tblEmployee");
entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");
entity.Property(e => e.City)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
entity.Property(e => e.Department)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
entity.Property(e => e.Gender)
.IsRequired()
.HasMaxLength(6)
.IsUnicode(false);
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
});
}
}
}
Quindi, seguendo le istruzioni, ho commentato il metodo OnConfiguring sopra dove stavo facendo la codifica.
Ho aggiunto al file appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"DBAngular5NetcoreEFDatabase": "Server=(localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"AllowedHosts": "*"
}
Ho aggiunto al mio metodo Startup.cs - ConfigureServices
:
using Angular5NetcoreEF.Models;
using Microsoft.EntityFrameworkCore;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the Angular files will be served from this directory.
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
// I added this.
services.AddDbContext<DBAngular5NetcoreEFContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));
}
Non è necessario DBAngular5NetcoreEFContext
un'istanza di una nuova istanza di DBAngular5NetcoreEFContext
all'interno di EmplyeeDataAccessLayer
. Invece, dovresti iniettarlo.
È inoltre necessario registrare EmployeeDataAccessLayer
nel contenitore DI e immetterlo in EmployeeController
.
Fondamentalmente, lasci che il contenitore DI risolva le dipendenze per te.
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DBAngular5NetcoreEFContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));
services.AddScoped<EmployeeDataAccessLayer>();
...
}
...
}
public class EmployeeController : Controller
{
private readonly EmployeeDataAccessLayer objemployee;
public EmployeeController(EmployeeDataAccessLayer employeeDataAccessLayer)
{
objemployee = employeeDataAccessLayer;
}
}
public class EmployeeDataAccessLayer
{
private readonly DBAngular5NetcoreEFContext _db;
public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
{
_db = db;
}
...
}
Un altro pensiero è l'uso interface
invece dell'implementazione concreta. Ti renderà la vita più facile quando implementerai i test unitari.
il problema che stai affrontando è infatti il fatto che non stai utilizzando il modello di iniezione delle dipendenze. Prima di tutto è necessario inserire DbContext dai servizi tramite l'integrazione delle dipendenze da parte del costruttore
public class EmployeeDataAccessLayer
{
private DBAngular5NetcoreEFContext _db;
public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
{
_db = db;
}
}
In secondo luogo, devono essere iniettati anche tutti i riferimenti, quindi in ogni livello dell'applicazione, per ogni classe come EmployeeDataAccessLayer
si dovrebbe innanzitutto: registrarlo con l'integrazione delle dipendenze utilizzando in Startup.cs -> ConfigureServices()
: ad esempio services.AddScoped<EmployeeDataAccessLayer>();
, Quindi iniettarlo nel costruttore del controller come nel caso precedente.
Puoi conoscere l'iniezione di dipendenza e gli ambiti di esempio (Scoped, Transient, Singleton ...) da ie Doc
Per sicurezza, nel tuo scenario corrente per verificare quando hai un contesto non configurato, puoi fare qualcosa del tipo:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
throw new Exception("Context not configured");
}
}
Così come costruttore vuoto "disabilitazione temporanea"