2

I have an Azure MVC Web app and a corresponding WebJob using Code First / Entity Framework 6. My database is first created locally (localdb) during the add-migration/update-database process. Everything gets created just fine, the seed method populates a bunch of preset data and the app runs fine. I then publish the Web App to Azure from VS 2015 and manually deploy the DB to Azure using the "Deploy Database to Windows Azure Database" option within SQL Management Studio. The DB deploys and the Web App runs on Azure without any issues.

The problem appears when the WebJob is triggered (via a QueueTrigger). The WebJob is also using EF and it's own instance of my DbContext (due to WebJob parallelism and EF not being thread safe, I have a using statement inside my WebJOb method to instantiate the DbContext on each call). Note, my DbContext is setup with a "null" initializer ("Database.SetInitializer(null);"). This I thought prevent the exact problem I am experiencing.

When the WebJob starts, it seems to try to run migrations. The first error I got was System.Data.SqlClient.SqlException: Database '<MyDbName>' already exists. Choose a different database name. Which implied it was trying to do a DB create when it should not have.

I then tried deleting the contents of the __MigrationHistory table to try to stop any migration trigger, but go this error: System.NotSupportedException: 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.

No matter what I try, the WebJob will not succeed and it looks like it's due to not honoring my null DbInitializer, but I am not sure. The web app side never has the problem.

It's also worth noting that the problem does not exist when running locally. If I start the WebJob in debug mode under VS, it runs perfectly and accesses the localdb version of my database with problem. The problem only exists in "live" Azure.


Update:

When looking at the detailed error log from Azure for the WebJob, it seems pretty clear that the job is triggering a migration attempt despite my best efforts:

   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
   at System.Data.Entity.SqlServer.SqlProviderServices.UsingConnection(DbConnection sqlConnection, Action1 act)
   at System.Data.Entity.SqlServer.SqlProviderServices.UsingMasterConnection(DbConnection sqlConnection, Action1 act)
   at System.Data.Entity.SqlServer.SqlProviderServices.CreateDatabaseFromScript(Nullable1 commandTimeout, DbConnection sqlConnection, String createDatabaseScript)
   at System.Data.Entity.SqlServer.SqlProviderServices.DbCreateDatabase(DbConnection connection, Nullable1 commandTimeout, StoreItemCollection storeItemCollection)
   at System.Data.Entity.Core.Common.DbProviderServices.CreateDatabase(DbConnection connection, Nullable1 commandTimeout, StoreItemCollection storeItemCollection)
   at System.Data.Entity.Core.Objects.ObjectContext.CreateDatabase()
   at System.Data.Entity.Migrations.Utilities.DatabaseCreator.Create(DbConnection connection)
   at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
   at System.Data.Entity.Internal.DatabaseCreator.CreateDatabase(InternalContext internalContext, Func3 createMigrator, ObjectContext objectContext)
   at System.Data.Entity.Internal.InternalContext.CreateDatabase(ObjectContext objectContext, DatabaseExistenceState existenceState)
   at System.Data.Entity.Database.Create(DatabaseExistenceState existenceState)
   at System.Data.Entity.DropCreateDatabaseIfModelChanges1.InitializeDatabase(TContext context)
   at System.Data.Entity.Internal.InternalContext.<>c__DisplayClassf1.<CreateInitializationAction>b__e()
   at System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
   at System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
   at System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)
   at System.Data.Entity.Internal.RetryAction1.PerformAction(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action1 action)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
   at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
   at System.Data.Entity.Internal.Linq.InternalSet1.Initialize()
   at System.Data.Entity.Internal.Linq.InternalSet1.get_InternalContext()
   at System.Data.Entity.Internal.Linq.InternalSet1.FindAsync(CancellationToken cancellationToken, Object[] keyValues)
   at System.Data.Entity.DbSet1.FindAsync(CancellationToken cancellationToken, Object[] keyValues)
   at System.Data.Entity.DbSet1.FindAsync(Object[] keyValues)
   at Repository.Pattern.Ef6.Repository1.<FindAsync>d__19.MoveNext()

