I have a Text Template snippet which generates a Solution
class with an Assemblies
property to list all project assemblies in the Visual Studio solution to help with IoC container configuration (GitHub, NuGet). It fails when projects are placed in solution folders though. How to make solution folders transparent for this script? The problematic code is:
<#+
class SolutionAssemblyNames : IEnumerable<string>
{
public SolutionAssemblyNames(ITextTemplatingEngineHost host)
{
Host = host;
}
public IEnumerator<string> GetEnumerator() => Assemblies.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerable<string> Assemblies => Projects
.Select(p => p?.Properties?.Item("AssemblyName")?.Value as string)
.Distinct().Where(a => !string.IsNullOrWhiteSpace(a));
IEnumerable<Project> Projects => VisualStudio.Solution.Projects.OfType<Project>();
DTE VisualStudio => (Host as IServiceProvider).GetService(typeof(DTE)) as DTE;
ITextTemplatingEngineHost Host { get; }
}
#>
The DTE doesn't return a flat list of projects, so you need to proactively check for solution folders and then read its sub-projects, recursively (as you can have solution folders inside solution folders, etc.)
IEnumerable<string> Assemblies => Projects
.SelectMany(GetProjectAndSubProjects) // ################# Flatten the list of projects
.Select(p => p?.Properties?.Item("AssemblyName")?.Value as string)
.Distinct()
.Where(a => !string.IsNullOrWhiteSpace(a));
IEnumerable<Project> Projects => VisualStudio.Solution.Projects.OfType<Project>();
private static IEnumerable<EnvDTE.Project> GetProjectAndSubProjects(EnvDTE.Project project)
{
if (project.Kind == VsProjectKindSolutionFolder)
{
return project.ProjectItems
.OfType<EnvDTE.ProjectItem>()
.Select(p => p.SubProject)
.Where(p => p != null)
.SelectMany(GetProjectAndSubProjects);
}
return new[] { project };
}
// Copied from EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder
private const string VsProjectKindSolutionFolder = "{66A26720-8FB5-11D2-AA7E-00C04F688DDE}";