61

Due to issues with merging etc, we have lots of project files that don’t contain all source code files that are within their folders.

Before I write a little tool, that checks that every *.cs file is included in a project file, I wish to make sure that no-body else has already done that before.

(We have close to 100 project files, and 1000s of C# files)

-------------------

Clearly the support that visual studio now has for using wildcards to include all “*.cs” files from a given directory in the project is the best solution to this problem. In that there is then no need to update project files when “.cs” files are added, renamed ete. However it is only in VS2017 that this become usable from the UI.

TPAKTOPA
  • 2,462
  • 1
  • 19
  • 26
Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317

12 Answers12

67

With that number of files and projects, it sounds like you might want something more automated. However, there is a manual approach (not sure if you are already aware of it):

  1. Select the project in Solution Explorer pane
  2. Project menu -> Show all Files
  3. Under the project, files which are not part of the project will show up as "ghost" icons
  4. Select the file(s) you want and pick "Include In Project" from the context menu
JohnD
  • 14,327
  • 4
  • 40
  • 53
  • The appearance of this option seems to be dependent on the individual project. This works for one solution that I have but "Show all files" option does not appear in another solution. Still working to determine the difference. (VS 2013). – Lars Jul 23 '14 at 14:58
  • Ah, a solution without having to write anything to add to VS 2015. Can't for the likes of me figure out why I couldn't add this file to VS 2015 project. It was there in Windows Explorer. Project worked, but you just couldn't see or get to the file in VS 2015. Now all is well. Thanks! – JustJohn Feb 02 '16 at 22:58
  • 2
    Tiny tip: If you find that the 'Include in project' option in context menu is greyed out, then you may be running/debugging it - so press the 'stop' button and then option will become available. – DEzra Jul 14 '16 at 14:17
  • 1
    This is fine if there are only a few subfolders to eyeball and see the "ghosted" files, but in my case there are hundreds of subfolders, and there doesn't seem to be any practical way to find all of the missing files. This is a HUGE problem after upgrading 3rd party JS and CSS libraries via Nuget. If those new versions come with new files, you have to manually find them and "Include" them in your projects. It is a massive pain in the ass. Visual Studio needs a better solution. – Bryan Williams Jun 19 '20 at 17:18
33

I've found the "Show missing files for VS 2019" Visual Studio extension. It will show the list both missing and not referenced from project files in the "Error list" window after the build.

For the older Visual Studio use "Show missing files for VS 2013-2017" extension.

izogfif
  • 6,000
  • 2
  • 35
  • 25
  • 2
    This solves the opposite problem of having files referenced from a project file that doesn’t exist in the file system. We had lots of source files (tests) in the file systems that were not referenced from project files. – – Ian Ringrose Oct 06 '16 at 10:19
  • 5
    It also solves the direct problem. There are two types of "errors" added in the "Error list" by this extension. The first one shows existing files not added to the project. The second one shows files added to the project (present in the project tree), but not found on the disk. – izogfif Oct 07 '16 at 03:46
  • This is a great solution. The currently most upvoted solution by JohnD definitely works -- but this removes the need to visually inspect each folder. – bdwakefield Oct 13 '16 at 19:52
9

After reading there is no generic solution for this here on Stack Overflow, I created a NodeJS module this weekend to solve this problem:

https://www.npmjs.com/package/check-vs-includes

This is pretty generic, so I hope this helps others as well. It saves me a manual check of over 70 folders (500+ files) on every deploy. If I have some time I hope to improve some things, like documentation... But let me give a simple example right now.

Simple example

  1. Install nodeJS (Works great on Windows too)
  2. npm install check-vs-includes

  3. Add a task for it and specify the files to check for.

For instance add a gulpfile.js to your project:

gulp.task('checkVSIncludes', function(cb) {
    checkVSIncludes(['/Content/**/*.less', '/app/**/*.js']);
});

This example checks that all .js and .less files in the specified folders are included in your project file. Notice that you can use glob's.

  1. Run the check; for the GULP example:

    gulp checkVSIncludes

Check the source code for more options, it's all on GitHub (contributions are welcome ;)).

Bart
  • 5,065
  • 1
  • 35
  • 43
  • Interesting including the checks as part of the build, would not have worked for me, as it would have needed 20+ people to install software on their machines. I used my "hack" after big merges etc, to check if the project file where OK, it did not make it into the automated build script in the end. – Ian Ringrose Jul 13 '15 at 15:49
  • I would also be concerned that the change to the project file to add the checks would get lost with a merger. Project files just don't merge well. – Ian Ringrose Jul 13 '15 at 15:50
  • @IanRingrose You can indeed add this check to your build process. Even in a 'watch', to check after every change of a targeted file. Given the time I might add an GULP plugin for this, to further simplify this. But the module works fine as it is. I'm currently running it manually during deploys. So I would notice if it disappeared from the package.json.. The task replaces a manual check of opening 77 folders (and 500+ files) I had to do previously :) There IS a node dependency, but in my current project all devs already have Node installed. Shouldn't everyone have Node? Its 2015 already :P – Bart Jul 14 '15 at 18:06
7

In my search for a solution for this, I ran into this VS Extension, but it only works with VS 2012. It's also on Github.

For VS 2013+ I use a Powershell script found on this blog post. Note that it only works for C# projects, but you can modify it for VB projects.

#Author: Tomasz Subik http://tsubik.com
#Date: 8/04/2012 7:35:55 PM
#Script: FindProjectMissingFiles
#Description: Looking for missing references to files in project config file
Param(
    [parameter(Mandatory=$false)]
    [alias("d")]
    $Directory,
    [parameter(Mandatory=$false)]
    [alias("s")]
    $SolutionFile
)


Function LookForProjectFile([System.IO.DirectoryInfo] $dir){
    [System.IO.FileInfo] $projectFile = $dir.GetFiles() | Where { $_.FullName.EndsWith(".csproj") } | Select -First 1

    if ($projectFile){
        $projectXmlDoc = [xml][system.io.file]::ReadAllText($projectFile.FullName)
        #[xml]$projectXmlDoc = Get-Content $projectFile.FullName
        $currentProjectPath = $projectFile.DirectoryName+"\"
        Write-Host "----Project found: "  $projectFile.Name

        $nm = New-Object -TypeName System.Xml.XmlNamespaceManager -ArgumentList $projectXmlDoc.NameTable
        $nm.AddNamespace('x', 'http://schemas.microsoft.com/developer/msbuild/2003')
        [System.Collections.ArrayList]$filesListedInProjectFile = $projectXmlDoc.SelectNodes('/x:Project/x:ItemGroup/*[self::x:Compile or self::x:Content or self::x:None]/@Include', $nm) | Select-Object Value

        CheckProjectIntegrity $dir $currentProjectPath $filesListedInProjectFile;
    }
    else { $dir.GetDirectories() | ForEach-Object { LookForProjectFile($_); } }
}

Function CheckProjectIntegrity([System.IO.DirectoryInfo] $dir,[string] $currentProjectPath,  [System.Collections.ArrayList] $filesListedInProjectFile ){
    $relativeDir = $dir.FullName -replace [regex]::Escape($currentProjectPath)
    $relativeDir = $relativeDir +"\"
    #check if folder is bin obj or something
    if ($relativeDir -match '(bin\\|obj\\).*') { return }

    $dir.GetFiles()  | ForEach-Object {
        $relativeProjectFile = $_.FullName -replace [regex]::Escape($currentProjectPath)
        $match = $false
        if(DoWeHaveToLookUpForThisFile($relativeProjectFile))
        {
            $idx = 0
            foreach($file in $filesListedInProjectFile)
            {
                if($relativeProjectFile.ToLower().Trim() -eq $file.Value.ToLower().Trim()){
                    $match = $true
                    break
                }
                $idx++
            }
            if (-not($match))
            {
                Write-Host "Missing file reference: " $relativeProjectFile -ForegroundColor Red
            }
            else
            {
                $filesListedInProjectFile.RemoveAt($idx)
            }
        }
    }
    #lookup in sub directories
    $dir.GetDirectories() | ForEach-Object { CheckProjectIntegrity $_ $currentProjectPath $filesListedInProjectFile }
}

Function DoWeHaveToLookUpForThisFile($filename)
{
    #check file extensions
    if ($filename -match '^.*\.(user|csproj|aps|pch|vspscc|vssscc|ncb|suo|tlb|tlh|bak|log|lib|sdf)$') { return $false }
    return $true    
}

Write-Host '######## Checking for missing references to files started ##############'
if($SolutionFile){
    [System.IO.FileInfo] $file = [System.IO.FileInfo] $SolutionFile
    $Directory = $file.Directory
}
LookForProjectFile($Directory)
Write-Host '######## Checking for missing references to files ends ##############'

Example usage (should be run from the NuGet console):

./FindProjectMissingFiles.ps1 -s $dte.Solution.FileName
Samir Aguiar
  • 2,509
  • 2
  • 18
  • 32
TWilly
  • 4,863
  • 3
  • 43
  • 73
  • The PowerShell script (including the addin from that repo) works great even up to VS2015, even though the extension doesn't. – EKW Apr 15 '16 at 19:26
  • 1
    Worth mentioning that that ps1 should be run from within the powerhell console (tools > package manager > nuget console) with the sln open. I ran it from a plain console and got the results from a different sln, which was odd. – Tim Abell Jul 08 '16 at 11:07
6

A small C# console application that finds all cs files referred from project files under a certain root folder (recursively), and compares with files in the file system under the same root folder. Can be applied to different file extensions, and different project file structures (I have tested it for VS2008). It may need some modifications to suit other needs, but should provide a useful base.

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace CompareProjectFilesWithFileSystem
{
    class Program
    {
        static void Main(string[] args)
        {
            string ext = "cs";
            string rootProjectFolder = @"C:\MySolutionRootFolder";
            Regex projectFileReferenceRegEx = new Regex(@"<(Compile|Content|None) Include=\""([^\""]+." + ext + @")\""( /)?>");

            // Files in file system:
            List<string> filesInFileSystem = new List<string>();
            filesInFileSystem.AddRange(Directory.GetFiles(rootProjectFolder, "*." + ext, SearchOption.AllDirectories));

            // Files referred from project files:
            string[] projectFilePaths = Directory.GetFiles(rootProjectFolder, "*.csproj", SearchOption.AllDirectories);
            List<string> filesReferredInProjectFiles = new List<string>();
            foreach (string projectFilePath in projectFilePaths)
            {
                string[] lines = File.ReadAllLines(projectFilePath);
                foreach (string line in lines)
                {
                    Match match = projectFileReferenceRegEx.Match(line);
                    if (match.Success)
                    {
                        filesReferredInProjectFiles.Add(Path.Combine(Path.GetDirectoryName(projectFilePath), match.Result("$2")));
                    }
                }
            }

            // Finding files referred from project files that are not contained in file system. And reversely.
            var list1 = filesReferredInProjectFiles.Except(filesInFileSystem).ToList();
            var list2 = filesInFileSystem.Except(filesReferredInProjectFiles).ToList();
        }
    }
}
Jesper Mygind
  • 2,406
  • 1
  • 18
  • 20
2

None of the previous solutions worked for me as the project I was attempting to add files to was a "Web Site Project"(WSP). When selecting the project in the solution explorer the "Project" menu item converted to "Website" and there was no "Show all Files" option.

This is because for WSP(link):

"all files are already shown in the Solution Explorer."

Except in my case they weren't... I resolved the issue by simply closing and reopening Visual Studio 2015(VS) and reloading the project. I think VS only detects the addition of new files when the Web Site is re-loaded, not when those files are added outside of VS.

David Rogers
  • 2,601
  • 4
  • 39
  • 84
0

We had a similar situation which resulted in failed compiles due to missing files. I stumbled upon this post linked below, which helped me. It describes writing a Visual Studio macro that runs when a build is started.

Report error/warning if missing files in project/solution in Visual Studio

Community
  • 1
  • 1
Andy S.
  • 79
  • 1
  • 4
  • 1
    This solves the opposite problem of having files referenced from a project file that doesn’t exist in the file system. We had lots of source files (tests) in the file systems that were not referenced from project files. – Ian Ringrose Oct 12 '12 at 09:36
0

(Assuming that Team Foundation Server is your source control): If the file has been added to the project and shows up in Source Control Explorer, but does NOT show up in Solution Explorer, you must manually add it to Source Control Explorer by selecting "Add", "Existing Item". This is an annoying Visual Studio/TFS bug that I just spend 2 hours trying to figure out.

dmbreth
  • 21
0

I wrote a tool for this some time ago. Available here.

Roger
  • 1,944
  • 1
  • 11
  • 17
  • 2
    Link-only answers should ideally be a comment. Else, feel free to add relevant info from that link into the answer here since links can change or rot. Thanks. – bPratik Jun 12 '17 at 15:40
0

Another possibility: Sometimes the file is selectively not added to the source control. To resolve this, right-click the project and select "Add Items to Folder".

Any files not shown in the source control explorer that you see in their source folders should be here and can be selectively added.

JWiley
  • 3,129
  • 8
  • 41
  • 66
0

I know this has already been answered, but here is what I use.

using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;

namespace ProjectReferenceChecker
{
    class Program
    {
        static void Main(string[] args)
        {
            if (string.IsNullOrEmpty(args[0]))
                throw new Exception("Project file must be specified using in argument");

            var projectFile = new FileInfo(args[0]);

            var text = File.ReadAllText(projectFile.FullName);
            var regex = new Regex("<(Compile|Content|None) Include=\"([^\"]*)\".*>");

            foreach (Match match in regex.Matches(text))
            {
                var relativePath = match.Groups[2].ToString();
                relativePath = HttpUtility.HtmlDecode(relativePath);
                relativePath = HttpUtility.UrlDecode(relativePath);
                var targetPath = Path.Combine(projectFile.Directory.FullName, relativePath);
                if (!new FileInfo(targetPath).Exists)
                {
                    Console.WriteLine(relativePath);
                }
            }
        }
    }
}

To call this from a command line (windows):

  1. Publish the console app
  2. Move that folder to C:\Program Files\[Your App Name]
  3. Open start menu and look for "edit the system environment variables"
  4. At the bottom of the "Advanced" tab click "Environment Variables"
  5. Either in the top box for just your variables or bottom box for system wide variables find the "path" variable. Double click it to open the edit window.
  6. Click "New" then enter "C:\Program Files\[Your App Name]". Press okay and back all the way out. Close any CMD or powershell sessions you have open.
  7. Reopen a new cmd/ps and you should be able the following from anywhere:
    [Your App Name].exe "C:\path\to\project.csproj"
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Simon Curtis
  • 382
  • 2
  • 9
-2

If anyone has the error File Not Included the first response dated 2011 still works on VS 2017 Version 15.8.5 on .NET Framework Version 4.7.03056 Windows 10 with latest updates. Closing and reopening VS shows all files.

WinWon
  • 1
  • 1