Duplicate files in csproj file Visual Studio - visual-studio

Somehow I am seeing duplicate files in my solution. I dig into it and found that somehow, there are two entries for some files in .csproj file. That's why two files are shown that is actually one file. I have to find for all the files in .csproj file. Is there any easy way to remove those entries from csproj? And also can anyone let me know the cause of this?

As per this question and this other one on StackOverflow, this might happen when TFS (or other version control systems) edit a project file e.g. during a merge operation.
Anyway, you have probably opened a csproj file and seen that it's just an XML, with files being listed in elements like those below:
<ItemGroup>
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\ContactsController.cs" />
<Compile Include="Controllers\HomeController.cs" />
...
</ItemGroup>
One answer to the question I linked above also provides a reference to a deduplication Powershell script on GitHub, which I haven't tried and cannot guarantee for, although I don't see what harm it could do.
If your files are not too many, you can just look for the following string
.cs" />
with a text editor like PsPad, have it list the results and remove double entries by hand. Of course, before doing anything, backup your file.
Another solution involves selecting all duplicated files in your project, clicking "Exclude from project" and then "Show all files" and include them by hand.

Related

Tooling or method to re-add 'content' to projects utilizing "Package References"

A project (original VS format) is converted to use Package References. Great.
Project References "don't support content". Questionable choice, although not debated here.
Some used packages contain "content" and cannot or will not be updated to use "content files". Hmm..
What semi-automated tooling / method can be used to copy the "content" from NuGet dependencies that "don't support contentFiles"+? Only applying to direct packages is fine.
+Naturally, one could manually open up each individual NuGet file and copy the contents. This question isn't about "why" the switch was made and/or any merits or trade-offs and/or how how packages "should" be authored. The question is about an automated or semi-automated method to be able to restore the "content" into a project's source tree.
It is possible to use "content"-based NuGet packages with original Visual Studio / MSBuild projects that have been converted to use Package References.
The presented solution can likely be amended for SDK-style projects as well. The feat is accomplished by utilizing the GeneratePathProperty attribute of PackageReference+. Using the generated Pkg* path properties ensures valid paths to the referenced packages. (Note: if a package name contains ., replace it with _ in the Pkg* property name.)
First, add a GeneratePathProperty to all the packages with content to copy or link.
<PackageReference Include="bootstrap" GeneratePathProperty="true">
<Version>Don't ask..</Version>
</PackageReference>
<PackageReference Include="AngularJS.Core" GeneratePathProperty="true">
<Version>..it's not great</Version>
</PackageReference>
"Get the Content"
Depending on needs there are two different approaches presented here. While these approaches can be used together, neither approach should be applied to "content files"-based NuGet packages.
Approach #1: Copy Content to Project Source
With this approach it's expected that the files are added to source control. The following lines in the project can thus be un-commented (and re-commented) when updating packages to ensure that the newest NuGet package content.
It uses the Copy Task to, well, copy the the content.
<ItemGroup>
<NugetContentToRestore Include="
$(Pkgbootstrap)\Content\**\*.*;
$(PkgAngularJS_Core)\Content\**\*.*;
" />
</ItemGroup>
<Target Name="BeforeBuild">
<Copy SourceFiles="#(NugetContentToRestore)"
DestinationFiles="#(NugetContentToRestore->'$(ProjectDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
If the ItemGroup is not commented out during normal development, the items will be included in the the project’s solution explorer root, which is a bit ugly. It’s also not possible to detect when "content" has been removed.
Approach #2: Link in Content
If none of the content is to be copied and/or checked into source control along with the project, it can also be linked in. This approach has the benefit of always linking in the latest content and does not pollute the solution explorer.
A local file explicitly included in the project will take precedence over the linked resources.
For a Normal Project (and bin-deployed files)
For a normal project, <CopyToOutputDirectory> is sufficient and the linked files will go in the 'bin' output. However, this does not work for a Web Project which only understands files which are physically present in the project tree.
<ItemGroup>
<Content Include="$(Pkgbootstrap)\Content\**\*.*">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(PkgAngularJS_Core)\Content\**\*.*">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
For a Web Project (requires local files)
For a Web Project, these links must be copied to local files: <CopyToOutputDirectory> is not sufficient or required. Packages with content that should go into the bin output should use the approach above.
<ItemGroup>
<Content Include="$(Pkgbootstrap)\Content\**\*.*">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Content>
<Content Include="$(PkgAngularJS_Core)\Content\**\*.*">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
Then add a target to copy the linked files so they are picked up by the Web Project tooling. See Copying linked content files at each build using MSBuild. It may be relevant so skip certain links and add source control ignore entries.
<Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
<Copy SourceFiles="%(Content.Identity)"
DestinationFiles="%(Content.Link)"
SkipUnchangedFiles='true'
OverwriteReadOnlyFiles='true'
Condition="'%(Content.Link)' != ''" />
</Target>
+This works in an up-to-date Visual Studio 2019 environment. It may not work in certain older MSBuild/NuGet configurations as Pkg* property generation is required.
Tooling or method to re-add 'content' to projects utilizing “Package
References”
I am afraid that there is no such tool to make files from content folder into projects with PackageReference nuget management format.
As the user of the package, there is currently no tool to copy the files of the content folder to the projects with PackageReference.
And actually, if there is such a tool, it also violates the mechanism of nuget. All of them are depended on the author of the nuget package rather than the users unless the package is authored by us
Suggestion
So you have to manually unzip the nuget package and copy the files into your project.
And it seems to be a bit complex and if you still want to get a easy way to get what you want, I suggest you could suggest a feature on our User Voice Forum.
And after that, you could share the link here and anyone who is interested in it will vote it so that it will get more Microsoft's attention. All of these will help get what you want as soon as possible.

