DotNet Core .csproj code files as child items - c#

I am migrating an old .NET Framework csproj to dotnet core. What is the dotnet core equivalent of this:
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
I tried:
<ItemGroup>
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
</ItemGroup>
But I got this error:
Duplicate 'Compile' items were included. The .NET SDK includes
'Compile' items from your project directory by default. You can either
remove these items from your project file, or set the
'EnableDefaultCompileItems' property to 'false' if you want to
explicitly include them in your project file. For more information,
see https://aka.ms/sdkimplicititems. The duplicate items were:
'ProjectInstaller.Designer.cs';
'ServiceHost.Designer.cs' TestWindowsService C:\Program
Files\dotnet\sdk\2.1.4\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.Sdk.DefaultItems.targets

Since the items are included by default, you need to use Update instead of Include if you only want to modify the items that need this update and not list every cs file individually:
<ItemGroup>
<Compile Update="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
</ItemGroup>

New format SDK projects have several globbing patterns set by default to "True". One of them is to include all *.cs files in project directory and it's subdirectories. The error you are getting is caused by double inclusion of *.cs files and there is an easy way to prevent it indicated in error message. You should include into your project the following property:
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
With that setting you have to include all files in the project explicitly by using:
<ItemGroup>
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
<Compile Include="MyOtherFile.cs"/>
.......
</ItemGroup>
If you decide to not use EnableDefaultCompileItems setting all *.cs files will be included automatically, however, their grouping could be confusing as it may be flattened without any subgroupings. In this case you should not include any *.cs files eplicitly in the .csproj. The globbing pattern used by project will include files in the project automatically for you.

Related

Including a Folder in NuGet Package and have it install into project as file .netcore/Razor

I am using Visual Studio 2019 and creating NuGet packages successfully with this method:
https://learn.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package-using-visual-studio?tabs=netcore-cli
All going well, but there are some settings (.json) files contained within a directory PageSettings/
When I publish my NuGet package and then install it into a new project, this directory appears in VS as a linked item (see pic). So as a user I can access the files, but they don't "exist" when the project is run.
This means if I run this project without physically copying and adding these files I get ArgumentException: The directory name 'Path-To-project\pagesettings' does not exist. (Parameter 'Path')
I can see why this is happening, but can't work out how to change it, or if it is possible.
The article linked above suggests adding code to the csproj file like:
<ItemGroup>
<Content Include="readme.txt">
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</Content>
</ItemGroup>
But that doesn't work and in fact seems unnecessary since the Pack command is including my files, just not creating them properly when installing.
Also - it would be extremely handy if there was a way to tell VS to prompt whether to install this file or not. Since it is settings, if a user changes the settings and then later installs an updated version of my NuGet package I would not want it to overwrite their customised settings... perhaps this is why the link design happens... if so, if someone could confirm?
Actually, you should create a .props file in your nuget package.
1) create a file called <package_id>.props file in your nuget project.
Like this:
Note: if your created nuget package called test.1.0.0.nupkg, the file should be named as test.props so that it will work.
2) add these in the test.props file:
<Project>
<Target Name="CopyFiles" BeforeTargets="Build">
<ItemGroup>
<File Include="$(MSBuildThisFileDirectory)..\Pagesettings\*.*"></File>
</ItemGroup>
<Copy SourceFiles="#(File)" DestinationFolder="$(ProjectDir)Pagesettings"></Copy>
</Target>
</Project>
3) add these in xxx.csproj file:
<ItemGroup>
<None Include="Pagesettings\*.*(the json files' path of your nuget project)" Pack="true" PackagePath="Pagesettings">
</None>
<None Include="build\*.*" Pack="true" PackagePath="build"></None>
</ItemGroup>
then reapck your project.
4) then clean your nuget caches or delete all files under C:\Users\xxx(current user)\.nuget\packages.
5) when you insall this new version of the nuget package, please build your main project again to run the target to generate the files.
Besides, there is also a similar issue about this.

Exclude file from project via msbuild

In my .csproj file, I am creating directories containing files, and these directories are being created in the main project directory as intended. For certain reasons, I cannot generate these directories in bin\debug. However, I do not want the files generated in the directories to be included in the project, as I do not want them to be checked in.
How can I exclude the files from my project automatically through msbuild?
For reference, I have tried the following, and though the files get generated as expected, they are still being added to the project unintentionally:
<Target Name="BuildThings" AfterTargets="Build" BeforeTargets="GatherStagingFiles" Inputs="#(Compile)" Outputs="$(GeneratedFilesDirectory)">
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" Command="$(ToolPath) buildpackage -InputDir:$(MSBuildProjectDirectory)\$(OutDir) -OutputDir:$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)" />
</Target>
<Target Name="HideFiles" DependsOnTargets="BuildThings">
<ItemGroup>
<GeneratedFiles Include="$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)\file.txt">
<InProject>false</InProject>
</GeneratedFiles>
</ItemGroup>
</Target>

