首页 文章

有没有办法从已发布的DLL运行EF Core RC2工具?

提问于
浏览
10

发布.Net Core RC1应用程序后,project.json中指定的命令具有为其创建的相应.cmd文件,这些文件可在部署后执行(例如web.cmd和ef.cmd) . 在我的例子中,我想在我的部署目标上运行以下Entity Framework命令:

dotnet ef database update -c MyContext

当我从包含源代码的文件夹运行它时,这工作正常,但是在发布后,它似乎没有在编译的DLL中找到命令 . 我对RC2命令变化的理解是“工具”可以编译为名为dotnet - * .dll的独立应用程序,并且可以通过CLI执行 . 如何将实体框架核心工具公开为已发布输出中的可执行DLL?

仅供参考,我的构建/部署工作流程如下:

TeamCity

dotnet restore => dotnet build => dotnet test => dotnet publish

Octopus Deploy

上传包=> EF更新数据库=>等

2 回答

  • 6

    我在项目中遇到了同样的问题,但由于多种原因,我不希望迁移在应用程序启动时自动运行 .

    为了解决这个问题,我更新了 Program.cs 以获取两个参数(完整代码列在下面)

    • --ef-migrate ,以应用所有待处理的迁移,以及

    • --ef-migrate-check ,用于验证是否已应用所有迁移

    如果存在参数,则应用EF操作并退出程序,否则启动Web应用程序 .

    请注意,它取决于 Microsoft.Extensions.CommandLineUtils 包以简化命令行解析 .

    For octopus deploy 然后可以将包发布两次到单独的位置 - 一个用于运行迁移,另一个用于webhosting . 在我们的例子中,我们添加了一个"post deploy powershell script"的内容

    $env:ASPNETCORE_ENVIRONMENT="#{Octopus.Environment.Name}"
    dotnet example-app.dll --ef-migrate
    

    In a docker context 它也能完美地运作

    docker run -it "example-app-container" dotnet example-app.dll --ef-migrate
    

    完整的Program.cs,不包括命名空间和使用:

    //Remember to run: dotnet add package Microsoft.Extensions.CommandLineUtils
    public class Program
    {
        public static void Main(string[] args)
        {
            var commandLineApplication = new CommandLineApplication(false);
            var doMigrate = commandLineApplication.Option(
                "--ef-migrate",
                "Apply entity framework migrations and exit",
                CommandOptionType.NoValue);
            var verifyMigrate = commandLineApplication.Option(
                "--ef-migrate-check",
                "Check the status of entity framework migrations",
                CommandOptionType.NoValue);
            commandLineApplication.HelpOption("-? | -h | --help");
            commandLineApplication.OnExecute(() =>
            {
                ExecuteApp(args, doMigrate, verifyMigrate);
                return 0;
            });
            commandLineApplication.Execute(args);
        }
    
        private static void ExecuteApp(string[] args, CommandOption doMigrate, CommandOption verifyMigrate)
        {
            Console.WriteLine("Loading web host");
            var webHost = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();
    
            if (verifyMigrate.HasValue() && doMigrate.HasValue())
            {
                Console.WriteLine("ef-migrate and ef-migrate-check are mutually exclusive, select one, and try again");
                Environment.Exit(2);
            }
    
            if (verifyMigrate.HasValue())
            {
                Console.WriteLine("Validating status of Entity Framework migrations");
                using (var context = webHost.Services.GetService<DatabaseContext>())
                {
                    var pendingMigrations = context.Database.GetPendingMigrations();
                    var migrations = pendingMigrations as IList<string> ?? pendingMigrations.ToList();
                    if (!migrations.Any())
                    {
                        Console.WriteLine("No pending migratons");
                        Environment.Exit(0);
                    }
    
                    Console.WriteLine("Pending migratons {0}", migrations.Count());
                    foreach (var migration in migrations)
                    {
                        Console.WriteLine($"\t{migration}");
                    }
    
                    Environment.Exit(3);
                }
            }
    
            if (doMigrate.HasValue())
            {
                Console.WriteLine("Applyting Entity Framework migrations");
                using (var context = webHost.Services.GetService<DatabaseContext>())
                {
                    context.Database.Migrate();
                    Console.WriteLine("All done, closing app");
                    Environment.Exit(0);
                }
            }
    
            // no flags provided, so just run the webhost
            webHost.Run();
        }
    }
    
  • 0

    有一个非常有用的帖子解决了这个问题here .

    它对我有用(我不得不稍微调整一下命令,但它给了我一个很好的基础) .

    总而言之:您可以通过传递 ef.dll 来复制 dotnet ef database update 命令(例如直接从您的nuget文件夹(或者从其他地方,如果您没有nuget,因为您在prod机器上...))与您的.dll包含使用一些附加参数(见下文)迁移到 dotnet.exe (或等效的linux) .

    为了完整性,这里是.cmd(也来自博客帖子!)

    set EfMigrationsNamespace=%1
    set EfMigrationsDllName=%1.dll
    set EfMigrationsDllDepsJson=%1.deps.json
    set DllDir=%cd%
    set PathToNuGetPackages=%USERPROFILE%\.nuget\packages
    set PathToEfDll=%PathToNuGetPackages%\microsoft.entityframeworkcore.tools.dotnet\1.0.0\tools\netcoreapp1.0\ef.dll
    
    dotnet exec --depsfile .\%EfMigrationsDllDepsJson% --additionalprobingpath %PathToNuGetPackages% %PathToEfDll% database update --assembly .\%EfMigrationsDllName% --startup-assembly .\%EfMigrationsDllName% --project-dir . --content-root %DllDir% --data-dir %DllDir% --verbose --root-namespace %EfMigrationsNamespace%
    

    (如果此cmd位于博客帖子中,则为bash版本)

    顺便说一句 . 在许多github问题中也提到了这种方法:https://github.com/aspnet/EntityFramework.Docs/issues/328 https://github.com/aspnet/EntityFramework.Docs/issues/180

    ps: I found this in the blog of Ben Day, so all credit goes to Ben!

相关问题