c# - No se pueden crear migraciones después de actualizar a ASP.NET Core 2.0
asp.net-core asp.net-core-mvc (24)
Algo que realmente me ayudó fue este artículo: https://elanderson.net/2017/09/unable-to-create-an-object-of-type-applicationdbcontext-add-an-implementation-of-idesigntimedbcontextfactory/
La idea básica es que en el cambio de .net core 1 a 2, toda la inicialización de db se debe mover de StartUp.cs a Program.cs. De lo contrario, las tareas de EF intentan ejecutar su DB inits al realizar tareas.
"Hay una buena sección en los documentos oficiales de migración ( https://docs.microsoft.com/en-us/ef/core/miscellaneous/1x-2x-upgrade ) titulada" Mover el código de inicialización de la base de datos "que parecía tener errado. Así que antes de que te dirijas a cualquier agujero de conejo como yo me aseguré de que esto no sea lo que está causando tu necesidad de agregar una implementación de IdesignTimeDbContextFactory ".
Después de actualizar a ASP.NET Core 2.0, parece que ya no puedo crear migraciones.
Me estoy poniendo
"Se produjo un error al llamar al método ''BuildWebHost'' en la clase ''Programa''. Continuar sin el proveedor de servicios de aplicaciones. Error: Se produjeron uno o más errores. (No se puede abrir la base de datos" ... "solicitada por el inicio de sesión. El inicio de sesión falló. Iniciar sesión falló para el usuario ''...'' "
y
"No se puede crear un objeto de tipo ''MyContext''. Agregue una implementación de ''IDesignTimeDbContextFactory'' al proyecto, o consulte https://go.microsoft.com/fwlink/?linkid=851728 para obtener patrones adicionales compatibles en el momento del diseño".
El comando que ejecuté anteriormente era
$ dotnet ef migrations add InitialCreate --startup-project "../Web"
(desde el proyecto / carpeta con el DBContext).
Cadena de conexión:
"Server=(localdb)//mssqllocaldb;Database=database;Trusted_Connection=True;MultipleActiveResultSets=true"
Este es mi Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
Anteriormente, configuró los datos semilla en el método Configure en Startup.cs. Ahora se recomienda que utilice el método Configurar solo para configurar la canalización de solicitudes. El código de inicio de la aplicación pertenece al método Main.
El método principal refactorizado. Agregue las siguientes referencias a Program.cs:
usando Microsoft.Extensions.DependencyInjection;
usando MyProject.MyDbContextFolder;
public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
//
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseSession();
app.UseMvc(routes =>
{
//
});
SeedData.EnsurePopulated(app);
}
}
Desde
https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dbcontext-creation
Cuando crea una nueva aplicación ASP.NET Core 2.0, este enlace se incluye de forma predeterminada. En versiones anteriores de EF Core y ASP.NET Core, las herramientas intentan invocar Startup.ConfigureServices directamente para obtener el proveedor de servicios de la aplicación, pero este patrón ya no funciona correctamente en las aplicaciones ASP.NET Core 2.0. Si está actualizando una aplicación ASP.NET Core 1.x a 2.0, puede modificar su clase de Programa para seguir el nuevo patrón.
Agregar fábrica en .Net Core 2.x
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
Ejemplo de clase de contexto DB para aplicaciones de consola central .net
IConfigurationRoot _config;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json");
_config = builder.Build();
}
En AppContext.cs, además de la clase AppContext, agregue otra clase:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
Esto resolverá tu segundo problema:
"No se puede crear un objeto de tipo ''MyContext''. Agregue una implementación de ''IDesignTimeDbContextFactory'' al proyecto,
Después de eso, podrá agregar la migración inicial y ejecutarla ejecutando el comando update-database . Sin embargo, si ejecuta estos comandos cuando aún no hay DataBase en su SqlServer local, recibirá la advertencia como su primer error: "Un error
ocurrió al llamar al método ''BuildWebHost'' en la clase ''Programa'' ... El inicio de sesión falló. Error de usuario ''...''"
Pero no es un error porque se creará la migración y se puede ejecutar. Así que simplemente ignore este error por primera vez, y después, dado que Db existirá, no volverá a suceder.
En el archivo appsettings.json del proyecto principal, configuré ''Copiar al directorio de salida'' en "Copiar siempre" y funcionó.
En mi caso, este error ocurrió debido a que eliminé MyDbContext de ConfigureServices debido a algunos patrones de diseño. Mira esto. En Startup.cs => ConfigureServices agregue estas líneas:
var connectionString = "Application Connection String!!!"; services.AddDbContext<MyDbContext>(c => c.UseSqlServer(connectionString));
En mi caso, la causa del problema fueron múltiples proyectos de inicio. Tengo tres proyectos en mi solución: Mvc, Api y Dal. DbContext y Migraciones en el proyecto Dal.
Había configurado múltiples proyectos de inicio. Tanto los proyectos Mvc como Api se estaban ejecutando cuando hice clic en Iniciar. Pero en este caso recibí este error.
"No se puede crear un objeto de tipo ''MyContext''. Agregue una implementación de ''IDesignTimeDbContextFactory'' al proyecto, o consulte https://go.microsoft.com/fwlink/?linkid=851728 para obtener patrones adicionales compatibles en el momento del diseño".
Pude agregar con éxito la migración después de configurar Mvc como el único proyecto de inicio y seleccionar Dal en la consola de Package Manager.
En mi caso, tuve el problema porque tenía un método llamado SeedData.EnsurePopulated () llamado en mi archivo Startup.cs .
public static void EnsurePopulated(IApplicationBuilder app)
{
ApplicationDbContext context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
if (!context.Products.Any())
{
context.Products.AddRange(
new Product
{
Name = "Kayak",
Description = "A boat for one person",
Category = "Watersports",
Price = 275
},
....
);
context.SaveChanges();
}
}
El trabajo de la clase SeedData es agregar datos iniciales a la tabla de la base de datos. Su código es:
// SeedData.EnsurePopulated(app);
SOLUCIÓN
Antes de realizar la migración, simplemente comente la llamada de la clase SeedData en el archivo Startup.cs.
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
Eso resolvió mi problema y espero que tu problema también se resuelva de la misma manera.
Hay un problema al ejecutar db desde Startup. Configure en 2.0 ... aún puede hacerlo con esta solución. Probado y funcionó bien
Me encontré con el mismo problema. Tengo dos proyectos en la solución. cual
- API
- Servicios y repositorio, que contienen modelos contextuales.
Inicialmente, el proyecto API se estableció como proyecto de inicio.
Cambié el proyecto de inicio al que contiene clases de contexto. Si está utilizando Visual Studio , puede configurar un proyecto como Proyecto de inicio:
Abra el explorador de soluciones >> haga clic con el botón derecho en el proyecto de contexto >> seleccione Establecer como proyecto de inicio
Para mí fue porque cambié el
Output Type
de
Output Type
de mi proyecto de inicio de la
Console Application
a la
Class Library
.
Volviendo a la
Console Application
hizo el truco.
Puede agregar una clase que implemente IDesignTimeDbContextFactory dentro de su proyecto web.
Aquí está el código de ejemplo:
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<CodingBlastDbContext>
{
public CodingBlastDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<CodingBlastDbContext>();
var connectionString = configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
return new CodingBlastDbContext(builder.Options);
}
}
Luego, navegue a su proyecto de base de datos y ejecute lo siguiente desde la línea de comandos:
dotnet ef migrations add InitialMigration -s ../Web/
dotnet ef database update -s ../Web/
-s stands for startup project and ../Web/ is the location of my web/startup project.
Puede probar esta solución a partir de esta discusión , que se inspiró en esta publicación .
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<MyDbConext>();
DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}
host.Run();
}
Recibí el mismo problema desde que me refería al viejo: Microsoft.EntityFrameworkCore.Tools.DotNet
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;
namespace EmailServerConsole.Data
{
public class EmailDBContext : DbContext
{
public EmailDBContext(DbContextOptions<EmailDBContext> options) : base(options) { }
public DbSet<EmailQueue> EmailsQueue { get; set; }
}
public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<EmailDBContext>
{
EmailDBContext IDesignTimeDbContextFactory<EmailDBContext>.CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<EmailDBContext>();
var connectionString = configuration.GetConnectionString("connection_string");
builder.UseSqlServer(connectionString);
return new EmailDBContext(builder.Options);
}
}
}
Después de actualizar a la versión más nueva, se resolvió
Si quieres evitar esa cosa IDesignTimeDbContextFactory: solo asegúrate de no utilizar ningún método de Seed en tu inicio. Estaba usando un método de semilla estática en mi inicio y me estaba causando este error.
También puede usar en el constructor de la clase de inicio para agregar un archivo json (donde se encuentra la cadena de conexión) a la configuración. Ejemplo:
var connectionString = "Application Connection String!!!";
services.AddDbContext<MyDbContext>(c => c.UseSqlServer(connectionString));
Tuve el mismo problema Acabo de cambiar el ap.jason a application.jason y solucionó el problema
Tuve este problema en una solución que tiene:
- un proyecto .NET Core 2.2 MVC
- un proyecto .NET Core 3.0 Blazor
- El contexto DB en un proyecto de biblioteca de clase .NET Standard 2.0
Recibo el mensaje "no se puede crear un objeto ..." cuando el proyecto Blazor se configura como el proyecto de inicio, pero no si el proyecto MVC se configura como el proyecto de inicio.
Eso me desconcierta, porque en la Consola del Administrador de paquetes (que es donde estoy creando la migración) tengo el proyecto predeterminado configurado en una biblioteca de clase C # que realmente contiene el contexto DB, y también estoy especificando el contexto DB en mi llamado a agregar-migración
add-migration MigrationName -context ContextName
, por lo que parece extraño que a Visual Studio le
add-migration MigrationName -context ContextName
qué proyecto de inicio está configurado actualmente.
Supongo que la razón es que cuando el proyecto Blazor es el proyecto de inicio, el PMC determina que la versión de .NET sea Core 3.0 del proyecto de inicio y luego intenta usar eso para ejecutar las migraciones en la clase .NET Standard 2.0 biblioteca y golpear un conflicto de algún tipo.
Cualquiera sea la causa, el cambio del proyecto de inicio al proyecto MVC que apunta a Core 2.2, en lugar del proyecto Blazor, solucionó el problema
Tuve este problema y lo resolví por Conjunto -> Proyecto de aplicación web (incluido Program.cs) a -> "Establecer como proyecto de inicio"
Luego ejecute -> add-migración initial -verbose
en la consola de Package Manager
Una mejor solución:
Si su proyecto de inicio es una
ASP.NET Core
, las herramientas intentan obtener el objeto
DbContext
del proveedor de servicios de la aplicación.
La herramienta primero intenta obtener el proveedor de servicios invocando
Program.BuildWebHost()
y accediendo a la propiedad
IWebHost.Services
.
agregue este método después del Método principal en Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Actualizar .net core 2.2
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
}
Otra posible solución :
Asegúrese de agregar
Dbcontext
a la inyección de dependencia:
AddDbContext<TContext>
hará que su tipo
TContext
,
TContext
y las
DbContextOptions<TContext>
correspondientes
DbContextOptions<TContext>
disponibles para la inyección desde el contenedor del servicio.
Esto requiere agregar un argumento constructor a su tipo
DbContext
que acepte
DbContextOptions<TContext>
.
Ejemplo: en Startup.cs
public class AppDbContext: DbContext
{
public AppDbContext(DbContextOptions<BloggingContext> options)
:base(options)
{ }
}
Código AppDbContext :
// required when local database deleted
public class ToDoContextFactory : IDesignTimeDbContextFactory<AppContext>
{
public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseSqlServer("Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true");
return new AppContext(builder.Options);
}
}
Actualización: establezca el Proyecto de aplicación web en "Establecer como proyecto de inicio"
Abra la Consola del Administrador de paquetes desde el menú
Tools
->
NuGet Package Manger
->
Package Manager Console
en Visual Studio para ejecutar los siguientes comandos.
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />
Nota: Use la opción
–verbose
para ver las declaraciones SQL que se aplican a la base de datos de destino. Contiene errores detallados.
por favor verifique que tiene la referencia
public static IWebHost MigrateDatabase(this IWebHost webHost)
{
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var db = services.GetRequiredService<MyContext>();
db.Database.Migrate();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while migrating the database.");
}
}
return webHost;
}
public static void Main(string[] args)
{
BuildWebHost(args)
.MigrateDatabase()
.Run();
}
No es necesario
IDesignTimeDbContextFactory
.
correr
add-migration initial -verbose
eso revelará los detalles bajo
Se produjo un error al acceder a IWebHost en la clase ''Programa''. Continuando sin el proveedor de servicios de aplicaciones.
advertencia, que es la causa raíz del problema.
En mi caso
, el problema era tener
ApplicationRole : IdentityRole<int>
e invocar
services.AddIdentity<ApplicationUser, IdentityRole>()
AddIdentity
services.AddIdentity<ApplicationUser, IdentityRole>()
que estaba causando el siguiente error
System.ArgumentException: GenericArguments[1], ''Microsoft.AspNetCore.Identity.IdentityRole'',
on ''Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,
TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]'' violates the constraint of type ''TRole''.
---> System.TypeLoadException: GenericArguments[1], ''Microsoft.AspNetCore.Identity.IdentityRole'',
on ''Microsoft.AspNetCore.Identity.UserStoreBase`8[TUser,TRole,TKey,TUserClaim,
TUserRole,TUserLogin,TUserToken,TRoleClaim]'' violates the constraint of type parameter ''TRole''.
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
Simplemente cambie el nombre de
BuildWebHost()
a
CreateWebHostBuilder()
, porque las migraciones usan este método de manera predeterminada.