-
Notifications
You must be signed in to change notification settings - Fork 549
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow EF Core migration tooling to use app host as startup project #2090
Comments
@kkirkfield Hi, thanks for taking the time to look into improving migrations. I copied your source code to play around with your idea. It looks like the goal of your changes is to make In your example below, where does the source code for using RazorPagesApp.Data;
var builder = DistributedApplication.CreateBuilder(args);
var database = builder.AddPostgres("postgres")
.AddDatabase("database")
.WithDesignTimeDbContext<PostgresDatabaseResource, ApplicationDbContext>();
builder.AddProject<Projects.RazorPagesApp>("app")
.WithReference(database)
.WithLaunchProfile("https");
builder.Build() .Run(); If you have time, it would be useful to see a repo with your exepriment. That would give an overview of how your idea hangs together.
Unfortunatly EF Core for .NET 8 (which Aspire is initially targeting) is done. Larger changes to EF's tooling most likely have to wait for .NET 9. But figuring out the problems now and coming up with a plan early is still extremely useful. |
@JamesNK Here is the link to a sample project: https://github.com/kkirkfield/DotnetAspireIssue2090Example. The readme has some example steps you can run to see where it is failing.
Yes, I am trying to find a workflow that uses the .NET EF Core tools to add, remove, and apply migrations to the development database that is started by the AppHost. Ideally the RazorPagesApp in this example shouldn't be applying the migrations during development, so it makes sense that the AppHost should handle applying these migrations during startup.
Yes, in this sample it just lives in the RazorPagesApp, but in a real world project using a layered architecture. this might live in a separate library project. |
Adding a reference to the EF mode in the apphost feels like it'll land us back in dependency hell. |
My current workaround for this is to use TestContainers to create the database in the AppHost so I have a solid connection string and then run my migrations on the database in the AppHost before running the DistributedApplication:
Then pass the connectionstring of that db through to the containers that need it through That works especially well for our team because we already use TestContainers everywhere for tests, but it would be an extra dependency here. I wonder if we could have some sort of "BuildAllTheThings" command on IResourceBuilder so we have a real connection string earlier in the process? I don't know the internals of that well enough to know if its possible. |
I would rather have code running at the right time than enabling individual resources to start a random arbitrary times (it gets trickier when there are dependencies as well). Instead, you can write code that runs later, so you can kick of the migration process. |
@kkirkfield I've checked in some changes that makes adding migrations better (no longer errors because of missing connection string). I've also added a migrations playground app: #2263 It doesn't attempt what you're doing here and allow the apphost to be the startup project, but it doesn't block doing that in the future either. |
This submission has been automatically marked as stale because it has been marked as requiring author action but has not had any activity for 14 days. |
While exploring .NET Aspire I've run into many of the issues outlined in #1899. I started working on an attempt to improve the migrations experience for local development. Would appreciate thoughts and input 😃
Database migration issues with the current developer experience
When using the .NET EF Core tools to create and manage migrations, the
AppHost
project cannot currently be set as the startup project because the EF Core design-time library has no way to resolve the DbContext.One workaround currently is to manually specify the connection string in the
appsettings.json
of the projects. This workaround is not great because you must duplicate the configuration in multiple places and cannot take advantage of service discovery and randomized ports. Another issue that this workaround doesn't solve for is waiting for the database container to be started.New API proof of concept
The new API I'm suggesting addresses the issues above and better integrates the EF Core design-time tools into projects using .NET Aspire.
To use the API below, the developer just needs to chain
.WithDesignTimeDbContext<TResource, TDbContext>()
to any database resource builder in theAppHost
project.Example:
ResourceBuilderExtensions.cs
This extension method is responsible for registering the
IDbContextFactory
with theIHost
services provider for theAppHost
project. This allows theHostFactoryResolver
used by the EF Core tools to resolve the DbContext when theAppHost
project is the startup project. It also connects the lifecycle hooks in .NET Aspire to the factory in order to create the DbContext at runtime after the database endpoints are running.DesignTimeDbContextFactory.cs
This class is responsible for creating the DbContext at runtime that will be used by the EF Core tools. It uses a
TaskCompletionSource
to wait for the .NET Aspire lifecycle hooks to indicate that the database endpoints are running.Currently this proof of concept is hard-coded to use Postgres, but this can be generalized in the final version.
ConnectionStringAvailableLifecycleHook.cs
This class is registered to listen to the lifecycle hooks. Once the connection string for the resource is available it triggers the
TaskCompletionSource
in theDesignTimeDbContextFactory
to complete so that new DbContext instances can be created with the connection string of the running database.Issues with this proof of concept
Currently this proof of concept does not work because the EF Core tools stop the startup application after the service provider is resolved. This prevents the host from running and the lifecycle hooks above to not execute. See: https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs#L122 and https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs#L339
One solution to this would be to update the
ResolveServiceProviderFactory()
method to accept thestopApplication
parameter from the EF Core tools command line. TheResolveHostFactory()
method already has a parameter for this and the logic to keep the application running. This just needs to be passed down. Then the EF Core tools can stop the application after the DbContext is resolved.The other improvement I would like to make is allowing the DbContextOptions to be configured as part of
.WithDesignTimeDbContext()
so that this new API works for all database resource types and to allow for further customization.The text was updated successfully, but these errors were encountered: