ASP.NET MVC Initializer doesn't seed Database during Update-Database - c#

The tagged duplicate question uses a custom context, I'm using the default ApplicationDbContext.
I'm confused why data isn't seeded whenever I run Update-Database. I read the other questions with answers but unfortunately they're using a custom Context, I'm using the default ApplicationDbContext. They seem to have the same answers but they don't work on my end.
I have the following done;
I have a custom Initializer:
public class PostInitializer : DropCreateDatabaseAlways<ApplicationDbContext>
{
protected override void Seed(ApplicationDbContext db)
{
var posts = new List<Post>
{
new Post()
{
Content = "TestA"
},
new Post()
{
Content = "TestB"
}
};
posts.ForEach(p => db.Posts.Add(p));
db.SaveChanges();
}
}
In My Global Asax:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// call PostInitializer here
Database.SetInitializer(new PostInitializer());
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
My Model:
public class Post
{
[Key]
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime? DateTimeCreated { get; set; }
}
I've tried deleting the DB and running Update-Database after, however data still isn't seeded.

Write your PostInitializer as follows:
public static class PostInitializer
{
public static void Seed()
{
using (ApplicationDbContext dbContext = new ApplicationDbContext())
{
if (dbContext.Database.Exists())
{
if(!dbContext.Posts.Any())
{
var posts = new List<Post>
{
new Post()
{
Content = "TestA"
},
new Post()
{
Content = "TestB"
}
};
posts.ForEach(p => dbContext.Posts.Add(p));
dbContext.SaveChanges();
}
}
}
}
}
Then register it as follows:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
PostInitializer.Seed(); // <-- Here it is
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}

Ok my bad. What solved this was running the application. I thought the seeding would happen during Update-Database. This is what worked for me;
Run App
Access Controller with the Model concerned in Initializer, accessing at least the Index page worked for me (localhost/posts)
During Access, the Database will be dropped and created, then seeded with whatever specified in the Initializer
Close any SQL tabs on Visual Studio that is connected to the target DB as it might throw an error during Drop Database

Related

Missing Type Map Configuration Or Unsupported Mapping AutoMapper

I have this code:
public ActionResult Details(string id, string detailsDate)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var tblPersonnel = new tblPersonnel();
using (var _context = new ScalehouseModel()) // for disposing
{
tblPersonnel = _context.tblPersonnels.Find(id);
}
if (tblPersonnel == null)
{
return HttpNotFound();
}
Mapper.Initialize(config => config.CreateMap<tblPersonnel, PersonnelDetailsVm>());
PersonnelDetailsVm person = Mapper.Map<tblPersonnel, PersonnelDetailsVm>(tblPersonnel);
.... // and more but the error happens on the line above.
}
After an ajax success, I am redirecting to the Details page, which the action you can see above. I am getting run time errors like so:
I have researched this and disposed my EF, but still not working and getting same error.
What do I need to do to resolve this?
In order for auto mapper to work, best way is to add automapper configuration in pipeline.
Here is how you can do
Step 1: Create a static class Mapping profile, and add all your mappings in this class
public static class MappingProfile
{
public static MapperConfiguration InitializeAutoMapper()
{
MapperConfiguration config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<tblPersonnel, PersonnelDetailsVm>();
});
return config;
}
}
Step 2: Inorder to configure, register automapper configuration in Application_Start() method in Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//Add AutoMapper configuration here.
MappingProfile.InitializeAutoMapper();
}
Give it a try.

Can't write to response in Application_Start

In my Application_Start method I'm doing some setup and logging to my database. I had an issue where my connectionstring was wrong, which is not a big deal but I'd like to validate the database is available during Application_Start() and report back to the user if it's down.
Since the httpResponse isn't yet available I can't write something to the browser.
What other practical options do I have?
Here's a quick implementation of my suggestion.
Modify global.asax to have a public variable
public class MvcApplication : System.Web.HttpApplication
{
public static bool IsConfigured { get; set; }
Set IsConfigured = true as you leave Application_Start if everything is configured
Then add a ActionFilter like this
public class ConfiguredAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (MvcApplication.IsConfigured) return;
filterContext.Result = new ViewResult
{
ViewName = "Offline",
TempData = filterContext.Controller.TempData
};
}
}
Create your Offline view in the Shared views folder
Register your new filter
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ConfiguredAttribute());
}
}

C# EF Code first - init database (create table) and enable migrations

