Last week I was trying to build an API on top of Azure Functions with a backing SQL database. This sounds like a pretty easy task however that was not the case, here’s my story.
Normally when I use a SQL database in a WebApp, and therefore this also applies to Functions, I use an ORM mapper. I’m pretty familiar with Entity Framework so that’s what I tried. You might think why don’t you use Triggers and Bindings to connect with your SQL database? Well SQL bindings and triggers aren’t supported yet.
If you want to use Entity Framework inside Azure Functions V2 then you would have to use Entity Framework Core (EF Core) since EF core runs on .NET Core which supports .NET Standard 2.0, and .NET Standard 2.0 is the target for Azure Functions v2 projects.
Installation
Well having that said I chose to have a separate class library for my EF Core database context to live in because I have multiple function apps inside my solution, which all have to use that same database context.
EF core requires some Nuget packages, at the time of writing I use the 2.1.2 versions of the understanding packages. The Design
package is required when you want to work with migrations, if your not planning to do that then forget about that package. The SqlServer
package has actually a pretty cool story. It is possible to use other underlying databases such as CosmosDb, MySql or what have you. So only use that SqlServer
package when you have a backing Sql Server database.
1 | Microsoft.EntityFrameworkCore |
Do not install the following packages.
1 | Microsoft.EntityFrameworkCore.Tools |
Those packages got deprecated after .Net core 2.1.3. Before you continue, make sure you have downloaded the latest .NET Core SDK. To check your local version execute:
1 | > dotnet --version |
Setting up the context
Just like with the traditional EF you have to setup a DbContext class with all the DbSets/tables and models and stuff. Generally EF core is simular to EF but there are some differences. A good site with alot of documentation is: https://www.learnentityframeworkcore.com/. Your context might look like this:
1 | public class MyContext : DbContext |
Azure Functions V2 Dependency injection
After setting up your DbContext you probably want to use it in your Azure Functions. In order for you to effectively do that you have to setup proper dependency injection. Sadly this is not yet supported out of the box in Azure Functions V1 or V2 so you’ll have to build it your own. Don’t be sad I have found a pretty good implementation on Github. Once you have a project with that code you can just reference that project from within your Azure Functions project or just create a Nuget package.
All you then have to do is setup a ServiceProvider and add your dependencies simular to what you would have done in ASP.net core for instance. Note that the package Microsoft.EntityFrameworkCore
contains a AddDbContext
method that is build for injecting EF Core DbContexts.
1 | public class ServiceProviderBuilder : IServiceProviderBuilder |
Once you’ve setup the registration then it’s very easy to inject it into your Azure Functions, take a look at this sample:
1 | public static class DemoFunction |
Migrations
So we’ve got a DbContext setup and injected it into our Azure Functions, the next thing what you probably want to do is to use Migrations. EF core comes with great command line tooling, remember when we were using the Package Manager console to execute some Powershell? Finally those days are over. With the new dotnet ef
tooling you can just do it from the command line.
There is no such thing as Enable-Migrations
anymore, you just add a Migration and you’ve enabled it. The command to add a migrations is: dotnet ef migrations add <name>
.
Remember that I created a Shared Class Library which targets .NET Standard? Well If you get the following error you’ve done the same as I did:
1 | > dotnet ef migrations add InitialCreate |
An easy work around is to enable multiple TargetFrameworks, note that its plural, add an ‘s’ after TargetFramework. If you add a netcoreapp target framework then your Class Library can execute on its own, even without a static void main()
or something like that.
1 | <Project Sdk="Microsoft.NET.Sdk"> |
If you execute the dotnet ef migrations add <name>
again then you will probably get the following error.
1 | > dotnet ef migrations add InitialCreate |
This error states that you do not have setup a DbContextOptions
object for your DbContext
class. In other words during command line execution it doesn’t know where to execute or check the migrations on. In order for you to workaround this you’ll have to implement a IDesignTimeDbContextFactory<MyContext>
. You’ll not have to reference it anywhere, the tooling will just check for the existence and initiate the class. I chose to create an appsettings.json
file and inject a connectionString inside that file.
1 | public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyContext> |
1 | { |
If you try the command again, it should work.
1 | > dotnet ef migrations add InitialCreate |
CI / CD
Last but not least you probably want to generate migrations and execute them from your CI/CD environment. This way you’ll get a fully managed way of migrating/managing your database for all different environments.
VSTS
In VSTS you just setup a build with the following steps: * dotnet restore * dotnet build * dotnet publish - Name the projects of your function apps. * dotnet custom - Add `ef` as custom command - Add the arguments below. Set the project and the startup-project to your Class Library. * Stage the ARM template * Publish the artifacts1 | migrations script -i --project $(Build.SourcesDirectory)\MyProject.Shared\MyProject.Shared.csproj --startup-project $(Build.SourcesDirectory)\MyProject.Shared.csproj\MyProject.Shared.csproj.csproj -o $(build.artifactstagingdirectory)\Migrations\scripts.sql |
Well that’s it, you’ve got Azure Functions V2 running Entity Framework Core in Azure! Thanks for reading and happy coding.
Some tips and tricks
Just some tips and tricks.
Don’t worry about this warning. Since EF Core tools are build into the .NET Core tooling you might have mismatches with your EF Core packages.
1 | The EF Core tools version '2.1.0-rtm-30799' is older than that of the runtime '2.1.1-rtm-30846'. Update the tools for the latest features and bug fixes. |
It can also occur that you only get this warning in VSTS. That might be the result of different .NET Core SDK’s on your client pc and VSTS. Check this page out to see what version of dotnet
is running in VSTS.
Adding the -i
argument prevents migrations from being executed twice.
1 | > dotnet ef migrations script -i |
It adds the following check to the generated SQL:
1 | IF NOT EXISTS(SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'20180823120412_InitialCreate') |
To remove all migrations and start over just simply execute this.
It can be handy at the initial development.
1 | > dotnet ef database update 0 |