Migrations Seed Method Ignores Seed Method of Database Initializer - asp.net

I'm working on an Asp.Net Mvc application then i want to seed my database using custom Database initializer class that I created.
so here is my DbContext :
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> {
public ApplicationDbContext()
: base("defaultConnection", throwIfV1Schema: false) {
}
static ApplicationDbContext() {
Database.SetInitializer(new ApplicationDbInitializer());
}
and here is my ApplicationDbInitializer class :
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext> {
protected override void Seed(ApplicationDbContext context) {
InitializeIdentityForEF(context);
base.Seed(context);
}
public static void InitializeIdentityForEF(ApplicationDbContext db) {
// Create Role Admin if it does not exist
// Add user admin to Role Admin if not already added
// And some more initializing stuff
}
}
Note: I'm using Migrations too.
so when i try to update and seed my database using command Update-Database (even if I delete database manually) , the database is being created but it does not seed it.
if I am doing anything wrong or it has other ways I'll be thankful to get your assistance.

This sounds like the same issue as in this question.
So, the seed code will only run when you create an instance of your ApplicationDbContext.
Add some code like this to your application startup:
var ctx = new ApplicationDbContext();
ctx.Database.Initialize(true);
Then your database will be seeded the next time your app starts.
Alternatively, if you wanted to use the Update-Database command to seed your database, that uses a different Seed method. You can see an example here.

Related

Database.Migrate method

i want to apply migrations automatically for my app
so i used this method
Database.Migrate()
Applies any pending migrations for the context to the database. Will create the database if it does not already exist.
so as i understood when i run my application it should do as follow
1- create database if it doesn't exist
2- update database => apply migration to database
but when I run my project nothing happens
i write command manually to apply database and it's work but i don't know where is the problem
this is my code
dbContext
using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;
using brokerTest.Entites;
namespace brokerTest.Brokers.Sotrage
{
public class StorageBroker : DbContext , IStorageBroker
{
private readonly IConfiguration configuration;
public StorageBroker(IConfiguration configuration)
{
this.configuration = configuration;
this.Database.Migrate();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){
var connectionString = this.configuration.GetConnectionString("DefaultConnection");
optionsBuilder.UseSqlServer(connectionString);
}
public DbSet<User> Users { get; set; }
}
}
startup.cs
services.AddDbContext<StorageBroker>();
services.AddScoped<IStorageBroker, StorageBroker>();
appsettingfile.json
{
"ConnectionStrings": {
"DefaultConnection": "server=(localdb)\\MSSQLLocalDB;Database=testDb"
},
Package installed
.NET 6 , Microsoft.EntityFrameworkCore.Design 5.0.8
Microsoft.EntityFrameworkCore.SqlServer 5.0.8
i found that class dbContext was not called at all because I didn't inject it with any controller or class
after i inject dbContext to my controller class
[ApiController]
[Route("/home")]
public class HomeController : Controller
{
private readonly IStorageBroker _storageBrodker;
public HomeController(IStorageBroker storageBroker)
{
_storageBrodker = storageBroker;
}
when i call route /home class is called then migrations apply
i thought it's called because i register it in services
but i didn't know it's called when need to resolve
and the comment for Sasan provide another way to do that from main when build iHost object
https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying?tabs=dotnet-core-cli#apply-migrations-at-runtime

EF not creating identity table when trying to create new database

I have 2 model classes:
Customer.cs with name and Id
Movies.cs with name and Id
I tried to run enable-migrations, but I got this error:
No context type was found in the assembly WebApplication2'.
Then I saw some answers on websites and people told to make a DBContext class. I do not have any DBContext class as I just made a new MVC project.
So, I tried to make a DbContext class of my own as follows:
{
public class MyDBContext:DbContext
{
public void MyDbContext()
{
}
}
}
Then I was able to run enable-migrtaions command and Migration folder was created with configuration.cs as follows:
internal sealed class Configuration : DbMigrationsConfiguration<WebApplication2.Models.MyDBContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(WebApplication2.Models.MyDBContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
}
}
}
Now when I run the add-migration Initialmodel the Up() and Down() methods are empty and there are no Identity tables.
Please help !
First off I suggest you refer to creating a new MVC project using Entity Framework. There are a lot of tutorials but here's the Microsoft one which is accurate and pretty complete:
Get Started with Entity Framework 6 Code First using MVC 5
It also includes a section on Migrations, however you don't need Migrations until you have a database and a model that's changing.
I would suggest backing out your Migrations until we're ready for them. Rick Strahl has a good article on how to back them out and get back to a clean state:
Resetting Entity Framework Migrations to a clean State
Finally, your DbContext class has to have a DbSet. A DbSet class is an entity set that can be used for create, read, update, and delete operations. With your DbContext class as it is, Entity Framework has no idea what to do or map.
Change your DbContext class to something like this:
{
public class MyDBContext:DbContext
{
public void MyDbContext()
{
}
public virtual DbSet<Movie> Movies {get; set;}
public virtual DbSet<Customer> Customers {get; set;}
}
This will allow you (say in a Controller) to do something like this to add a new Customer to the database:
var customer = new Customer { name = "John Smith" };
using(var context = new MyDbContext())
{
context.Customers.Add(customer); // adds the customer to the DbSet in memory
context.SaveChanges(); // commits the changes to the database
}
NOTE: I don't recommend creating a DbContext this way in a controller, in the first link on using EF6 with MVC 5 there are better ways.
Hope that helps.

Get database name within Up method of Migration

How do I get the name of the database that a migration is operating over from within the Up (or Down) method of a class that extends Migration
public class BaseMigration : Migration
{
public override void Up()
{
var databaseName = HOW_DO_I_GET_THIS?
}
}
You can derive the database name from the connection string if you have it specified there. For example, this will work if you're using SQL server:
public class BaseMigration : Migration
{
public override void Up()
{
System.Data.SqlClient.SqlConnectionStringBuilder builder =
new System.Data.SqlClient.SqlConnectionStringBuilder(ConnectionString);
var databaseName = builder.InitialCatalog;
}
}
Otherwise, use one of the other available
System.Data.Common.DbConnectionStringBuilder implementations:
System.Data.EntityClient.EntityConnectionStringBuilder
System.Data.Odbc.OdbcConnectionStringBuilder
System.Data.OleDb.OleDbConnectionStringBuilder
System.Data.OracleClient.OracleConnectionStringBuilder
See this stackoverflow post for more information.

Renaming dbo.AspNetUsers table

I'm trying to rename the default table names generated by ASP.net Identity 2.0. I read all the articles, the questions and the answers on stackoverflow but im still getting the same error.
I renamed the tables to Roles, UserClaims, Logins, UserRoles and Users. I also changed the application dbcontext to the following
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("Users", "dbo");
modelBuilder.Entity<IdentityRole>().ToTable("Roles", "dbo");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles", "dbo");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims", "dbo");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins", "dbo");
}
}
But i keep getting the Invalid object name 'dbo.AspNetUsers'. error, and I have no idea why its still trying to locate AspNetUsers in the first place instead of just Users although i made the changes above. Totally desperate by now.
The database as well, same columns with the new table names:
And the SQL database project:
You need to update database. Enable-Migrations and Update-Database, explained in details here. The point of EF code first approach is to write our model classes and configurations and each time we change something we use EF migrations to update the database schema.
Database first approach with asp.net-identity-entityframework are explained here and here, not so straightforward
Write the following code in IdentityModels.cs
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DBConnectionString", throwIfV1Schema: false)
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
modelBuilder.Entity<ApplicationUser>().ToTable("Users");
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Write the following code in Application_Start() Method in Global.asax.cs file
Database.SetInitializer<ApplicationDbContext>(null);

