【问题标题】:Easy way to add multiple existing .csproj to a Visual Studio Solution?将多个现有 .csproj 添加到 Visual Studio 解决方案的简单方法?
【发布时间】:2009-12-11 21:39:45
【问题描述】:

我已经从源代码管理中检查了一个 C# 代码分支。它在不同的文件夹中可能包含 50 个项目。找不到现有的 .sln 文件。

我打算创建一个空白解决方案来添加现有解决方案。 UI 一次只允许我做一个项目。

我有什么遗漏吗?我想指定一个 *.csproj 文件列表,并以某种方式提出一个包含所有项目的 .sln 文件。

【问题讨论】:

  • 手动添加它们并不好玩 - 与 Visual Studio 斗争,试图让它做一些简单的事情,现在这很有趣。
  • 好吧,当然它现在已经完成了。问题的重点是避免将来感到沮丧。并仔细检查我是否遗漏了任何明显的东西。感谢大家对问题的关注。
  • 对于少量项目来说,使这更容易一些的解决方法是将 File.AddExistingProject 映射到您可以用左手使用的快捷键,然后您可以使用该快捷键弹出浏览器并选择并用鼠标手添加。

标签: visual-studio projects-and-solutions csproj


【解决方案1】:

一种 PowerShell 实现,它递归地扫描脚本目录中的 .csproj 文件并将它们添加到(生成的)All.sln:

$scriptDirectory = (Get-Item $MyInvocation.MyCommand.Path).Directory.FullName
$dteObj = [System.Activator]::CreateInstance([System.Type]::GetTypeFromProgId("VisualStudio.DTE.12.0"))

$slnDir = ".\"
$slnName = "All"

$dteObj.Solution.Create($scriptDirectory, $slnName)
(ls . -Recurse *.csproj) | % { $dteObj.Solution.AddFromFile($_.FullName, $false) }

$dteObj.Solution.SaveAs( (Join-Path $scriptDirectory 'All.sln') ) 

$dteObj.Quit()

