Is there an easy way to add multiple projects to a solution?
Asked Answered
T

2

7

In some solutions I use direct references to internal projects during development and switch to nuget references for release. However, adding 30+ projects to new solutions manually is a tedious task.

I was wondering whether there is a quicker way to do this. With projects it's pretty easy because you just copy/paste the xml but solution files are not that easy to edit but maybe there is some trick?

Tann answered 19/4, 2019 at 16:11 Comment(10)
@AhmadIbrahim sure, but it's not like the *.sln format is as self explanatory as *.csproj files are. With all the guids it's pretty confusing what to edit :|Tann
I have not heard of any visual studio extension that helps with this. Editing the SLN file by hand may be as much or more work than doing it manually through VS. You would have to open each csproj and file the GUID and enter that into the SLN, along with the path, and also setup any build configurations in the SLN. Maybe create a script and make it open source?Omophagia
Can you accomplish what you want with 2 separate SLN files? Or separate solution configurations?Omophagia
@Omophagia I would... do you think there is an API that one can use in such a script?Tann
I would use Fake if you like F# or Cake if you prefer C#. They make lots of automation tasks easier. You could also just do a small C# console app. You mostly just need System.IO classes to manipulate files.Omophagia
System.Xml.Linq may also be useful for dealing with the XML in csproj files at a higher level than just raw text.Omophagia
@Omophagia oh, I was thinking more in terms of visual-studio API like AddProjectReference(fileName) that I could use from the cmd-line level ;-]Tann
I am not familiar with the APIs for VS extensions and automation.Omophagia
learn.microsoft.com/en-us/visualstudio/extensibility/…Omophagia
@Omophagia done! You can take a look if you're curious ;-)Tann
E
3

You can use the dotnet CLI.

For Linux:

dotnet sln MySolution.sln add **/*.csproj

For Windows PowerShell:

dotnet sln MySolution.sln add (Get-ChildItem -Recurse *.csproj)
Edelweiss answered 9/8, 2022 at 16:22 Comment(2)
This works on Windows too! Also perfect timing because I was going to update some old solutions and this will make it a piece of cake ;-]Tann
Probably also interesting for people wanting to create a super solution from scratch - just create an empty solution before invoking the add command: dotnet new sln --name MySolutionMeticulous
T
0

I've done some reaserch on the visualstudio extensibility based on @JamesFaix link and I managed to put together this small piece of code:

using System;
using System.IO;
using System.Linq;
using EnvDTE;
using EnvDTE80;

class Program
{
    static void Main(string[] args)
    {
        // VS2019
        var dteType = Type.GetTypeFromProgID("VisualStudio.DTE.16.0", true);
        var dte = (EnvDTE.DTE)System.Activator.CreateInstance(dteType);

        var sln = (SolutionClass)dte.Solution;

        // Solution to add projects to
        sln.Open(@"C:\Projects\MyProject\MySolution.sln");

        // Projects should be added to the "lib" solution-folder.
        var lib = FindSolutionFolderOrCreate(sln, "lib");

        // These projects should be added.
        var projectPaths = new[]
        {
            @"C:\Projects\MyLibs\Lib1.csproj",
            @"C:\Projects\MyLibs\Lib2.csproj"
        };

        foreach (var path in projectPaths)
        {
            var name = Path.GetFileNameWithoutExtension(path);
            // If project not already in the solution-folder then add it.
            if(!(lib.Parent.ProjectItems.Cast<ProjectItem>().Any(pi => pi.Name == name)))
            {
                lib.AddFromFile(path);
            }
        }

        dte.Solution.Close(true);
    }

    private static SolutionFolder FindSolutionFolderOrCreate(SolutionClass sln, string folderName)
    {
        foreach (var x in sln.Projects)
        {
            if (x is Project p && p.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase))
            {
                return (SolutionFolder)p.Object;
            }

        }

        var proj = (sln as Solution2).AddSolutionFolder(folderName);

        return (SolutionFolder)proj.Object;
    }
}

*.csproj file of this utility:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <!--<TargetFramework>netcoreapp2.2</TargetFramework>-->
    <TargetFramework>net47</TargetFramework>
    <EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>full</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="EnvDTE">
      <HintPath>..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\envdte.dll</HintPath>
    </Reference>
    <Reference Include="EnvDTE80">
      <HintPath>..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\envdte80.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

I'm using net47 here because netcoreapp doesn't allow you to debug COM objects which makes it really a painful experience.

You'll also need references to the two EnvDTE files.

Tann answered 19/4, 2019 at 18:39 Comment(3)
You have to admit, this is such a mess this API. Without other SE questions I would probably could never find out that you need to cast a SolutionClass into (sln as Solution2) - what a mindfuck :-oTann
I've put it on GitHub too, it's hereTann
tried the code on latest vs2019 - failed with CS1752 Interop type 'SolutionClass' cannot be embedded. Use the applicable interfaceGale

© 2022 - 2024 — McMap. All rights reserved.