EntityFramework Code first migrations not running after deploying to Azure

I'm developing a web application in ASP.NET using code first migrations. It works fine locally but after deploying to Azure, code first migrations are not executed. I have been following this tutorial step by step a few times but I have not been able to spot what is wrong on my setup. Here is the relevant code:

DB Context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}

    public DbSet<BC_Instance> BiocloudInstances { get; set; }

    static ApplicationDbContext() {}

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
           "SoftDeleteColumnName",
           (type, attributes) => attributes.Single().ColumnName);

        modelBuilder.Conventions.Add(conv);
    }
}

Connection strings:

(it is replaced on publish, but just in case)

<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=bcplatform2;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /></connectionStrings>

Code First Migrations configuration

internal sealed class Configuration : DbMigrationsConfiguration<bcplatform2.Models.ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(bcplatform2.Models.ApplicationDbContext context)
    {
        var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
        var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context));
        const string name = {name here};
        const string password = {pass here};
        const string adminRole = {role};
        string[] roles = new string[] { adminRole, ApplicationRole.DefaultRoleName };

        foreach (string role in roles)
        {
            if (!context.Roles.Any(r => r.Name == role))
            {
                roleManager.CreateAsync(new ApplicationRole(role));
            }
        }

        if (!context.Users.Any(u => u.UserName == name))
        {
            var user = new ApplicationUser { UserName = name, Email = name, credit = 10 };

            userManager.Create(user, password);
            userManager.AddToRole(user.Id, adminRole);
            userManager.SetLockoutEnabled(user.Id, false);
        }
    }
}

Publication wizard

Entity framework section in deployed Web.config

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="mssqllocaldb" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
  <contexts>
    <context type="bcplatform2.Models.ApplicationDbContext, bcplatform2">
      <databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[bcplatform2.Models.ApplicationDbContext, bcplatform2], [bcplatform2.Migrations.Configuration, bcplatform2]], EntityFramework, PublicKeyToken={token}">
        <parameters>
          <parameter value="DefaultConnection_DatabasePublish" />
        </parameters>
      </databaseInitializer>
    </context>
  </contexts>
</entityFramework>

Connection strings in deployed Web.config

<connectionStrings>
  <add name="DefaultConnection" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User Id={user};Password={password}" providerName="System.Data.SqlClient" />
  <add name="DefaultConnection_DatabasePublish" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User ID={user};Password={password}" providerName="System.Data.SqlClient" />
</connectionStrings>

Answers


You can update your Web.config file in Solution

It's not necessary provide connection string inside "context" section, because you already provide it in ApplicationDbContext constructor.

Also, with this config, you can uncheck "Execute code first migration" in Publication Wizard.

Your EF section should look similar to this (most important is "context" section):

<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
  <parameters>
    <parameter value="mssqllocaldb" />
  </parameters>
</defaultConnectionFactory>
<providers>
  <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
<contexts>
  <context type="TestWebApp.Models.AppContext, TestWebApp">
    <databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[TestWebApp.Models.AppContext, TestWebApp], [TestWebApp.Migrations.Configuration, TestWebApp]], EntityFramework" />
  </context>
</contexts>


It is not working because you might have created/selected other connection in deploy wizard. Same is confirmed in the deployed connection string where you can see two connnection strings.

The second connection string is also referecened in EF seciton -

And, in the context you have used first connectionstring - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}

Changing name here will solve your issue.


if you want to have more control on the migration process you can handle the migration in the Startup.Auth by creating the context and use the DBMigrator() class to apply any pending migration:

//Get the connection string
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"];

//Instanciate the sql connection string builder
var builder = new System.Data.SqlClient.SqlConnectionStringBuilder(connectionString.ConnectionString);

//Create your context
var dbContext = new ApplicationDbContext(builder.ConnectionString);

//Check for null (Handle issue here).
if (dbContext == null) return;

//Get your configuration and specify the target database
var config = new Migrations.Configuration();
config.TargetDatabase = new DbConnectionInfo(builder.ConnectionString, "System.Data.SqlClient");

//Create the migrator using your config
var mig = new DbMigrator(config);

//Check for any pending migration to speed up the process and Update
//The migration will be applied here each time the application is published on azure   
if(mig.GetPendingMigrations().Any())mig.Update();

While this may not solve your issue directly, it allow more control and you should be able to see if the migration is not applied with a little debbuging.


The problem was on the seed method:

protected override void Seed(bcplatform2.Models.ApplicationDbContext context)
{
    var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
    var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context));
    const string name = {name here};
    const string password = {pass here};
    const string adminRole = {role};
    string[] roles = new string[] { adminRole, ApplicationRole.DefaultRoleName };

    foreach (string role in roles)
    {
        if (!context.Roles.Any(r => r.Name == role))
        {
            roleManager.CreateAsync(new ApplicationRole(role));
        }
    }

    if (!context.Users.Any(u => u.UserName == name))
    {
        var user = new ApplicationUser { UserName = name, Email = name, credit = 10 };

        userManager.Create(user, password);
        userManager.AddToRole(user.Id, adminRole);
        userManager.SetLockoutEnabled(user.Id, false);
    }
}

It did not complete but didn't show any error on the publication output making the error difficult to spot. I removed the seed method and the migrations worked.

Some advice to avoid similar problems in the future would be not use the "Use this connection string at runtime" and "Execute code first migrations" options from the publication wizard. If something goes wrong the output won't always show an error and it gives little control over how Web.config is modified.

Instead, replace the connection string in Web.config before publishing or configure the Web.Debug.config and Web.Release.config accordingly.


Need Your Help

Connecting to mongoHQ with mongojs on heroku

node.js mongodb heroku mongohq mongojs

I am trying to connect to mongoHQ from my node.js app.

EF Migrations on CI Build Server

entity-framework migration continuous-integration

I run the migrations within Visual Studio's package manager. I am currently on the process of setting up a CI for our project. I was wondering how can you update the database from the CI (since you...