Avere una soluzione con 3 assiemi: dati, dominio e Web. Data detiene il contesto, Web è un'app WebAPI .NET Core e sono tutti nella stessa directory di soluzioni. Sto anche usando Postgre come database.
Ecco il mio metodo ConfigureServices
in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
...
services.AddDbContext<WebStoreContext>(
options => options.UseNpgsql(
connectionString,
(providerOptions) =>
{
providerOptions.CommandTimeout(20);
providerOptions.MigrationsAssembly("WebStore.Data");
}));
services.AddMvc();
...
}
Si noti come è stato configurato un provider di database utilizzando AddDbContext
e passando il parametro optionsAction
.
Ora ho creato una migrazione iniziale per il db, usando lo strumento ef della riga di comando. Ho inserito cd in WebStore.Data e ho eseguito:
dotnet ef --startup-project ..\WebStore.Web migrations add IntializeDb
Va tutto bene.
Il problema inizia quando provo a, dalla stessa directory, eseguire:
dotnet ef database update
Nessun costruttore senza parametri è stato trovato su "WebStoreContext". Aggiungere un costruttore senza parametri a "WebStoreContext" o aggiungere un'implementazione di "IDbContextFactory" nello stesso assembly di "WebStoreContext".
L'errore sopra riportato prima di dichiarare un costruttore senza parametri nella mia classe derivata DbContext e l'errore seguente dopo che ne ho dichiarato uno:
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.
Quindi mi sembra che il costruttore di paramterless continui a essere chiamato nonostante io fornisca un'istanza di DbContextOptions.
Allora, ho provato questo:
//parameterless constructor calling the one accepting the DbContextOptions argument
public WebStoreContext() : this(new DbContextOptionsBuilder<WebStoreContext>()
.UseNpgsql("UserID=****;Password=****;Host=localhost;Port=****;Database=webstore;Pooling=true;")
.Options){ }
e ottenuto questo:
System.Reflection.TargetInvocationException: l'eccezione di una chiamata è stata lanciata dalla destinazione. ---> System.IO.FileLoadException: Impossibile caricare il file o l'assembly 'System.Diagnostics.DiagnosticSource, Versione = 4.0.1.1, Culture = neutral, PublicKeyToken = cc7b13ffcd2ddd51'. La definizione manifest di assembly individuato non corrisponde al riferimento all'assembly. (Eccezione da HRESULT: 0x80131040)
Sto ancora cercando di capire cosa sta succedendo qui. L'aiuto sarebbe molto apprezzato.
EDIT: ho applicato la soluzione di Shay Rojansky e ha funzionato, anche se ho avuto il seguente problema:
System.IO.FileLoadException: Impossibile caricare il file o l'assembly 'System.Diagnostics.DiagnosticSource, Versione = 4.0.1.1, Culture = neutral, PublicKeyToken = cc7b13ffcd2ddd51'. La definizione manifest di assembly individuato non corrisponde al riferimento all'assembly. (Eccezione da HRESULT: 0x80131040) Nome file: 'System.Diagnostics.DiagnosticSource, Versione = 4.0.1.1, Culture = neutral, PublicKeyToken = cc7b13ffcd2ddd51' su Microsoft.EntityFrameworkCore.Infrastructure.RelationalServiceCollectionExtensions.AddRelational (servizi IServiceCollection) su Microsoft.Extensions. DependencyInjection.NpgsqlEntityFrameworkServicesBuilderExtensions.AddEntityFrameworkNpgsql (servizi IServiceCollection) in Microsoft.EntityFrameworkCore.Internal.ServiceProviderCache. <> C__DisplayClass4_1.b__2 (Int64 k) in System.Collections.ConcurrentDoncary`2.GetOrAdd (chiave TKey, Func`2 valueFactory) in Microsoft .EntityFrameworkCore.DbContext.InitializeServices () in Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider () in Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService [TService] (IInfrastructure`1 accessor) in Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext ( Func`1 factory) in Microsoft.EntityFramewor kCore.Design.Internal.DbContextOperations.CreateContext (String contextType) in Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase (String targetMigration, String contextType) in Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase. <> c__DisplayClass0_1. <. ctor > b__0 () in Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute (Azione azione)
Impossibile caricare il file o l'assembly 'System.Diagnostics.DiagnosticSource, Versione = 4.0.1.1, Culture = neutral, PublicKeyToken = cc7b13ffcd2ddd51'. La definizione manifest di assembly individuato non corrisponde al riferimento all'assembly. (Eccezione da HRESULT: 0x80131040)
A cui la soluzione sta aggiungendo questo nel file .csproj:
<PropertyGroup>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
Ciò accade apparentemente a causa di un bug .
Ho trovato la soluzione più semplice a questo è rimuovere il costruttore predefinito dal contesto. Basta avere un singolo costruttore con DBContentOptions o DBContentOptions <> come parametro che viene quindi passato alla classe base.
public class ApplicationDbContext : DbContext>
{
#region Constructor
public ApplicationDbContext(DbContextOptions options) : base(options) { }
#endregion
}
ma ho convenuto che non è l'ideale. Esp se hai bisogno di usare il contesto al di fuori dell'unità IOC EF.
Speriamo che questo aiuti gli altri là fuori.