【问题标题】:How to automate Package Manager Console in Visual Studio 2013如何在 Visual Studio 2013 中自动化包管理器控制台
【发布时间】:2013-12-14 17:47:02
【问题描述】:

我的具体问题是如何在实体框架的构建过程中自动化“添加迁移”。在对此进行研究时,似乎最有可能的方法是使这些步骤自动化

  1. 在 Visual Studio 2013 中打开解决方案
  2. 在包管理器控制台中执行“Add-Migration blahblah”(很可能通过加载项 vsextention)
  3. 关闭解决方案

这个初始方法基于我自己的研究和this question,最终在 Add-Migration 背后的 powershell 脚本需要相当多的设置才能运行。 Visual Studio 在创建包管理器控制台并使 DTE 对象可用时自动执行该设置。我不希望尝试在 Visual Studio 之外复制该设置。

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

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

具有讽刺意味的是,我可以通过包管理器控制台中的“$dte.Windows”命令找到“包管理器控制台”,但在 VS 2013 窗口中,该集合为我提供了“Microsoft.VisualStudio.Platform. WindowManagement.DTE.WindowBase”。如果有办法将文本填充到其中,我认为我需要通过查看 source code 将其变为 NuGetConsole.Implementation.PowerConsoleToolWindow" 我不清楚文本将如何填充,但我一点也不熟悉什么我看到了。

在最坏的情况下,我会尝试按照 this question 的方式填充它的密钥,但我不希望这样做,因为这会使构建过程的自动化大大复杂化。

说了这么多,

  1. 是否可以通过代码将命令流式传输到 Visual Studio 中的包管理器控制台,该控制台已完全初始化并能够支持实体框架“add-migration”命令?

提前感谢您的任何建议、建议、帮助、非滥用,

约翰

【问题讨论】:

  • 您是否尝试过使用 SendKeys 将按键推送到 WindowBase? msdn.microsoft.com/en-us/library/…
  • 我有/没有尝试过 SendKeys。我认为这是我最后的解决方案。我首先想出了下面的方法。
  • 要获取PMC窗口,你可以调用DTE.ExecuteCommand("View.PackageManagerConsole"),然后DTE.ActiveWindow就是PMC窗口。不过,我还没有弄清楚如何向它发送文本。

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


【解决方案1】:

对我有用的方法是从 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 对象并从那里找到要传递给调用的项目对象。

【讨论】:

    【解决方案2】:

    这是对约翰回答的更新,我必须感谢他的“困难部分”,但这里有一个完整的示例,它创建一个迁移并将该迁移添加到提供的项目(项目必须在之前构建)以相同的方式正如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)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-30
      • 2016-09-10
      • 1970-01-01
      • 2018-04-29
      • 2016-12-19
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      相关资源
      最近更新 更多