Microsoft.EntityFrameworkCore.Tools - Azure Functions with .NET 5 (Isolated) Design-time DbContext Creation with HostBuilder
See original GitHub issueI have created a new FunctionApp
in Visual Studio Version 16.10.0
using the template Azure Functions
with .NET 5 (Isolated)
and Http trigger
.
I have then created the following files:
Blog.cs
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
}
ApplicationDbContext.cs
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Blog> Blogs { get; set; }
}
Program.cs
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:DefaultConnection");
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
connectionString,
sqlServerOptions => sqlServerOptions.CommandTimeout(600)));
})
.Build();
host.Run();
}
}
Function1.cs
public class Function1
{
private readonly ApplicationDbContext _applicationDbContext;
public Function1(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}
[Function("Function1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("Function1");
logger.LogInformation("C# HTTP trigger function processed a request.");
var connectionString = _applicationDbContext.Database.GetDbConnection().ConnectionString;
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to Azure Functions!");
return response;
}
}
local.settings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=FunctionApp1.Test;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
}
}
I have verified that dependency injection works from Program.cs
-> new HostBuilder
If I run Add-Migration InitialCreate
in Package Manager Console I get the following error:
Unable to create an object of type ‘ApplicationDbContext’. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=vs
https://docs.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=vs
To obtain the DbContext object from the application’s service provider the example code looks like this:
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
// EF Core uses this method at design time to access the DbContext
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
=> services.AddDbContext<ApplicationDbContext>();
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
}
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
The tools first try to obtain the service provider by invoking Program.CreateHostBuilder(), calling Build(), then accessing the Services property.
Is there anyway to make Tools work with HostBuilder instead?
Include provider and version information
EF Core version: 5.0.6 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 5.0 Operating system: Windows 10 IDE: Visual Studio 2019 16.10.0
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (3 by maintainers)
I was able to work around this issue implementing IDesignTimeDBContextFactory as above. https://github.com/dotnet/efcore/issues/30897 This post was helpful.
@bricelam
$ConnectionStrings = [PSCustomObject]@{DefaultConnection = 'Server=tcp:mySqlServerStuffxxx'}
Will also cause the error
Value cannot be null. (Parameter 'connectionString')
. My point was showing thatDefaultConnection
is nested and the solution shown below won’t work:https://dev.to/azure/using-entity-framework-with-azure-functions-50aa#adding-an-entity-framework-migration
I also tried the solution above with changing to
var connectionString = Environment.GetEnvironmentVariable("ConnectionString");
inCreateHostBuilder
and then running:This also caused the exception:
Value cannot be null. (Parameter 'connectionString')
.Is it a dead end with
CreateHostBuilder
?I did not think about that! Worked after fixing this.
Really nice. I first tried with
-ConnectionString
but got this error:After reading documentation I saw that the parameter was actually
-Connection
. After trying that it worked like a charm with the simpleIDesignTimeDbContextFactory
below.https://docs.microsoft.com/en-us/ef/core/cli/powershell#update-database