I'm making a helper application that reformats some code files and creates new code files, which are to be added to my other project, so I could use the new code right away, but I'm having serious trouble adding that new code file into my project automatically. By the way it's in c# and the helper app is WinForms.
This question's only answer has two ways of doing that, but I couldn't make any of them work. With the first I can't find a Microsoft.Build
assembly to reference, and in the other there are clearly not enough arguments for a command line.
How do I programmatically include a file into a project without the use of third-party applications?
Basically, I'm looking for the equivalent of this:
...But done using code.
These are the features I suppose the solution should offer:
With user @psubsee2003's help I was able to find the Microsoft.Build.dll
file in C:\Windows\Microsoft.NET\Framework\v4.0.30319
folder on my computer and successfully import it by changing my project's target framework to version 4 Full profile, not the default Client profile.
And I found how to use the AddItem
method:
var p = new Microsoft.Build.Evaluation.Project(@"C:\projects\MyProject.csproj");
p.AddItem("Compile", @"C:\folder\file.cs");
p.Save();
The file will appear in project's root folder unless the project already had a folder called folder
, in which case the file will be placed there. So basically the file will be placed in the deepest folder chain found in the original file's path going towards the root folder.
It worked for my just adding the it to the ProjectFolder, and also add the folder programmatically like this.
var p = new Microsoft.Build.Evaluation.Project(@"C:\projects\BabDb\test\test.csproj");
p.AddItem("Folder", @"C:\projects\BabDb\test\test2");
p.AddItem("Compile", @"C:\projects\BabDb\test\test2\Class1.cs");
p.Save();
As a supplement to Boot750's answer (first suggested as an edit to his answer but re-posted as a standalone)
You should note that the call to new Microsoft.Build.Evaluation.Project(path)
actually causes the project to be loaded into a global cache maintained by the Microsoft.Build.Evaluation
assembly. Calling new Project(path)
again with the same path, without unloading it from the global collection first/restarting your app will cause an exception like:
An equivalent project (a project with the same global properties and tools version) is already present in the project collection, with the path "YOUR_PATH". To load an equivalent into this project collection, unload this project first.
even if the variable p
has gone out of scope.
You might hence need to adopt a pattern more like this, if you plan to use the Load/AddItem/Save pattern repeatedly:
var p =
Microsoft.Build.Evaluation
.ProjectCollection.GlobalProjectCollection
.LoadedProjects.FirstOrDefault(pr => pr.FullPath == projFilePath);
if (p == null)
p = new Microsoft.Build.Evaluation.Project(projFilePath);
Just to add to the response from @caius-jard
Once the project is in the GlobalProjectCollection it's held in memory and does not reflect any manual changes made to the project. This includes updating the .csproj file and using VS to remove the generated files.
If you remove the generated file and run the code again the project will update to contain 2 of the generated file. Use the ReevaluateIfNecessary() function to update the instance of the project before use like this:
var p = Microsoft.Build.Evaluation
.ProjectCollection.GlobalProjectCollection
.LoadedProjects.FirstOrDefault(pr => pr.FullPath == projFilePath);
if (p == null)
p = new Microsoft.Build.Evaluation.Project(projFilePath);
// Update instance of project
p.ReevaluateIfNecessary();
// Check folder is not already in the project
var folderLoc = @"C:\projects\BabDb\test\test2";
if(p.Items.FirstOrDefault(i => i.EvaluatedInclude == folderLoc) == null)
p.AddItem("Folder", folderLoc);
// Check file is not already in the project
var fileLoc = @"C:\projects\BabDb\test\test2\Class1.cs";
if(p.Items.FirstOrDefault(i => i.EvaluatedInclude == fileLoc) == null)
p.AddItem("Compile", fileLoc);
p.Save();
The simplest way to do this is to modify the Project file. As it is just an MSBUILD file, VS will pick up the change and prompt up to reload the project. Load the project file as an XML and find the first <Compile Include="Name of File.cs" />
. Insert a new <Compile Include="NewFile.CS" />
and your done.
As another option you can remove all the <Compile>
tags and replace them with <Compile Include="*.cs" />
I know that this is an old post. However, I was in need of this option and didn't find the suitable one as I wished. So, I developed a VS extension with extended features. You can set the file types, and then, select the list of projects' directory that you want their files to be loaded into the project once they get generated.
Market (free) | Source-Code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With