As you’ve probably heard, ASP.NET Core runs on Linux (and macOS)! And it’s actually pretty easy to get started. However, running Entity Framework Core database migrations on Linux after publishing is not as easy.
During development [on Linux and macOS], running migrations is as simple as always:
$ dotnet ef database update
Note that to use the dotnet ef command, you must either have version 2.1+ of the .NET Core SDK installed, or the
Microsoft.EntityFrameworkCore.Tools NuGet package installed in your project.
~That’s because the EF tools are installed on your system and easily accessible. Where I ran into issues however, is while trying to deploy my application using AWS Code Deploy. Like most CI/CD systems, this is intended to be fully automated. Here are the high-level steps to deploy this application. I’ll cover the details of each step in a later blog post (or hopefully series). ~
-
From your development machine or build server, publish your application and zip it up:
$ dotnet publish -c Release -
Since Code Deploy relies on the above artifact being in an S3 bucket, put the file in the appropriate S3 bucket.
-
Kick off the Code Deploy process. In my case, there’s a hook in the
appspec.ymlfile to execute the migrations.
For example purposes, we’re going to assume my application was deployed to my Linux server at /var/www/html/api and this will
be our working directory.
If we run the same database update command, we get an error:
$ dotnet ef database update
No project was found. Change the current working directory or use the --project option.
Well that’s interesting. I’d gladly specify a project file, but since the app has been published already, it doesn’t exist in our artifact. So now what? Turns out we need to be a little more verbose with our command:
# Note: I broke this up into lines to make it easier to read and explain
$ dotnet exec \
--depsfile MyApiProject.deps.json \
--runtimeconfig MyApiProject.runtimeconfig.json \
"/opt/ef-tools/ef.dll" database update \
--assembly MyApiProject.dll \
--startup-assembly MyApiProject.dll \
--root-namespace MyApiProject
When you run your EF commands from your development machine with the .csproj file, it gathers all the dependencies
it needs from the project. Because we don’t have the .csproj file after publishing, we have to tell dotnet where to find
those dependencies. Let’s take a look at these lines individually.
dotnet execis responsible for running the command. We need to do this to provide the EF tools with the additional information missing due to the lack of.csproj--depsfiledescribes the dependencies the application has--runtimeconfigdescribes the runtime configuration for the app, including the SDK version"/opt/ef-tools/ef.dll" database updateis calling out to the EF tools to actually run the database update command--assemblyand--startup-assemblyare telling EF where to find the migrations andDbContext. Note that dependening on your project structure, these may be the same or could vary.--root-namespaceIs the root namespace (or the assembly name) of the application
As a side note, if you want to see what
dotnetis running when you rundotnet ef database updatelocally, you can add the--verboseflag. If there are migrations, you’ll have to scroll up and you’ll see adotnet execcommand similar to the above.
I’m really hoping the EF / .NET teams make this easier in the future. I’ve opened an issue here which talks about this, so please “up-vote” it if you’d like to see it as well. Also, a special thanks to Ben Day for his post and script pointing me in the right direction.
In the issue comment thread, the .NET CLI team does not recommend “trying this at home” [referring to running
dotnet exec] - use caution with other use cases.