C
C#2mo ago
Core

How to block the execution of a method when running EF migration

Hello, I have a background service registered in Program.cs. It does an HTTP call to an external service that is essential for getting some configuration settings. This HTTP call should not happen when ef commands are executed, so I was wondering what solutions might be there.
16 Replies
Zendist
Zendist2mo ago
What is calling these EF commands? The BG Service or the HTTP server?
tera
tera2mo ago
just run migrations before you even start the background service
Jimmacle
Jimmacle2mo ago
running migrations while your app is running at all sounds like a bad idea, i run them at startup
Core
Core2mo ago
The background service is an IHostedLifecycleService. I also create an instance of that just to do a http call, but all of this happens once. When I run the EF command dotnet ef migrations add ... it also executes the HTTP call. The app is not running when the migration is being created
c#
services.AddHttpClient<ICoordinationService, CoordinationService>((serviceProvider, httpClient) =>
{
var options = serviceProvider.GetRequiredService<IOptions<CoordinationServiceOption>>().Value;

httpClient.BaseAddress = new Uri(options.BaseUrl);
})
.ConfigurePrimaryHttpMessageHandler(() =>
new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(2) });

var coordinationService = services.BuildServiceProvider().GetRequiredService<ICoordinationService>();
var instanceConfig = coordinationService.GetInstanceConfig().Result;
c#
services.AddHttpClient<ICoordinationService, CoordinationService>((serviceProvider, httpClient) =>
{
var options = serviceProvider.GetRequiredService<IOptions<CoordinationServiceOption>>().Value;

httpClient.BaseAddress = new Uri(options.BaseUrl);
})
.ConfigurePrimaryHttpMessageHandler(() =>
new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(2) });

var coordinationService = services.BuildServiceProvider().GetRequiredService<ICoordinationService>();
var instanceConfig = coordinationService.GetInstanceConfig().Result;
For the app that external service call is essential, but it also gets executed whenever I create a migration. I think that is because the app is built one time before the EF command
Core
Core2mo ago
No description
Jimmacle
Jimmacle2mo ago
when you run a migration your app is run up until its services are configured and you build the host so if you're actually making external calls when you're supposed to just be configuring services it will cause problems
Jimmacle
Jimmacle2mo ago
if that's unavoidable then your only option is to set up an IDesignTimeDbContextFactory afaik https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
Design-time DbContext Creation - EF Core
Strategies for creating a design-time DbContext with Entity Framework Core
Core
Core2mo ago
Sorry, my notifications were turned off. Thank you, I will look into this as soon as I can
Core
Core4w ago
@Jimmacle it's been a while. I iplemented the IDesignTimeDbContext, but the outcome is the same. The HTTP call is still executed.
c#
public class DbContextDesignTimeFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
Console.WriteLine("Design Time");

var configuration = new ConfigurationManager();
configuration.BuildConfigurationManager();

var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseNpgsql(configuration.GetConnectionString("Database"));

return new ApplicationDbContext(optionsBuilder.Options);
}
}
c#
public class DbContextDesignTimeFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
Console.WriteLine("Design Time");

var configuration = new ConfigurationManager();
configuration.BuildConfigurationManager();

var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseNpgsql(configuration.GetConnectionString("Database"));

return new ApplicationDbContext(optionsBuilder.Options);
}
}
No description
Core
Core4w ago
Sorry, it turns out that IDesignTimeDbContextFactory is no longer supported in .NET 6 and above. I found a discussion on GitHub about it
Jimmacle
Jimmacle4w ago
where did you read that? i'm using it in .NET 8 with no problems
tera
tera4w ago
yeah same
Jimmacle
Jimmacle4w ago
it's also still in the EF core documentation that i linked above
Core
Core4w ago
Yes, and that is what I implemented. My output shows that the DesignTimeFactory was executed and not the regular DbContext I found a solution which is available from .NET 7. EF exposes a static flag trough EF.IsDesignTime. I simply organized the Program.cs content in a way to only have code needed for EF in design time.
tera
tera4w ago
that should not happen if you are doing everything right - how/from where (exact command, directory) are you running migrations - where is the dbcontextfactory located (project..) - is it same project as the dbcontext my suspicion is that it was not even using that factory you made i would rather focus on solving the actual problem than workaround
Core
Core4w ago
It was, I did a Console.Write in the factory It was located in the main project, not in which the dbcontext. But either way, it should work from the main project, because for EF commands both the source project and the other project where the dbcontext is located should be specified