【讨论】:

  • 对我不起作用 =( (Join-Path : 无法将参数绑定到参数“Path”,因为它为空。在 line:1 char:36 + $dteObj.Solution.SaveAs( (Join-路径
  • 我一直认为 $dteObj.Solution 为空。你是怎么解决这个问题的?
  • 我更新了答案,将 DTE 对象的构造更改为使用 New-Object。它现在正在接受同行评审,但如果您想手动更改脚本,请将第 2 行更改为: $dteObj = New-Object -ComObject "VisualStudio.DTE.10.0" (将版本号更改为您使用的任何版本的 Studio '正在使用。)
【解决方案2】:

一个生成可执行文件的 C# 实现,它创建一个解决方案,其中包含执行它的目录和子目录中的所有唯一 *.csproj 文件。

class Program
{
  static void Main(string[] args)
  {
    using (var writer = new StreamWriter("All.sln", false, Encoding.UTF8))
    {
      writer.WriteLine("Microsoft Visual Studio Solution File, Format Version 11.00");
      writer.WriteLine("# Visual Studio 2010");

      var seenElements = new HashSet<string>();
      foreach (var file in (new DirectoryInfo(System.IO.Directory.GetCurrentDirectory())).GetFiles("*.csproj", SearchOption.AllDirectories))
      {
        string fileName = Path.GetFileNameWithoutExtension(file.Name);
        
        if (seenElements.Add(fileName))
        {
          var guid = ReadGuid(file.FullName);
          writer.WriteLine(string.Format(@"Project(""0"") = ""{0}"", ""{1}"",""{2}""", fileName, file.FullName, guid));
          writer.WriteLine("EndProject");
        }
      }
    }
  }

  static Guid ReadGuid(string fileName)
  {
    using (var file = File.OpenRead(fileName))
    {
      var elements = XElement.Load(XmlReader.Create(file));
      return Guid.Parse(elements.Descendants().First(element => element.Name.LocalName == "ProjectGuid").Value);
    }
  }
}

【讨论】:

  • 如果你想使用(我最喜欢的新脚本工具)scriptcs,你可以将函数移出类,将上面的 ReadGuid 移到函数范围之外的顶部和下面的主要内容并保存它为 .csx。
  • 恕我直言,这应该是公认的答案。它比第一个选项快得多。
【解决方案3】:

有可用的 VS 扩展,能够添加所选目录中的所有项目(以及更多):

http://www.cyotek.com/blog/visual-studio-extension-for-adding-multiple-projects-to-a-solution

【讨论】:

  • 不错。在 VS2015 中运行良好。 :)
  • 虽然在 VS2012 中不起作用...github.com/cyotek/Cyotek.AddProjects/issues/4
  • 这很可悲 :( 作为一种解决方法,您可能会为此使用 2015,但如果有更好的解决方案会很棒。
【解决方案4】:

使用 Visual Studio 扩展“Add Existing Projects”。它适用于 Visual Studio 2012、2013、2015、2017。

要使用扩展程序,请打开工具菜单并选择添加项目。

【讨论】:

  • 这也适用于 2019,尽管有潜在不稳定的警告。
【解决方案5】:

您也许可以编写一个小的 PowerShell 脚本或 .NET 应用程序来解析所有项目的 .csproj XML 并提取它们的详细信息(ProjectGuid 等),然后将它们添加到 .sln 文件中。手动添加它们会更快,风险更小,但仍然是一个有趣的挑战。

【讨论】:

    【解决方案6】:

    注意:这仅适用于 Visual Studio 2010

    Found here 是 Visual Studio 2010 的一个很酷的插件,它在 VS 中为您提供了一个 PowerShell 控制台,让您可以与 IDE 进行交互。您可以使用@Avram 提到的内置 VS 可扩展性来做许多其他事情,将文件或项目添加到解决方案中非常容易。

    【讨论】:

    • 答案中的链接似乎已过时。
    【解决方案7】:

    这是 Bertrand 脚本的 PowerShell 版本,它假定解决方案文件旁边有一个 Src 和 Test 目录。

    function GetGuidFromProject([string]$fileName) {
        $content = Get-Content $fileName
    
        $xml = [xml]$content
        $obj = $xml.Project.PropertyGroup.ProjectGuid
    
        return [Guid]$obj[0]
    }
    
    $slnPath = "C:\Project\Foo.sln"
    
    $solutionDirectory = [System.IO.Path]::GetDirectoryName($slnPath)
    
    $srcPath = [System.IO.Path]::GetDirectoryName($slnPath)
    $writer = new-object System.IO.StreamWriter ($slnPath, $false, [System.Text.Encoding]::UTF8)
    
    $writer.WriteLine("Microsoft Visual Studio Solution File, Format Version 12.00")
    $writer.WriteLine("# Visual Studio 2013")
    
    $projects = gci $srcPath -Filter *.csproj -Recurse
    
    foreach ($project in $projects) {
       $fileName = [System.IO.Path]::GetFileNameWithoutExtension($project)
    
       $guid = GetGuidFromProject $project.FullName
    
       $slnRelativePath = $project.FullName.Replace($solutionDirectory, "").TrimStart("\")
    
       # Assume the project is a C# project {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
       $writer.WriteLine("Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""$fileName"", ""$slnRelativePath"",""{$($guid.ToString().ToUpper())}""")
       $writer.WriteLine("EndProject")
    }
    
    $writer.Flush()
    $writer.Close()
    $writer.Dispose()
    

    【讨论】:

      【解决方案8】:

      如果你用记事本打开 sln 文件,你可以看到文件的格式,这很容易理解,但更多信息请看@Hack the Project and Solution Files。了解解决方案文件的结构,你可以编写一个应用程序,它将打开所有项目文件并将应用程序名称、地址和 GUID 写入 sln 文件。

      当然我认为如果只是一次你最好手动完成

      【讨论】:

        【解决方案9】:

        每个答案似乎都使​​目录结构变平(所有项目都添加到解决方案根目录,而不考虑文件夹层次结构)。因此,我编写了自己的控制台应用程序来生成解决方案并使用解决方案文件夹对它们进行分组。

        查看GitHub中的项目

        用法

          SolutionGenerator.exe --folder C:\git\SomeSolutionRoot --output MySolutionFile.sln
        

        【讨论】:

          【解决方案10】:

          当您安装了 dotnet core 后,您可以从 git bash 执行此操作:

          donet new sln; find . -name "*.csproj" -exec dotnet sln add {} \;
          

          生成的解决方案适用于为旧 .NET Framework 创建的 csproj。

          【讨论】:

            【解决方案11】:

            这里已经有很多答案了,但没有一个比这个 powershell oneliner 更清楚

            Get-ChildItem -Recurse -Include *.csproj | ForEach-Object { dotnet sln add $_ }
            

            【讨论】:

            • 这太棒了!!
            【解决方案12】:

            取决于 Visual Studio 版本。
            但这个过程的名称是“Visual Studio 的自动化和可扩展性”
            http://msdn.microsoft.com/en-us/library/t51cz75w.aspx

            【讨论】:

              【解决方案13】:

              检查一下: http://nprove.codeplex.com/

              它是一个免费的 vs2010 插件,它可以做到这一点以及更多 如果项目在 tfs 下

              【讨论】:

                【解决方案14】:

                以 Bertrand 在 https://stackoverflow.com/a/16069782/492 的回答为基础 - 制作一个控制台应用程序,并在您希望 VS 2015 解决方案出现的根文件夹中运行它。它适用于 C# 和 VB(嘿!别客气)。

                它会覆盖除源代码控制之外的任何现有内容,对吗?

                检查最近使用的 .SLN 文件,看看在您阅读本文时,前几行 writer.WriteLine() 标题行实际上应该是什么。

                不用担心项目类型 GUID Ptoject("0") - Visual Studio 会在您保存 .sln 文件时解决并写入。

                using System;
                using System.Collections.Generic;
                using System.IO;
                using System.Linq;
                using System.Text;
                using System.Xml;
                using System.Xml.Linq;
                
                namespace AddAllProjectsToNewSolution
                {
                    class Program
                    {
                        static void Main(string[] args)
                        {
                            Console.WriteLine("starting");
                            using (var writer = new StreamWriter("AllProjects.sln", false, Encoding.UTF8))
                            {
                                writer.WriteLine("Microsoft Visual Studio Solution File, Format Version 14.00");
                                writer.WriteLine("# Visual Studio 14");
                                writer.WriteLine("VisualStudioVersion = 14.0.25420.1");
                                var seenElements = new HashSet<string>();
                
                                foreach (var file in (new DirectoryInfo(Directory.GetCurrentDirectory())).GetFiles("*.*proj", SearchOption.AllDirectories))
                                {
                                    string extension = file.Extension;
                                    if (extension != ".csproj" && extension != ".vbproj")
                                    {
                                        Console.WriteLine($"ignored {file.Name}");
                                        continue;
                                    }
                
                                    Console.WriteLine($"adding {file.Name}");
                
                                    string fileName = Path.GetFileNameWithoutExtension(file.Name);
                
                                    if (seenElements.Add(fileName))
                                    {
                                        var guid = ReadGuid(file.FullName);
                                        writer.WriteLine($"Project(\"0\") = \"{fileName}\", \"{GetRelativePath(file.FullName)} \", \"{{{guid}}}\"" );
                                        writer.WriteLine("EndProject");
                                    }
                
                                } 
                            }
                             Console.WriteLine("Created AllProjects.sln. Any key to close");
                             Console.ReadLine();
                        }
                
                        static Guid ReadGuid(string fileName)
                        {
                            using (var file = File.OpenRead(fileName))
                            {
                                var elements = XElement.Load(XmlReader.Create(file));
                                return Guid.Parse(elements.Descendants().First(element => element.Name.LocalName == "ProjectGuid").Value);
                            }
                        }
                        // https://stackoverflow.com/a/703292/492
                        static string GetRelativePath(string filespec, string folder = null)
                        {
                            if (folder == null)
                                folder = Environment.CurrentDirectory;
                
                            Uri pathUri = new Uri(filespec);
                            // Folders must end in a slash
                            if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
                                folder += Path.DirectorySeparatorChar;
                
                            Uri folderUri = new Uri(folder);
                            return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
                        }
                    }
                }
                

                【讨论】:

                  【解决方案15】:

                  这里是Bertrand's solution 更新为 Microsoft Visual Studio 解决方案文件,格式版本 12.00

                  using System;
                  using System.Collections.Generic;
                  using System.IO;
                  using System.Text;
                  
                  namespace AllSolutionGenerator
                  {
                      internal static class Program
                      {
                          private static void Main()
                          {
                              var dir = new DirectoryInfo(Directory.GetCurrentDirectory());
                  
                              var projects = new Dictionary<string, string>();
                              var guid1 = Guid.NewGuid().ToString().ToUpperInvariant();
                  
                              using (var writer = new StreamWriter("all.sln", false, Encoding.UTF8))
                              {
                                  writer.WriteLine("Microsoft Visual Studio Solution File, Format Version 12.00");
                  
                                  foreach (var file in dir.GetFiles("*.csproj", SearchOption.AllDirectories))
                                  {
                                      var fileName = Path.GetFileNameWithoutExtension(file.Name);
                  
                                      if (!projects.ContainsKey(fileName))
                                      {
                                          var guid = Guid.NewGuid().ToString().ToUpperInvariant();
                  
                                          projects.Add(fileName, guid);
                  
                                          writer.WriteLine(@$"Project(""{{{guid1}}}"") = ""{fileName}"", ""{file.FullName}"",""{guid}""");
                                          writer.WriteLine("EndProject");
                                      }
                                  }
                  
                                  writer.WriteLine("Global");
                                  writer.WriteLine("  GlobalSection(SolutionConfigurationPlatforms) = preSolution");
                                  writer.WriteLine("      Debug|Any CPU = Debug|Any CPU");
                                  writer.WriteLine("      Release|Any CPU = Release|Any CPU");
                                  writer.WriteLine("  EndGlobalSection");
                                  writer.WriteLine("  GlobalSection(ProjectConfigurationPlatforms) = postSolution");
                  
                                  foreach (var (_, guid) in projects)
                                  {
                                      writer.WriteLine(@$"        {{{guid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU");
                                      writer.WriteLine(@$"        {{{guid}}}.Debug|Any CPU.Build.0 = Debug|Any CPU");
                                  }
                  
                                  writer.WriteLine("  EndGlobalSection");
                                  writer.WriteLine("EndGlobal");
                              }
                          }
                      }
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    如果您在解决方案资源管理器中选择“显示所有文件”,则可以查看所有文件和文件夹并选择它们并右键单击以使用“包含在项目中”添加它们。

                    【讨论】:

                    • 这会将文件添加到项目中,而不是像 OP 要求的那样将项目添加到解决方案中。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-10-20
                    • 2015-11-28
                    • 1970-01-01
                    • 2017-07-11
                    • 2012-07-01
                    相关资源
                    最近更新 更多