Skip to content
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

Add a static flag in EF that will be set when code is being executed for design-time discovery #27306

Closed
hookenful opened this issue Jan 28, 2022 · 15 comments · Fixed by #28508
Closed
Assignees
Labels
area-tools closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Milestone

Comments

@hookenful
Copy link

I have strange behavior with my EF Core tools in developer powershell in VS2019.

I am creating migration with dotnet ef migrations add VisibleLink3 -p .\src\Only.Portal.Data\ -s .\src\Only.Portal.Web command.

And it is starting my app, but previously it didn't.method to apply last migrations. Which causes dotnet ef migrations remove fully broken, because when using it, it firstly start app and Migrate().

Then I have a message:

The migration '20220128090939_VisibleLink3' has already been applied to the database. Revert it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration instead..

Looks like dead end loop.

@hookenful
Copy link
Author

hookenful commented Jan 28, 2022

I have already used dotnet ef database update previous-migration command . And after it successful execute, I execute dotnet ef migration remove. And my app somehow starting in console and somewhere inside calling Migrate() to apply that migration what I want to remove and after that it saying that it has already been applied to the database.

@roji
Copy link
Member

roji commented Jan 28, 2022

@hookenful it's difficult to understand from the above what exactly is going on, as a lot of details are missing.

Are you saying that when executing dotnet ef migration add, your application is executed? That definitely shouldn't be the case; if so, can you please submit a runnable code sample which shows that happening?

@ajcvickers
Copy link
Member

@roji

Are you saying that when executing dotnet ef migration add, your application is executed?

This can happen now--see dotnet/runtime#53757

@hookenful

This issue is lacking enough information for us to be able to fully understand what is happening. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

@hookenful
Copy link
Author

@roji is right. I am executing command in Developer powershell in VS2019. And my app is starting after this.

dotnet ef migrations add VisibleLink -p .\src\Only.Portal.Data\ -s .\src\Only.Portal.Web
Build started...
Build succeeded.
[12:21:23 WRN] xxxx
[12:21:23 WRN] xxxx
[12:21:23 WRN] xxxx
[12:21:23 WRN] xxxx
Hosting environment: Development
Content root path: C:\Users\hoozr\source\repos\portal-web\src\Only.Portal.Web
Now listening on: http://localhost:5000
Now listening on: https://localhost:5001
Application started. Press Ctrl+C to shut down.
->>>>> HERE I CTRL+C CLOSE Application is shutting down...
PS C:\Users\hoozr\source\repos\portal-web> An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the application service provider. Error: The entry point exited without ever building an IHost.
xxx
xxx
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use 'ef migrations remove'

@hookenful
Copy link
Author

hookenful commented Jan 28, 2022

Which is causing some problem, because for example if I need to revert migration ->
My steps:

  1. dotnet ef database update previous-migration
  2. dotnet ef database remove here my app is starting and somewhere inside there are Seed and Migrate methods, where Migrate() execute, applying to database existing NOT YET removed migrations. And in output I recieve

"The migration '20220128090939_VisibleLink3' has already been applied to the database. Revert it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration instead.."

Somehow dead end loop.

@hookenful
Copy link
Author

hookenful commented Jan 28, 2022

@frogerdevs
Copy link

I'm facing this issue too when creating the .net6 project and using startup.cs file like .net 5.

after few days reading again on how to upgrade from .net5 to .net 6
https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60?view=aspnetcore-6.0&tabs=visual-studio

I'm implementing "Use Startup with the new minimal hosting mode" and executing "add-migration" my code runs well.

Hope it helps.

@hookenful
Copy link
Author

@frogerdevs for sure it helped, thanks a lot :) good luck for all you blessed guys.

@ajcvickers
Copy link
Member

Notes from triage: the issue here is that, in order to support minimal APIs, a hosted application is now executed in order to discover services. This is a problem if the application performs migrations (or does anything else that is incompatible with design-time) before the host is terminated.

In 7.0, we plan to add a static "design-time" flag to EF Core that can be checked while the application is running. This flag can be used by the application to avoid applying migrations or doing anything else that should not happen at startup. This issue will track that change.

For now, the best workaround is to use a Startup class, as suggested above by @frogerdevs . See Use Startup with the new minimal hosting model for more information.

In addition, we will look into creating an IDesignTimeContextFactory without first doing full DbContext type discovery.

/cc @davidfowl

@ajcvickers ajcvickers changed the title Why does application start start with dotnet ef migrations add? Add a static flag in EF that will be set when code is being executed for design-time discovery Jan 31, 2022
@ajcvickers ajcvickers added this to the 7.0.0 milestone Jan 31, 2022
@davidfowl
Copy link
Member

davidfowl commented Jan 31, 2022

I wonder if we could make this more generic and not have it be an EF static but a static that any tool can use? We can base it on an environment variable or app context switch or something like that as well so we could potentially backport it to 6.0

@ajcvickers
Copy link
Member

@davidfowl Can you suggest a place to put it?

@AndriySvyryd
Copy link
Member

The EF-specific flag could be the version of the tool, so when invoked by a different major version than expected a (potentially third-party) service could display a warning

@bricelam
Copy link
Contributor

@danroth27 Brought up an interesting point today, if you were creating the database in Program.Main before, there's currently no way to do that with a Minimal API project that works well with dotnet-ef.

Here's the old pattern:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        
        // Migrate
        using (var scope = host.Services.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            db.Database.Migrate();
        }
        
        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

And here's what it might look like as Minimal API:

var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);

var app = builder.Build();

// TODO: Need a flag to skip during dotnet-ef
//if (!EF.IsInDesignMode)
//{
    // Migrate
    using (var scope = app.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        db.Database.Migrate();
    }
//}

startup.Configure(app, app.Environment);
app.Run();

@foriequal0
Copy link

I'm using this little trick. It works for my scenarios.

public static bool IsDesignTime()
{
    var args = Environment.GetCommandLineArgs();
    if (args.Length < 1)
    {
        return false;
    }

    var arg = args[0];
    return Path.GetFileName(arg) == "ef.dll";
}

@dziedrius
Copy link

I would be nice to update documentation at https://docs.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-a-design-time-factory if design time factory is not supported anymore in .net 6.

ajcvickers added a commit that referenced this issue Jul 25, 2022
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jul 25, 2022
ajcvickers added a commit that referenced this issue Jul 26, 2022
ajcvickers added a commit that referenced this issue Jul 28, 2022
ajcvickers added a commit that referenced this issue Jul 28, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, 7.0.0-rc1 Jul 29, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0-rc1, 7.0.0 Nov 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-tools closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported type-enhancement
Projects
None yet
9 participants