Deploy Entity Framework Core 2.1 Migrations from a DLL

by

We’ve got a new version of .NET Core and a new version of Entity Framework Core (EF Core).  Unfortunately, EF Core 2.1 hasn’t made it any easier to deploy database migrations from DLLs rather than from the source code.  (sigh)  Deploying EF Core migrations from DLLs is a key feature for DevOps CI/CD stuff — especially if you’re doing “The Right Thing” and splitting your builds from your releases.  For example, using VSTS Builds to compile your code and then VSTS Releases to deploy your apps into one or more environments.

Thankfully, there are options.  If you’re trying to deploy EF migrations from TFS or VSTS, you can use my Build & Release Tools extension.  If you’re using something else, I’ve got a batch script for you.  I’ve been maintaining both of these for a while and with this release, I’ve taken some suggestions from the community and added some new features.

Option #1: TFS / VSTS Extension

It’s free.  Go download and install this extension.  After you’ve installed that extension, you can add the Deploy Entity Framework Core Migrations step to your build definition or release definition.

The updated version that I pushed out on 7/4/2018 now give you the option to split your Entity Framework code & migrations DLL from the startup project that you’ll use to deploy your migrations.  For example, if you’ve got an ASP.NET Core web project and then also an API project that has your EF stuff in it, the new version of the extension now handles this.

In order to enable this, the extension now requires that you provide the class name of your DbContext.  Don’t worry…you don’t have to provide the full namespace.  You just have to provide the class name.  This new feature also lets you have multiple DbContext classes in your code and each of those DbContexts can have their own migrations.

To support how all the Entity Framework dependencies are now handled in .NET Core, you’ll need to provide the name of your runtimeconfig.json file for your deployed application.  If you don’t do this, you’ll run into errors where your EF Core dependencies won’t properly resolve.

Option #2: Batch Script

I originally wrote a batch script for EF Core v1 and included it in a blog post and then updated it for EF Core 2.0. This script does almost exactly the same thing as what “dotnet ef database update” does except that it references your already compiled DLLs instead of your source code.

One of the hardest parts of scripting this is trying to figure out where ef.dll is on disk.  The script tries to find ef.dll in a couple different places but if it can’t find it, the script will fail.  If you don’t want to deal with that uncertainty, you can now just manually put ef.dll into the same directory as the script and the script will use that copy.

There are a handful of minor changes to the args for this new version of the script.  The first argument is now the filename for your migrations DLL (it used to be just the namespace).  There are now a couple of optional args.  Argument #2 is the startup DLL filename and argument #3 is your DbContext class name.

deploy-ef2dot1-migrations.bat migrationsDllName [startupDllName] [dbContextClassName]

The startup DLL filename arg is handy for that multi-DLL scenario that I discussed above.  The DbContext class name arg is helpful for when you have multiple DbContext classes in your project.

Here’s a link to download the EF Core 2.1 migration deploy script.

Anyway, I hope this helps.

-Ben

 

— Looking for help with Entity Framework Core?  Need some assistance getting EF Core working with your team’s DevOps pipelines?  Want someone to come help your team figure out why integrating, building your code, and deploying your apps is so difficult and make it a whole lot less difficult?  We can help.  Drop us a line at info@benday.com.   

 

17 Responses to "Deploy Entity Framework Core 2.1 Migrations from a DLL"
  1. Thanks for updating the VSTS Extension to support Entity Framework Core 2.1. Anyway, I have still problems using it, because before it picked up the connectionstring from appsettings.json, but now it seams like it picks up appsettings.Development.json (and I don’t have same users defined in my local development environment and on the server where I’m deploying the application). Any ideas?

    • It’s almost definitely because of a rogue environment variable. Go look for “ASPNETCORE_ENVIRONMENT” on that system. It’s probably set to ‘development’ and that’s what’s triggering the load of appsettings.development.json.

      • The log says: “Using environment ‘Development’.”
        I have not set any environment-variable “ASPNETCORE_ENVIRONMENT=Development” on this system. The VSTS Extension used to work until Entity Framework Core 2.0, and I did no changes to any environment-variables.
        Maybe Development is default environment? Is it possible to override in the VSTS Extension?

      • I’m still not sure where ASPNETCORE_ENVIRONMENT i set. Anyway solved my problem by overriding environment in DbContextFactory by reading it from a file:

        var environment = Environment.GetEnvironmentVariable(“ASPNETCORE_ENVIRONMENT”);
        Console.WriteLine($”Environment from EnvironmentVariable ASPNETCORE_ENVIRONMENT: {environment}”);

        var path = Directory.GetCurrentDirectory();
        Console.WriteLine($”Loading environment.json from: {path}”);

        var config = new ConfigurationBuilder()
        .SetBasePath(path)
        // Read “environment.json” created in powershell during VSTS-release
        .AddJsonFile(“environment.json”, optional: true, reloadOnChange: true);

        // Build an initial configuration
        var conf = config.Build();
        // …and set the environmentname if it exists
        if (conf.GetSection(“ActiveEnvironment”).Exists())
        {
        environment = conf.GetSection(“ActiveEnvironment”).Value;
        Console.WriteLine($”Environment from environment.json ActiveEnvironment: {environment}”);
        }

        And then I have a Powershell VSTS step before running Deploy EF Core migrations with Inline Script:

        param([string]$environmentName, [string]$environmentJsonPath)

        $json = @{
        ActiveEnvironment= $environmentName
        }
        $json | ConvertTo-Json | Set-Content $environmentJsonPath

  2. Thanks Ben, this is working nicely to generate migration scripts for production, and I can call into this from my CI pipeline.

    One question I have is: Is there a way to copy the correct version of EF.dll into the publish output? I’m using separate servers for Build and Deployment and I’d like to guarantee that whichever EF version was used during the build is the one which is used to generate the migration script during deployment.

    • Hey Paul —

      Sadly, there isn’t a good way to figure that out. If you’re using VSTS/TFS, you can use my Build & Release Tools that are published on marketplace.visualstudio.com. I package ef.dll in that so you’d essentially be getting what you’re asking for without having to work too hard to get it.

      -Ben

  3. How can I specify a connection string variable to use here? My build has my local dev connection string in it, and none of my other connection strings (UAT, PROD) are in source control or the build by design.

    • Hey Jeremy –

      Where do your other connection strings live? The migration deployment script doesn’t have anything to do with connection strings because it delegates all of that to EF. So whatever EF is going to use to run your migrations is what you’ll need to set.

      Make sense?

      -Ben

  4. Hi Benjamin,
    Thank you for your extensions. I saves me a lot of work. I’m wondering why Microsoft hasn’t this feature build in VSTS.

    Thanks,
    Marcel

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.