How can you inject an asp.net (mvc2) custom membership provider using Ninject?

OK, so I've been working on this for hours. I've found a couple of posts here, but nothing that actually resolves the problem. So, let me try it again...
I have an MVC2 app using Ninject and a custom membership provider.
If I try and inject the provider using the ctor, I get an error: 'No parameterless constructor defined for this object.'
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider(IMyRepository repository)
{
_repository = repository;
}
I've also been playing around with factories and Initialize(), but everything is coming up blanks.
Any thoughts/examples?
The Membership provider model can only instantiate a configured provider when it has a default constructor. You might try this using the Service Locator pattern, instead of using Dependency Injection. Example:
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider()
{
// This example uses the Common Service Locator as IoC facade, but
// you can change this to call NInject directly if you wish.
_repository = ServiceLocator.Current.GetInstance<IMyRepository>;
}
This is how I was able to do this:
1) I created a static helper class for Ninject
public static class NinjectHelper
{
public static readonly IKernel Kernel = new StandardKernel(new FooServices());
private class FooServices : NinjectModule
{
public override void Load()
{
Bind<IFooRepository>()
.To<EntityFooRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["FooDb"].ConnectionString);
}
}
}
2) Here is my Membership override:
public class FooMembershipProvider : MembershipProvider
{
private IFooRepository _FooRepository;
public FooMembershipProvider()
{
NinjectHelper.Kernel.Inject(this);
}
[Inject]
public IFooRepository Repository
{
set
{
_FooRepository = value;
}
}
...
With this approach it doesn't really matter when the Membership provider is instantiated.
I had the same problem at the exact same spot in the book. It wasn't until later on in the book that I noticed there were two separate web.config files. I initially placed my connectionString key in the wrong web.config file. It wasn't until I placed the connectionString in the correct web.config file that the 'no parameterless constructor' error went away.

Resources