Tag Archives: Solution Folders

An ADR Visual Studio Tool – Part 5 – Sub Projects

Here, 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 here.

Sub Projects

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:

        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.

Validation

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 this:

        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:

            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!

References

https://stackoverflow.com/questions/38740773/how-to-get-project-inside-of-solution-folder-in-vsix-project

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