The calls to InitializeDatabase and DropCreateDatabaseIfModelChanges1, seem clear that my null SetInitilizer is not having the intended effect when running on Azure. I'm stumped.

Bryan Lewis
  • 5,629
  • 4
  • 39
  • 45
  • 1
    It looks like you have an EF problem, not a WebJob problem. I can assure you that if you deleted the _MigrationsHistory table and you do have migrations in your current solution, this is not going to work. My suggestion is to recreate your SQL Azure Db and try to connect to it running your Webjob locally pointing to SQL Azure. That's going to help you debug your app. – lopezbertoni Dec 10 '15 at 23:39
  • 1
    I took your suggestion and changed all of the local DB connection strings to point to my real Azure SQL DB. I ran the add-migration and update-database calls against the azure database, everything looked good. When running the Web app and WebJob locally but pointing everything at the Azure SQL DB, it ran flawlessly. I had high hopes. HOWEVER, I then published the app to Azure. The Web App continued to work great (DB was fine, read, write, update) but as soon as the WebJob was triggered, it nuked the database. The DB still exists, but ALL tables got deleted. What's different? – Bryan Lewis Dec 11 '15 at 02:01
  • Can you paste the code in your EF DataContext and you .config files? – lopezbertoni Dec 11 '15 at 02:03
  • Another thing to check is whether you have a Configuration class that might be setting AutomaticMigrationsEnabled = true (explained more here https://msdn.microsoft.com/en-us/magazine/dn818489.aspx). Another thing to check: Database.SetInitializer is a static method - make sure you're not pulling in some other dependency that might be setting a non-null initializer. Also make sure you're setting this initializer to null as early as possible on startup. – mathewc Dec 11 '15 at 03:02
  • 1
    My Configuration class has an explicit "AutomaticMigrationsEnabled = false;" in the constructor. Honestly, I am not sure how to check that I am not pulling in some non-null initializer. I tried adding an explicit call to Database.SetInitializer(null); directly above my using statement in my WebJob method to call it as "early" as possible. No difference. I am still confused why this only happens on Azure and NOT when I am running locally, even against the Azure DB. Because the WebJob is running under the Web App environment on Azure and only as a console app locally? – Bryan Lewis Dec 11 '15 at 04:02
  • Ok, I found a SO post (http://stackoverflow.com/questions/14654055/how-can-i-disable-code-first-migrations) that might explain your mystery. It says that if you've ever done migrations (if there is a __MigrationHistory table in your DB) then setting the initializer will not have any effect. That post tells you how to disable the migrations completely, then you should be good. Sometimes too much magic is too much trouble :) – mathewc Dec 13 '15 at 05:28
  • Thanks for the pointer, but I had already seen this message. I tried deleting the __MigrationHistory table, which only caused a different error. I tried keeping migrations but using the -Script option. So instead of having the DB auto-created and seeded, I used the script and then seeded the DB myself with a sql script. STILL failed. Same problem. No matter what, the migration is triggered by the WebJob, but NOT the web app. – Bryan Lewis Dec 13 '15 at 21:16
  • Now, how about this for crazy? I rewrote the WebJob to use ADO.Net only. No EF. All EF/DI packages removed from the project. The WebJob ran perfectly when launched as a console app in debug mode locally. Guess what? I published to Azure and it STILL triggered a migration and nuked the DB? Again, the web app side works fine on Azure. The problem only occurs on the first trigger of this WebJob, which now doesn't have EF! I can only think it's somehow triggering the EF on the MVC side? I am going to try to publish WebJob separately. – Bryan Lewis Dec 15 '15 at 01:53
  • Did you ever get to the bottom of this? I'm about to try to use EF from a webjob function and would also like to use a null initializer to make sure no database-management operations are attempted. Any insights on pitfalls would be appreciated! – sammy34 Mar 08 '17 at 17:58
  • @sammy34 Sorry, I never did solve this. I changed all of my WebJobs to use Dapper instead. It works great. Sorry I can't be more helpful. – Bryan Lewis Mar 09 '17 at 18:48

0 Answers0