An ADR Visual Studio Extension – Sub Projects
Tags: extensions, visualstudio
Published: 2020-01-26 15:26:19

<a href="https://www.pmichaels.net/2019/09/07/an-adr-visual-studio-tool-part-1-creating-a-visual-studio-extension-to-scrape-the-solution-and-list-all-items-including-solution-items-and-solution-folders/">Here</a>, I started writing about my efforts to create an extension for Visual Studio that would allow a user to see all of the ADR records in their solution.

If you wish to see the code for this project, then it can be found <a href="https://github.com/pcmichaels/ADRManager">here</a>.

<h1>Sub Projects</h1>

In this post, I wanted to cover the concept of Sub Projects.  Essentially, when you have a solution folder, scrolling through the solution projects will return top level solution folders as "Project Items".  Being folders, these don't contain "Project Items" of their own - rather they contain Sub Projects.  Let's see how we could change our code to look at these:

```csharp
        private async Task ScanProjectItems(
            ProjectItems projectItems, ProjectData projectData, string solutionDirectory)
        {
            await Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            foreach (EnvDTE.ProjectItem pi in projectItems)
            {
                if (pi.IsKind(ProjectItemTypes.SOLUTION_FOLDER, 
                              ProjectItemTypes.PROJECT_FOLDER,
                              ProjectItemTypes.SOLUTION_ITEM))
                {
                    if (pi.ProjectItems != null)
                    {
                        await ScanProjectItems(pi.ProjectItems, projectData, solutionDirectory);
                        continue;
                    }
                    else if (pi.SubProject != null)
                    {
                        await ScanProjectItems(pi.SubProject.ProjectItems, projectData, solutionDirectory);
                        continue;
                    }                    
                }

                if (!_rulesAnalyser.IsProjectItemNameValid(pi.Name))
                {
                    continue;
                }

                string text = await pi.GetDocumentText(solutionDirectory);
                if (string.IsNullOrWhiteSpace(text)) continue;

                projectData.Items.Add(new Models.ProjectItem()
                {
                    Name = pi.Name,
                    Data = text
                });
            }
        }

```

Previously, we were only calling recursively where we had project items, but now we're checking for SubProjects, and using the project items inside the sub project to recursively call the method.

<h1>Validation</h1>

The other issue that we have is that, for the solution items, we can't get the path to the specific item.  For normal projects, we would do it like <a href="https://stackoverflow.com/questions/59531191/getting-the-contents-of-a-file-in-visual-studio-without-opening-the-file-from-an">this</a>:

```csharp
        private async static Task<string> GetFullPath(Properties properties)
        {
            try
            {
                await Microsoft.VisualStudio.Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                return properties?.Item("FullPath")?.Value?.ToString();
            }
            catch
            {
                return string.Empty;
            }
        }
```

So, what we need to do is check if we can get the text; then, if it's blank, check if we can get it another way; then, if it's blank... etc.. It looks like this:

```csharp
            string path = await GetFullPath(projectItem.Properties);
            if (string.IsNullOrWhiteSpace(path))
            {
                path = await GetFullPath(projectItem.ContainingProject?.Properties);

                if (string.IsNullOrWhiteSpace(path))
                {
                    path = Path.Combine(solutionDirectory, projectItem.Name);
                }
                else
                {
                    path = Path.Combine(path, projectItem.Name);
                }
            }
```

Not very pretty, I'll grant!





<h1>References</h1>

<a href="https://stackoverflow.com/questions/38740773/how-to-get-project-inside-of-solution-folder-in-vsix-project">https://stackoverflow.com/questions/38740773/how-to-get-project-inside-of-solution-folder-in-vsix-project</a>

<a href="https://stackoverflow.com/questions/2336818/how-do-you-get-the-current-solution-directory-from-a-vspackage">https://stackoverflow.com/questions/2336818/how-do-you-get-the-current-solution-directory-from-a-vspackage</a>