Asp.net core 有没有办法从发布的DLL运行EF Core RC2工具?
发布.Net Core RC1应用程序后,project.json中指定的命令会为它们创建相应的.cmd文件,这些文件可以在部署后执行(例如web.cmd和ef.cmd)。在本例中,我希望在部署目标上运行以下Entity Framework命令: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的
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
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
}
}