Specify AdditionalReferencePaths from an external .target file

I have a bunch of project that requires tweaks to be build in a continuous environement.
I put every tweaks in a separate .target file to reuse this file across all projects.
At the very end of my csproj files, I put (before the closing) Project element:
This is working quite well unless I try to include additional reference path.
If I specify using command line the path (msbuild myproject.csproj /p:ReferencePath="C:\path\to\dlls"). The project compile.
My target file is :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- some tweaks here -->
<PropertyGroup Condition="'$(CompileFor)' == 'SP2013'">
<SomeProperty>some value</SomeProperty>
<AdditionalReferencePaths>C:\path\to\dlls</AdditionalReferencePaths>
</PropertyGroup>
</Project>
But this does not works (dll cannot be resolved).
I also tried :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Project>
This is not working, because the ItemGroup element can't be out of a Target element
Lastly, I tried:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="SomeTarget" BeforeTargets="BeforeBuild">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Target>
</Project>
This still isn't working. No error, I can see the target is called in the build log, but the DLLs are still not resolved.
How to fix it?
To give a bit of context, tweaks I include in the target file allows me to compile the project against different version of DLLs. The code is a plugin of a 3rd party application (SharePoint to name it), and I want to compile for several different versions of the product. Using some conditional, I can target either a folder with one version of the product or another folder for other version of the product.
I get rid of this issue after two fixes.
The correct property wasn't AdditionalReferencePath but ReferencePath
I also have to move the Import before the first ItemGroup of my csproj. I guess this was required to have to properties set before the Reference element

CopyToPublishDirectory in .csproj

I'm using CopyToPublishDirectory in my .csproj to copy over files/folders when publishing my dotnet app:
<None Update="Views\**\*; wwwroot\**\*">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
Is there a way to copy over a folder and change its name in the process? For example, I'd like to copy over a subset of my node_modules folder, so I could create a new folder called node_modules_dev with my subset of npm dependencies, and copy it over via CopyToPublishDirectory as node_modules. I'd imagine the syntax would work something like this:
<None Update="node_modules_dev/**/*" Rename="node_modules">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
Thanks--
The trick here is to:
Ensure that the items are not yet included by default so there is no leftover metadata from previous glob pattern expansions. This can be done by adding the path to the DefaultItemExcludes property so the web sdk will ignore the files.
Use the %(RecursiveDir) metadata that is available for items expanded via glob patterns and represents the value of any expanded path. This will be defined for the Include="…" syntax only hence 1.
This will overwrite the default target path to a new directory using the Link metadata:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);node_modules_dev\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<Content Include="node_modules_dev\**\*" Link="node_nodules\%(RecursiveDir)%(FileName)%(Extension)" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>

Visual Studio/MSBuild copy referenced class library's app.config as *.dll.config to bin folder of current project

I have a class library that is referenced by many other web application projects. It has many settings in its app.config that I wish to use in all of the referencing web projects. When the class library is built, it copies the app.config to its own bin folder as <assembly.name>.dll.config.
How do I ensure that <assembly.name>.dll.config is copied to the bin folder of each of my referencing web application projects?
Visual Studio / MSBuild does not seem to do this by default.
Changing Copy to Output Directory or Build Action (in any combination) does not work.
SlowCheetah VS extension appears to do what I want as an unintended side-effect of its config transform process, but I want to do this without any 3rd-party extensions.
As an aside: It's impractical to manually put all of this config in each of the web application projects. I can read the file by looking for <assembly.name>.dll.config in the bin folder, and extract the settings from there. I can already do this, so that's not an issue - I just need to ensure the file is going to be there for reading
This can be achieved without 3rd-party tools by adding the following to the class library's project file, assembly.name.csproj:
// Find this <Import> element for Microsoft.CSharp.targets
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
// Add this <ItemGroup> element immediately after
<ItemGroup>
<Content Include="app.config">
<Link>$(TargetName).dll.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
This causes the app.config to be copied to whichever project is referencing it as <assembly.name>.dll.config. It's good because you only need to configure the one .csproj file and the effect cascades out to all referencing projects.
Visual Studio 2015 and earlier
For Visual Studio 2015, I am using the solution of #theyetiman (see this answer):
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<None Include="app.config">
<Link>$(TargetFileName).config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
(The import of Microsoft.CSharp.targets was already present.)
Visual Studio 2017
During my experiments, Visual Studio 2017 seems to handle configuration files as expected out of the box. No manual modification of the project file is needed.

Categories