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

时间:2016-06-01 07:28:01

标签: asp.net-core entity-framework-core

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

dotnet ef database update -c MyContext

当我从包含源代码的文件夹中运行它时,这很好用,但是在发布后,它似乎不会在已编译的DLL中找到命令。我对RC2命令变化的理解是'工具'可以编译为名为dotnet - * .dll的独立应用程序,并可以通过CLI执行。如何将Entity Framework Core工具公开为已发布输出中的可执行DLL?

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

TeamCity的

dotnet restore => dotnet build => dotnet test => dotnet发布

Octopus Deploy

上传套餐=> EF更新数据库=>等

5 个答案:

答案 0 :(得分:8)

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

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

  • --ef-migrate,以应用所有待处理的迁移,以及
  • --ef-migrate-check,用于验证是否已应用所有迁移

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

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

对于章鱼部署,可以将包发布两次到单独的位置 - 一个用于运行迁移,另一个用于虚拟主机。在我们的例子中,我们添加了一个带有内容

的“post deploy powershell脚本”
$env:ASPNETCORE_ENVIRONMENT="#{Octopus.Environment.Name}"
dotnet example-app.dll --ef-migrate

在泊坞广告环境中,它也可以完美地运作

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();
    }
}

答案 1 :(得分:2)

有一个非常有用的帖子可以解决这个问题here

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

总之:您可以通过传递dotnet ef database update来复制ef.dll命令(例如直接来自您的nuget文件夹(或者如果您没有nuget,则可以从其他地方复制),因为您正在进行刺激机器..))你的.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:我在blog of Ben Day中找到了这个,所以归功于Ben!

答案 2 :(得分:1)

不幸的是, EF Core迁移文件很多……我已经看到了很多解决方案,但让我们列出其中的解决方案。因此,这是您可以在没有Visual Studio的情况下运行和部署EF迁移的方法。 以下都不是完美的解决方案,但都需要注意以下几点:

  1. 使用 EF核心工具 here是指向MS官方网站的链接,其中解释了如何安装和使用它。
    • 专家:MS官方工具。所有版本的.NET Core都支持。
    • 缺点:似乎是EF6“ Migrate.exe”的后继者。 但事实并非如此!当前,如果没有实际的源代码(.csproj),则无法使用此工具。这对于Live / Prod部署而言并不是一个很好的选择。通常,您的数据库服务器上没有C#项目。
  2. dotnet主管,我试图弄清大量记录不良的参数。并且直到发现this script为止都无法运行迁移。该名称建议使用.NET core 2.1,但我将其与3.0一起使用并可以正常工作。
    • 优点:它可以像EF6“ migrate.exe”一样使用。最终,迁移无需源代码即可进行。而且很可能这是从脚本迁移和使用Assembly的唯一方法。
    • 缺点:很难设置脚本,并且容易遗漏一个参数。没有真正记录的解决方案,并且可能会在.NET Core版本之间更改。同样,您很可能也需要更改代码。您必须实现IDesignTimeDbContextFactory<DbContext>接口以使其工作。另外,请确保您在部署服务器上具有 EF.dll Microsoft.EntityFrameworkCore.Design.dll 。链接的脚本正在大量文件夹中寻找它们。最好是在构建过程中将其从.nuget文件夹复制到工件。听起来很复杂,是的...但是链接脚本有很大帮助。
  3. EF迁移添加到Startup.cs 或代码开始运行并可以访问DBContext的任何位置。使用dbContext.Database.Migrate();
    • 优点:每次都会自动进行迁移,而无需执行其他任何操作。
    • 缺点:每次都会自动发生迁移...您可能不希望发生的问题。 它还将在每次应用启动时运行。因此,您的启动时间将非常糟糕。
  4. 自定义应用。。它与先前的解决方案(第3点)相似。因此,您可以使用.NET代码来运行迁移。但是,您应该创建一个小型控制台应用,而不是将其放入您的应用中,然后在该应用中调用迁移。您必须构建此应用程序并将其放入工件中才能在部署期间运行它。
    • 优点:不涉及脚本。您可以随时在部署管道中调用它。因此,您真正的应用启动时间不会受到它的影响。
    • 缺点:您只需要维护,构建和打包应用程序即可进行EF Core迁移。
  5. 如果您使用Azure Devops进行部署,则可以使用extension like this 。或者只是在Azure Devops Marketplace中搜索一个。
    • 专业人士:它应该可以工作:)还没有尝试过任何一个,也不知道他们在做什么。 (我很确定他们也在使用“ dotnet exec”第2点。)
    • 缺点:并非每个人都可以从Azure Devops访问Live / Prod。

抱歉,列表很长。但希望能有所帮助。

答案 3 :(得分:0)

在我的背景下,我收到了来自here的这个骇客

    // Hack added so EntityFrameworkCore\Add-Migration initial works
public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<MyContext>
{
    MyContext IDesignTimeDbContextFactory<MyContext>.CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

        var optionsBuilder = new DbContextOptionsBuilder<MyContext>();
        optionsBuilder.UseSqlServer(configuration.GetConnectionString("StreamCheckpointContextDB"));
        return new MyContext(optionsBuilder.Options);
    }
}

我编写了程序。Main的内容如下:

    public static void Main(string[] args)
    {
        if (args.Contains("JustMigrateMe"))
        {
            IDesignTimeDbContextFactory<MyContext> factory = new ApplicationContextDbFactory();
            var ctx = factory.CreateDbContext(new string[0]);
            ctx.Database.Migrate();
            ctx.Dispose();
            return;
        }

        // Other stuff
    }
}

因此,要应用迁移,我只需使用添加的参数调用exe。

答案 4 :(得分:0)

对于EF Core 3.1,我在发布文件文件夹中成功运行了以下代码行。当然,可以使用以下方式调整MyUser的路径

dotnet exec --depsfile ProjectName.deps.json --runtimeconfig ProjectName.runtimeconfig.json C:\ Users \ MyUser.nuget \ packages \ dotnet-ef \ 3.1.9 \ tools \ netcoreapp3.1 \ any \ tools \ netcoreapp2.0 \ any \ ef.dll 数据库更新--context MyContext --assembly Project.dll-详细