Asp.net core 有没有办法从发布的DLL运行EF Core RC2工具?

Asp.net core 有没有办法从发布的DLL运行EF Core RC2工具?,asp.net-core,entity-framework-core,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的

发布.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还原=>dotnet构建=>dotnet测试=>dotnet发布

八达通部署


Upload Package=>EF Update Database=>etc

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

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

  • --ef migrate
    ,以应用所有挂起的迁移,以及
  • --ef migrate check
    ,以验证是否已应用所有迁移
如果存在参数,则应用EF操作并退出程序,否则启动web应用程序

请注意,它依赖于
Microsoft.Extensions.CommandLineUtils
包来简化命令行解析

对于八达通部署用户可以将包发布两次到不同的位置,一个用于运行迁移,另一个用于网络托管。在我们的例子中,我们添加了一个包含内容的“部署后powershell脚本”

$env:ASPNETCORE_ENVIRONMENT="#{Octopus.Environment.Name}"
dotnet example-app.dll --ef-migrate
在docker环境中它也能完美工作

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");
        //
        // Please note that this webHostBuilder below is from an older 
        // dotnet core version. Newer dotnet cores have a simplified version
        // Use that instead and just take the command line parsing stuff with you
        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 serviceScope = webHost.Services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            { 
                using (var context = serviceScope.ServiceProvider.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 serviceScope = webHost.Services.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                using (var context = serviceScope.ServiceProvider.GetService<DatabaseContext>())
                {
                    context.Database.Migrate();
                    Console.WriteLine("All done, closing app");
                    Environment.Exit(0);
                }
            }
        }

        // no flags provided, so just run the webhost
        webHost.Run();
    }
}
//记住运行:dotnet添加包Microsoft.Extensions.CommandLineUtils
公共课程
{
公共静态void Main(字符串[]args)
{
var commandLineApplication=新commandLineApplication(false);
var doMigrate=commandLineApplication.Option(
“--ef migrate”,
“应用实体框架迁移并退出”,
CommandOptionType.NoValue);
var verifyMigrate=commandLineApplication.Option(
“--ef迁移检查”,
“检查实体框架迁移的状态”,
CommandOptionType.NoValue);
commandLineApplication.HelpOption(“-?|-h |-help”);
commandLineApplication.OneExecute(()=>
{
ExecuteApp(args、doMigrate、verifyMigrate);
返回0;
});
commandLineApplication.Execute(args);
}
私有静态void ExecuteApp(字符串[]args,CommandOption doMigrate,CommandOption verifyMigrate)
{
Console.WriteLine(“加载web主机”);
//
//请注意,下面的webHostBuilder来自较旧版本
//dotnet core版本。较新的dotnet core具有简化版本
//使用它,只需带上命令行解析工具即可
var webHost=new WebHostBuilder()
.UseKestrel()
.UseContentRoot(目录.GetCurrentDirectory())
.Useii整合()
.UseStartup()
.Build();
if(verifyMigrate.HasValue()&&doMigrate.HasValue())
{
Console.WriteLine(“ef migrate和ef migrate check是互斥的,请选择一个,然后重试”);
环境。出口(2);
}
if(verifyMigrate.HasValue())
{
Console.WriteLine(“验证实体框架迁移的状态”);
使用(var serviceScope=webHost.Services.GetRequiredService().CreateScope())
{ 
使用(var context=serviceScope.ServiceProvider.GetService())
{
var pendingMigrations=context.Database.GetPendingMigrations();
var migrations=pendingMigrations作为IList??pendingMigrations.ToList();
如果(!migrations.Any())
{
Console.WriteLine(“没有挂起的迁移”);
环境。退出(0);
}
WriteLine(“挂起的迁移{0}”,migrations.Count());
foreach(迁移中的var迁移)
{
WriteLine($“\t{migration}”);
}
环境。出口(3);
}
}
}
if(doMigrate.HasValue())
{
Console.WriteLine(“应用实体框架迁移”);
使用(var serviceScope=webHost.Services.GetRequiredService().CreateScope())
{
使用(var context=serviceScope.ServiceProvider.GetService())
{
Migrate();
Console.WriteLine(“全部完成,关闭应用程序”);
环境。退出(0);
}
}
}
//没有提供标志,所以只需运行webhost
webHost.Run();
}
}

有一篇非常有用的文章,介绍了这个问题的解决方案

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

总之:您可以通过传递
ef.dll
(例如,直接从您的nuget文件夹复制
dotnet ef database update
命令(或者从其他地方复制,如果您没有nuget,因为您是在prod机器上…),其中.dll包含带有一些附加参数的迁移(见下文)到
dotnet.exe
(或linux等效版本)。
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%
    // 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);
    }
}
    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
    }
}