如何在Visual Studio 2013中自动化Package Manager控制台

时间:2013-12-14 17:47:02

标签: visual-studio entity-framework nuget build-process

我的具体问题是如何在Entity Framework的构建过程中自动执行“添加迁移”。在研究这个问题时,似乎最有可能的方法是自动执行这些步骤

  1. 在Visual Studio 2013中打开解决方案
  2. 在程序包管理器控制台中执行“Add-Migration blahblah”(最有可能是通过加载项vsextention)
  3. 关闭解决方案
  4. 这个初始方法基于我自己的研究和this question,最终在Add-Migration背后的powershell脚本需要相当多的设置才能运行。 Visual Studio在创建程序包管理器控制台并使DTE对象可用时自动执行该设置。我不想尝试在Visual Studio之外复制该设置。

    解决方案的一个可能途径是未应答的堆栈溢出question

    在研究NuGet API时,它似乎没有“发送此文本,它将像在控制台中输入一样运行”。我不清楚Visual Studio与NuGet之间的界限,所以我不确定这是否会存在。

    我能够通过软件包管理器控制台中的“$ dte.Windows”命令找到“Pacakage Manager Console”,但在VS 2013窗口中,该集合为我提供了“Microsoft.VisualStudio.Platform”对象。 WindowManagement.DTE.WindowBase”。如果有一种方式填充文本,我认为我需要将它变为NuGetConsole.Implementation.PowerConsoleToolWindow“通过查看source code我不清楚文本将如何填充但我根本不熟悉我所看到的。

    最糟糕的情况是,我会回到试图按照this question的方式填写密钥,但不愿意这样做,因为这会使构建过程周围的自动化大大复杂化。

    所有这一切,

    1. 是否可以通过代码将命令流式传输到Visual Studio中的Package Manager控制台,该控制台已完全初始化并且能够支持实体框架“add-migration”命令?
    2. 感谢您提前提出任何建议,建议,帮助,非滥用行为,

      约翰

2 个答案:

答案 0 :(得分:5)

对我有用的方法是从EntityFramework.Powershell项目中的AddMigrationCommand.cs开始跟踪实体框架代码,找到EntityFramework项目中的钩子,然后使这些钩子工作,这样就没有Powershell依赖

你可以得到类似......

    public static void RunIt(EnvDTE.Project project, Type dbContext, Assembly migrationAssembly, string migrationDirectory,
        string migrationsNamespace, string contextKey, string migrationName)
    {
        DbMigrationsConfiguration migrationsConfiguration = new DbMigrationsConfiguration();
        migrationsConfiguration.AutomaticMigrationDataLossAllowed = false;
        migrationsConfiguration.AutomaticMigrationsEnabled = false;
        migrationsConfiguration.CodeGenerator = new CSharpMigrationCodeGenerator(); //same as default
        migrationsConfiguration.ContextType = dbContext; //data
        migrationsConfiguration.ContextKey = contextKey;
        migrationsConfiguration.MigrationsAssembly = migrationAssembly;
        migrationsConfiguration.MigrationsDirectory = migrationDirectory;
        migrationsConfiguration.MigrationsNamespace = migrationsNamespace;

        System.Data.Entity.Infrastructure.DbConnectionInfo dbi = new System.Data.Entity.Infrastructure.DbConnectionInfo("DataContext");
        migrationsConfiguration.TargetDatabase = dbi;

        MigrationScaffolder ms = new MigrationScaffolder(migrationsConfiguration);

        ScaffoldedMigration sf = ms.Scaffold(migrationName, false);

    }

您可以使用this question访问dte对象,然后从那里找到要传递给调用的项目对象。

答案 1 :(得分:0)

这是对约翰回答的更新,我要感谢"困难部分",但这里有一个完整的示例,它创建了一个迁移并将迁移添加到提供的项目中(必须以Add-Migration InitialBase -IgnoreChanges的方式构建项目:

public void ScaffoldedMigration(EnvDTE.Project project)
{
    var migrationsNamespace = project.Properties.Cast<Property>()
         .First(p => p.Name == "RootNamespace").Value.ToString() + ".Migrations";

    var assemblyName = project.Properties.Cast<Property>()
                           .First(p => p.Name == "AssemblyName").Value.ToString();
    var rootPath = Path.GetDirectoryName(project.FullName);
    var assemblyPath = Path.Combine(rootPath, "bin", assemblyName + ".dll");
    var migrationAssembly = Assembly.Load(File.ReadAllBytes(assemblyPath));
    Type dbContext = null;
    foreach(var type in migrationAssembly.GetTypes())
    {
        if(type.IsSubclassOf(typeof(DbContext)))
        {
            dbContext = type;
            break;
        }
    }

    var migrationsConfiguration = new DbMigrationsConfiguration()
        {
            AutomaticMigrationDataLossAllowed = false,
            AutomaticMigrationsEnabled = false,
            CodeGenerator = new CSharpMigrationCodeGenerator(),
            ContextType = dbContext,
            ContextKey = migrationsNamespace + ".Configuration",
            MigrationsAssembly = migrationAssembly,
            MigrationsDirectory = "Migrations",
            MigrationsNamespace = migrationsNamespace
        };

    var dbi = new System.Data.Entity.Infrastructure
                     .DbConnectionInfo("ConnectionString", "System.Data.SqlClient");
    migrationsConfiguration.TargetDatabase = dbi;

    var scaffolder = new MigrationScaffolder(migrationsConfiguration);
    ScaffoldedMigration migration = scaffolder.Scaffold("InitialBase", true);

    var migrationFile = Path.Combine(rootPath, migration.Directory,
                            migration.MigrationId + ".cs");
    File.WriteAllText(migrationFile, migration.UserCode);
    var migrationItem = project.ProjectItems.AddFromFile(migrationFile);

    var designerFile = Path.Combine(rootPath, migration.Directory,
                           migration.MigrationId + ".Designer.cs");
    File.WriteAllText(designerFile, migration.DesignerCode);
    var designerItem = project.ProjectItems.AddFromFile(migrationFile);
    foreach(Property prop in designerItem.Properties)
    {
        if (prop.Name == "DependentUpon")
            prop.Value = Path.GetFileName(migrationFile);
    }

    var resxFile = Path.Combine(rootPath, migration.Directory,
                       migration.MigrationId + ".resx");
    using (ResXResourceWriter resx = new ResXResourceWriter(resxFile))
    {
        foreach (var kvp in migration.Resources)
            resx.AddResource(kvp.Key, kvp.Value);
    }
    var resxItem = project.ProjectItems.AddFromFile(resxFile);
    foreach (Property prop in resxItem.Properties)
    {
        if (prop.Name == "DependentUpon")
            prop.Value = Path.GetFileName(migrationFile);
    }
}

我在我的项目模板的IWizard实施中执行此操作,我在IgnoreChanges运行迁移,因为与基础项目共享参与者。如果要包含更改,请将scaffolder.Scaffold("InitialBase", true)更改为scaffolder.Scaffold("InitialBase", false)