I'm updating a webform app to a mvc app but I have an issue.
I would like to create automatically the AspNetUsers tables when I try, for the first time,to log in through the webApp
Below the error messages:
The target context 'PROJECT.Data.DataContext' is not constructible.
Add a default constructor or provide an implementation of
IDbContextFactory.
Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for
databases created using Code First or Code First Migrations.
The first one is fired with the code below:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, MyConfiguration>());
public class MyConfiguration : DbMigrationsConfiguration<DataContext>
{
public MyConfiguration()
{
this.AutomaticMigrationsEnabled = true;
}
protected override void Seed(DataContext context)
{
InitializeIdentityForEF(context);
base.Seed(context);
}
public void InitializeIdentityForEF(DataContext db)
{
// create admin user with role and claims
}
}
The second one:
Database.SetInitializer(new ApplicationDbInitializer());
public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<DataContext>
{
protected override void Seed(DataContext context)
{
InitializeIdentityForEF(context);
base.Seed(context);
}
public void InitializeIdentityForEF(DataContext db)
{
// create admin user with role and claims
}
}
I think that I can fix this issue if I enable the the migration through the console but I would like to implement everything in the code. Any idea to mix theses two code above?
NOTE: I just want to create the AspNetUser table because I'm using "Database First" once they are created.
public class DataContext : DbContext, IEntitiesContext
{
private static readonly object Lock = new object();
private static bool _databaseInitialized;
public DataContext(string nameOrConnectionString, ILogger logger) : base(nameOrConnectionString)
{
Database.Log = logger.Log;
if (_databaseInitialized)
{
return;
}
lock (Lock)
{
if (!_databaseInitialized)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, MyConfiguration>());
Database.SetInitializer(new ApplicationDbInitializer());
_databaseInitialized = true;
}
}
}

Why is my Funq container not working properly?

I'm getting a null reference exception when hitting my code that tries to access the database.
This is in global.asax and I have stepped through the debugger and this code is being executed.
public class MvcApplication : System.Web.HttpApplication
{
public class DmsAppHost : AppHostBase
{
public DmsAppHost() : base("API", typeof(AppUsersService).Assembly) { }
public override void Configure(Funq.Container container)
{
var dbConnectionFactory = new OrmLiteConnectionFactory("Server=localhost;Port=5432;User Id=dms; Password=dms; Database=dms", PostgreSqlDialect.Provider);
container.Register<IDbConnectionFactory>(dbConnectionFactory);
container.RegisterAutoWiredAs<AppUserRepository, IAppUserRepository>();
}
}
protected void Application_Start()
{
new DmsAppHost().Init();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BootstrapSupport.BootstrapBundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
}
}
When I hit this code (using (var db = DbConnectionFactory.OpenDbConnection())) I am getting a NullReferenceException.
Object reference not set to an instance of an object.
public class AppUserRepository : IAppUserRepository
{
public IDbConnectionFactory DbConnectionFactory { get; set; }
public AppUser GetAppUserByUsername(string username)
{
AppUser appUser;
using (var db = DbConnectionFactory.OpenDbConnection())
{
appUser = db.QuerySingle<AppUser>(new { username });
}
return appUser;
}
}
Am I to assume something is wrong with my Connection or is there something I'm not doing right to make Funq work?
You have shown some Funq container configuration that is injecting dependencies into your AppUserRepository class. But you haven't shown how and where is this class used. Since your question is tagged with asp.net-mvc I assume that this happens inside an ASP.NET MVC controller action. Something along the lines of:
public class HomeController: Controller
{
private readonly IAppUserRepository repo;
public HomeController(IAppUserRepository repo)
{
this.repo = repo;
}
public ActionResult Index(int id)
{
var model = this.repo.Get(id);
return View(model);
}
}
If you want to use a dependency injection framework in ASP.NET MVC you will have to write a custom dependency resolver which will do the injection into the controllers.
So let's go ahead and write one for Funq:
public class FunqDependencyResolver : IDependencyResolver
{
private readonly ContainerResolveCache cache;
public FunqDependencyResolver(Container container)
{
this.cache = new ContainerResolveCache(container);
var controllerTypes =
(from type in Assembly.GetCallingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(type)
select type).ToList();
container.RegisterAutoWiredTypes(controllerTypes);
}
public object GetService(Type serviceType)
{
return this.cache.CreateInstance(serviceType, true);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return Enumerable.Empty<object>();
}
}
and then we could register it in Application_Start:
protected void Application_Start()
{
var container = new Container();
var dbConnectionFactory = new OrmLiteConnectionFactory("Server=localhost;Port=5432;User Id=dms; Password=dms; Database=dms", PostgreSqlDialect.Provider);
container.Register<IDbConnectionFactory>(dbConnectionFactory);
container.RegisterAutoWiredAs<AppUserRepository, IAppUserRepository>();
DependencyResolver.SetResolver(new FunqDependencyResolver(container));
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BootstrapSupport.BootstrapBundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
}
Also I would recommend you using constructor injection for your AppUserRepository class because the DbConnectionFactory is an absolutely required dependency for this class to work properly:
public class AppUserRepository : IAppUserRepository
{
private readonly IDbConnectionFactory dbConnectionFactory;
public class AppUserRepository(IDbConnectionFactory dbConnectionFactory)
{
this.dbConnectionFactory = dbConnectionFactory;
}
public AppUser GetAppUserByUsername(string username)
{
AppUser appUser;
using (var db = this.dbConnectionFactory.OpenDbConnection())
{
appUser = db.QuerySingle<AppUser>(new { username });
}
return appUser;
}
}
Tell the container how to resolve IAppUserRepository with the following configuration.
container.RegisterAutoWiredAs<AppUserRepository, IAppUserRepository>();
RegisterAutoWiredAs will inject the IDbConnectionFactory dependency
You're not showing how your resolve IAppUserRepository, but with Funq you would have to do any project injection in your factory delegate instance when you register the abstraction.
See http://funq.codeplex.com/discussions/217686 for more info.
your problem is that DbConnectionFactory doesn't becomes an object so it is still null
it's like you would do this
public TextBlock nullBlock; // it's your public IDbConnectionFactory DbConnectionFactory { get; set; }
nullBlock.Text; // DbConnectionFactory.OpenDbConnection()
you need to set an object
in your case something like
var obj = new AppUserRepository();
obj.DbConnectionFactory = .... //
additional if you fill it in some hidden code
you should do this and set a breakpoint maybe your overhanded object is null
private IDbConnectionFactory _dbConnectionFactory
public IDbConnectionFactory DbConnectionFactory
{
get {return _dbConnectionFactory; }
set {_dbConnectionFactory=value;}
}