Generating SpecFlow's feature.cs files in a different location to the feature files

Fairly simple one: I'm trying to make SpecFlow generate feature.cs files, but in a directory I specify and not the default (which is the same directory as the associated feature file). Is this possible?
Not by default, but it might be possible.
SpecFlow uses an inbuilt mechanism inside Visual Studio called a custom tool. its a means of automatically performing an action whenever a file changes and is also used in designers (such as the winforms, asp.net etc) which also generate an xxx.designer.cs file. For more details see https://msdn.microsoft.com/en-us/library/hefydhhy.aspx
This is controlled by a couple of entries in the .csproj file
<None Include="xxx.feature">
<Generator>SpecFlowSingleFileGenerator</Generator>
<LastGenOutput>xxx.feature.cs</LastGenOutput>
</None>
and
<Compile Include="xxx.feature.cs">
<DependentUpon>xxx.feature</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
So as you can see you have all the information you need here to change the file locations and keep the association between them. However I've never tried it, so let us know how you get on.

MSBuild, include files based on a group of paths

I'm trying to create a build script which would allow me to specify a list of paths to "module projects" that is included in a specific web site.
Hence, I have this layout:
customer folder
|_MainProject
|_ModuleProject1
|_ModuleProject2
So, basically I want to be able to specify an ItemGroup that would contain ModuleProject1 and 2, and copy relevant files from it into the MainProject.
<ItemGroup>
<CustomModule Include="ModuleProject1\*.csproj" />
<CustomModule Include="ModuleProjec2\*.csproj" />
</ItemGroup>
In my main build script I then want to find out the paths to my satellite assemblies, as well as all dlls that reside inside the obj\Release*.dll folder of the project.
I already have item groups for the project file (.csproj), so basically I just want to add some more file references. But I can't figure out how I would do that. This is what I have today:
<Satellites Include="$(ReferencesFolder)\??\*.dll" />
<Satellites Include="$(SiteRoot)\bin\??\*.dll" />
<Satellites Include="%(CustomModule.RelativeDir)obj\$(Configuration)\??\*.dll" />
How would I go about making the last line work based on the facts that I have?
When doing this:
<Message Text="%(CustomModule.RelativeDir)obj\$(Configuration)\??\*.dll" />
It outputs this:
ModuleProject1\obj\Release\??\*.dll
ModuleProject2\obj\Release\??\*.dll
And if anyone has some links to the fundamentals of MSBuild with good examples, I would really appreciate it. I always end up at msdn with some really cryptic examples that doesn't really explain a lot.
EDIT: I revised my plan and almost have it working, however the include doesn't really work as I expect it to. Nothing is included, but there are files mathing the path.
If I manually add this:
<Satellites Include="ModuleProject1\obj\Release\??\*.dll" />
It is actually included in the "Satellites" item group.
Found a solution myself, seems like I needed a workaround for it to work explicitly.
Since I wasn't able to include items based on another item list, this was what I finally came up with:
<Target Name="BuildModules">
<!-- We do this because we need a property with the correct wildcards, otherwise it won't work -->
<PropertyGroup>
<CustomModuleSatellites>#(CustomModule->'%(RelativeDir)obj\$(Configuration)\??\*.dll')</CustomModuleSatellites>
</PropertyGroup>
<ItemGroup>
<Satellites Include="$(CustomModuleSatellites)" />
</ItemGroup>
</Target>
I needed to create a property within a Target (outside of it it didn't fly because it still contained the wild cards), and then use that property ti include the files using wildcards in my item list, otherwise it would be paths with wildcards in it and then the copy command didn't work either.

Visual Studio Linked Files Directory Structure

I have two versions of a project. One for Silverlight and one for .NET. The SL project has the vast majority of the code base in it. I want to globally add all files from the SL project into the .NET version as linked files. I've managed to do so successfully like this in the csproj file for the .NET version:
<Compile Include="..\MyProj.Common.SL\**\*.cs" Exclude="..\MyProj.Common.SL\Properties\**">
Unfortunately, this adds all the files right to the root of my project... so I end up with a long unreadable list of linked files in the .NET project. I really really really don't want to have to maintain an entire duplicate directory structure by hand and deal with directory name changes and file name changes and whatnot.
So, is there any way to have Visual Studio preserve the directory structure when adding linked files in the wildcard manner above? Or is there at least a way of making it group all the linked files together under a directory in the .NET project like MyProj.Common.SL.Links?
The very closest I've come is to set the <Visible>false</Visible> under the <Compile> tag, which effectively removes the long unreadable list of 300+ files....but unfortunately this screws up Resharper, which no longer sees those files as valid and it goes crazy on all the projects that reference the .NET project. If I could figure out a way of making Resharper not get all messed up, that would be an acceptable solution too...
Any suggestions?
Thanks.
I think I found a way of getting this to work:
<Compile Include="..\MyProj.Common.SL\**\*.cs" Exclude="..\MyProj.Common.SL\Properties\**">
<Link>MyProj.Common.SL.LinkedFiles\MyProj.Common.SL.LinkedFiles</Link>
</Compile>
It will create a MyProj.Common.SL.LinkedFiles folder and group all the linked files under that folder.
I think I would do this:
Copy the existing project's <Compile> items, which presumably have e.g. Include="foo.cs" and Include="Folder\bar.cs"
Paste them into the new project
Search and replace <Compile Include="(.*?)" /> with <Compile Include="..\Other\$1" ><Link>$1</Link></Compile>
I don't know if I got the regular expression search and replace syntax exactly right, but the point is, you already have a good project, you should be able to cut, paste, regex-replace it to get the same set of files, only referenced from a different folder, and with the same directory structure.
You'll still have two .csproj's to maintain at this point, but this is also easily fixed. Now take this new list of compile items, and put it in a file named e.g. "Common.csproj" that just contains the property group with those compile items, and then have both projects <Import Include="..\Common.csproj" /> and not include any Compile items of their own.
Basically, a little manual labor to refactor the .csproj file for sharing once, and then I think you'll be set. I am not sure if this is the 'easiest' way to unblock you, but I think this sounds approximately like what you may want for an 'ideal' structure.

Creating a VS 2010 Project with only content files

I have some content files that I would like to share between a number of projects in Visual Studio.
I have put these files in their own project, set the build action to "Content", and the copy to output directory to "Copy if newer". I would like all these files to be copied to the bin/debug directory of the projects that reference them.
I can get it to work by including a reference to the "contents" project in each of the projects that need the files, but that requires that a minimal assembly be generated (3K). I assume there is a way, using MSBuild, to make this all work without creating the empty assembly?
Thanks to everone who took the time to make a suggestion about how to solve this problem.
It turns out that if I want my compiled content files to be treated like content files (in that they get copied to the output directory of any other project that references my project), I need to create a target which runs before GetCopyToOutputDirectoryItems, and add the full path of the compiled content files to the AllItemsFullPathWithTargetPath ItemGroup. MSBuild calls GetCopyToOutputDirectoryItems for projects on which the current project depends, and uses the resulting file list to determine the files that are copied along with the assembly.dll. Here is the XML from my .csproj, just in case someone else has a similar problem.
I have a custom task called "ZipDictionary", and I accumulate all the files that I am going to compile in an ItemGroup called DictionaryCompile. My target, "FixGetCopyToOutputDirectoryItems" is executed before "GetCopyToOutputDirectoryItems". I don't do the actual compilation there, since this target can be called multiple times by referencing projects, and it would hurt performance. The target does some transforms to get the post-compilation file names, and then returns the full paths to all the files, since relative paths will not work when copy is called from the referencing project.
<ItemGroup>
<DictionaryCompile Include="Dictionaries\it-IT.dic">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</DictionaryCompile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="ZipDictionary" AssemblyFile="..\LogicTree.DictionaryCompiler\bin\Debug\LogicTree.DictionaryCompiler.dll"/>
<Target Name="BeforeCompile">
<Message Text="Files #(DictionaryCompile)" Importance="high" />
<ZipDictionary DictionaryFiles="#(DictionaryCompile)" OutputDirectory="$(OutputPath)">
<Output TaskParameter="OutputFiles" ItemName="DictionaryOutputFiles" />
</ZipDictionary>
</Target>
<Target Name="FixGetCopyToOutputDirectoryItems" BeforeTargets="GetCopyToOutputDirectoryItems">
<ItemGroup>
<_DictionaryCompile Include="#(DictionaryCompile->'$(OutputPath)Dictionaries\%(FileName).ltdic')" />
</ItemGroup>
<AssignTargetPath Files="#(_DictionaryCompile)" RootFolder="$(MSBuildProjectDirectory)\$(OutputPath)">
<Output TaskParameter="AssignedFiles" ItemName="_DictionaryCompileWithTargetPath" />
</AssignTargetPath>
<ItemGroup>
<AllItemsFullPathWithTargetPath Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'" />
<_SourceItemsToCopyToOutputDirectoryAlways Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='Always'" />
<_SourceItemsToCopyToOutputDirectory Include="#(_DictionaryCompileWithTargetPath->'%(FullPath)')" Condition="'%(_DictionaryCompileWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'" />
</ItemGroup>
</Target>
A better possible solution would be to
place a common directory in the solution dir and place your common content files there.
in VS, in each project that should share this content, right-click add existing item, browse to the desired item(s), select, click the down-arrow on the add button and select add as link. In the project, you will notice the files are added with a 'shortcut' overlay.
In the project, select the newly added links and right-click->properties and select Build Action: content, Copy To Output Directory: Copy Always.
This is a simple solution to the problem given.
I use this technique for things like SQL scripts and partial config files (using configSource) with great success. This allows me to make changes to these files in a single location with the assurance that they will be propigated throughout the solution.
A more robust solution would be to create a project with embedded resources. This requires a bit more work to manage the content on the receiving end but may be worth it in the long run as having a bunch of loose artifacts flying about can become problematic.
Hope that helps.
A similar solution like the one Sky suggested can be found in my answer to "Is there a way to automatically include content files into asp.net project file?".
It allows to share your content but you must not touch the folder or its content inside VS because this breaks the recursive path.
This approach works best for auto-generated content - you don't have to bother about including new content files to your solution.
And of course you can reuse this in multiple solutions/projects.
We do something similar where we have "...ReleaseBuilds" that reference dlls and content we require for specific projects. Compiling copies everything to the bin debug folder and indeed creates the empty assembly.
Within Visual Studio we have a post-build event in the "...RealeaseBuild" (in project properties) that copies/deletes or run batch files to make sure we have all the files (configs, services etc etc) required and to delete the empty assembly.
HTH

Resources