Entity Framework Migrations - Enable AutoMigrations along with added migration

I'm utilizing Entity Framework 4.3 Migrations in my project. I would like to use Automatic migrations so that when I make modifications to my domain objects and my context class, my database automatically updates when I run the project. I have this working so far.
I would also like to use some Added Migrations in addition to the automatic migrations, and I would like the application to automatically jump to the latest version (based on my added migrations) when I run the application.
In order to do this I have placed this in the global.asax file...
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Core.Migrations.Configuration>());
Now this works, but when I do this it no longer automatically updates the database based on my domain objects.
I would like to be able to completely delete the database and then run the application and have all the automatic migrations run and then have my explicit migrations run and bring the database up to the latest version.
I know I've had this working in a previous project, but I'm not sure what I'm doing wrong in this instance.
Thanks
You need to pass a configuration that has the AutomaticMigrationsEnabled set to true in the constructor. Something like this should help:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyConfiguration>());
with MyConfiguration being something like:
public class MyConfiguration : Core.Migrations.Configuration
{
public MyConfiguration { this.AutomaticMigrationsEnabled = true; }
}
DISCLAIMER: Just hacked this in, so small tweaks might be required to get this to compile
EDIT:
Just checked with EF 4.3.1 and the code is like this for the initializer:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, MyConfiguration>());
and this for the configuration class:
public class MyConfiguration : System.Data.Entity.Migrations.DbMigrationsConfiguration<DataContext>
{
public MyConfiguration()
{
this.AutomaticMigrationsEnabled = true;
}
}
After banging my head on this for several hours, I finally came up with a solution that creates the database if necessary or upgrades it if out of date. We use this technique in Gallery Server Pro to make it easy to install the first time or upgrade previous versions.
private static void InitializeDataStore()
{
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
var configuration = new GalleryDbMigrationConfiguration();
var migrator = new System.Data.Entity.Migrations.DbMigrator(configuration);
if (migrator.GetPendingMigrations().Any())
{
migrator.Update();
}
}
public sealed class GalleryDbMigrationConfiguration : DbMigrationsConfiguration<GalleryDb>
{
protected override void Seed(GalleryDb ctx)
{
MigrateController.ApplyDbUpdates();
}
}
I wrote up a blog post with a few more details:
Using Entity Framework Code First Migrations to auto-create and auto-update an application
Same solution that Roger did but using an static constructor on the DbContext.
Full code below.... this allow the initialization code to live on the class itself and is self-invoked at the first instantiation of the DataDbContext class.
public partial class DataDbContext : DbContext
{
public DataDbContext()
: base("name=DefaultConnection")
{
}
static DataDbContext() // This is an enhancement to Roger's answer
{
Database.SetInitializer(new DataDbInitializer());
var configuration = new DataDbConfiguration();
var migrator = new DbMigrator(configuration);
if (migrator.GetPendingMigrations().Any())
migrator.Update();
}
// DbSet's
public DbSet<CountryRegion> CountryRegion { get; set; }
// bla bla bla.....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
//Configuration.ValidateOnSaveEnabled = false;
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); // Discover and apply all EntityTypeConfiguration<TEntity> of this assembly, it will discover (*)
}
}
internal sealed class DataDbInitializer : MigrateDatabaseToLatestVersion<DataDbContext, DataDbConfiguration>
{
}
internal sealed class DataDbConfiguration : DbMigrationsConfiguration<DataDbContext>
{
public DataDbConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(DataDbContext context)
{
DataSeedInitializer.Seed(context);
base.Seed(context);
}
}
internal static class DataSeedInitializer
{
public static void Seed(DataDbContext context)
{
SeedCountryRegion.Seed(context);
// bla bla bla.....
context.SaveChanges();
}
}
internal static class SeedCountryRegion
{
public static void Seed(DataDbContext context)
{
context.CountryRegion.AddOrUpdate(countryRegion => countryRegion.Id,
new CountryRegion { Id = "AF", Name = "Afghanistan" },
new CountryRegion { Id = "AL", Name = "Albania" },
// bla bla bla.....
new CountryRegion { Id = "ZW", Name = "Zimbabwe" });
context.SaveChanges();
}
}
public class CountryRegionConfiguration : EntityTypeConfiguration<CountryRegion> // (*) Discovered by
{
public CountryRegionConfiguration()
{
Property(e => e.Id)
.IsRequired()
.HasMaxLength(3);
Property(e => e.Name)
.IsRequired()
.HasMaxLength(50);
}
}
public partial class CountryRegion : IEntity<string>
{
// Primary key
public string Id { get; set; }
public string Name { get; set; }
}
public abstract class Entity<T> : IEntity<T>
{
//Primary key
public abstract T Id { get; set; }
}
public interface IEntity<T>
{
T Id { get; set; }
}
We can see that the Seed method is running again and again..
We can avoid this by checking if a migration already exits, since one is applied automatically when the database is create.. then we can refactor the DataDbConfiguration as follows...
internal sealed class DataDbConfiguration : DbMigrationsConfiguration<DataDbContext>
{
private readonly bool _isInitialized;
public DataDbConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
var migrator = new DbMigrator(this);
_isInitialized = migrator.GetDatabaseMigrations().Any();
}
protected override void Seed(DataDbContext context)
{
InitializeDatabase(context);
}
public void InitializeDatabase(DataDbContext context)
{
if (!_isInitialized)
{
if (context.Database.Connection.ConnectionString.Contains("localdb"))
{
DataSeedInitializer.Seed(context); // Seed Initial Test Data
}
else
{
// Do Seed Initial Production Data here
}
}
else
{
// Do any recurrent Seed here
}
}
}
Here is my current solution, which I'm not completely satisfied with.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var context = new KCSoccerDataContext();
var initializeDomain = new CreateDatabaseIfNotExists<KCSoccerDataContext>();
var initializeMigrations = new MigrateDatabaseToLatestVersion<KCSoccerDataContext, Core.Migrations.Configuration>();
initializeDomain.InitializeDatabase(context);
initializeMigrations.InitializeDatabase(context);
}
I'm actually creating two different initializers. The first, using CreateDatabaseIfNotExists, succcessfully goes through and creates tables based on my Domain objects. The second, using MigrateDatabaseToLatestVersion, executes all of my explicit migrations.
I don't like it because Automatic Migrations are basically disabled. So in order to add or change my Domain model I have to completely drop the database and recreate it. This won't be acceptable once I've moved the application to production.
If your application contains Startup.cs class, you can use DbMigrator Class as follows
Go to your App_Start folder, open Startup.Auth
Paste these lines of code inside of ConfigureAuth method
var configuration = new Migrations.Configuration();
var dbmigrator = new DbMigrator(configuration);
dbmigrator.Update();
NOTE: Remember to use this namespace- using System.Data.Entity.Migrations;
what this does is to update your database to the latest version anytime the application starts up
You just need to do
private static void InitializeDataStore()
{
System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<GalleryDb, GalleryDbMigrationConfiguration>());
System.Data.Entity.Database.Initialize(false);
}

Categories

Resources