Include file in solution explorer without it being a build dependency - c#

How can I include a file in the list of files in solution explorer without including it as a dependency for compilation?
I have a .targets file that generates .cs files, similar to the examples in this answer.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CoreCompileDependsOn>$(CoreCompileDependsOn);GenerateCode</CoreCompileDependsOn>
</PropertyGroup>
<ItemGroup>
<Sources Include="..\sources\*.txt" />
</ItemGroup>
<Target Name="GenerateCode" Inputs="#(Sources)" Outputs="#(Sources->'generated\%(Filename).cs')">
<!-- run executable that generates files -->
<ItemGroup>
<Compile Include="generated\*.cs" />
</ItemGroup>
</Target>
</Project>
This builds correctly and consecutive builds don't rebuild the project unnecessarily. The resulting .cs files are not visible in the solution explorer. The generated code also isn't found by intellisense.
If I add the files with ItemGroups in the .csproj, the generated files are visible in the solution explorer, but subsequent builds result in rebuilding the project unnecessarily. The genereated code still isn't found by intellisense.
<ItemGroup>
<Sources Include="..\sources\*.txt">
<Link>sources\%(Filename)%(Extension)</Link>
</Sources>
<!-- using None instead of Compile on the next line makes no difference -->
<Compile Include="#(Sources->'generated\%(Filename).cs')">
<Generator>MSBuild:Compile</Generator>
<Link></Link>
</Compile>
</ItemGroup>
How can I tell msbuild that the .cs files included in the project are inconsequential to the build and therefore shouldn't trigger rebuilding the entire project?

Move the code generation to BeforeCompile instead of CoreCompileDependsOn. this will keep the generation of the files from tirggering the subsequent builds.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="BeforeCompile" DependsOnTargets="GenerateCode">
</Target>
<Target Name="GenerateCode" Inputs="#(Sources)" Outputs="#(Sources->'generated\%(Filename).cs')">
<!-- run executable that generates files -->
</Target>
</Project>
If you include all of the generated files in the .csproj, the visual studio intellisense will work.
<ItemGroup>
<Sources Include="..\sources\*.txt">
<Link>sources\%(Filename)%(Extension)</Link>
<LastGenOutput>generated\%(Filename).cs</LastGenOutput>
</Sources >
<Compile Include="#(Sources->'generated\%(Filename).cs')">
<Link></Link>
</Compile>
</ItemGroup>

Related

GeneratePackageOnBuild NU5118 resources.dll

in my solutions there are two libraries:
The library I want to ship as a nuget package (let's call it EntryLibrary)
The library, where I store the translations using RESX files (Translations)
The translations library csproj looks like (nothing fancy):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<Compile Update="Strings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Strings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
The EntryLibrary csproj looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>9.0</LangVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Translations\Translations.csproj" PrivateAssets="all" />
</ItemGroup>
</Project>
For someone like me, who is not very familiar with the nuspec things, I just like the ease of <GeneratePackageOnBuild>, however building this shows the following warning:
C:\Program Files\dotnet\sdk\6.0.401\Sdks\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets(221,5): warning NU5118: File '<Path-to-EntryLibrary>\bin\Debug\netstandard2.0\pl\Translations.resources.dll' is not added because the package already contains file 'lib\netstandard2.0\Translations.resources.dll'
And it won't ship any localized Translations.resources.dll. It only works if all of these are directly part of the EntryLibrary, but I seperated them by intention into another library.
Is there any way to get this working without a dedicated nuspec configuration?
UPDATE
I made a demo solution, which can be found on GitHub

Error CS0579 Duplicate 'global::System.Runtime.Versioning.TargetFrameworkAttribute'

I have 2 projects in a solution, and I am not sure why I am running into this error for the 1st project when building the solution.
Error CS0579 Duplicate
'global::System.Runtime.Versioning.TargetFrameworkAttribute'
Ive tried the following answer, Cleaned and Rebuilt, but it didn't help.
Add the following two lines to the <PropertyGroup>.
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
</PropertyGroup>
And this answer says to delete the assemeblyinfo.cs file from project under properties menu and rebuild it, but I don't even see an Assemblyinfo.cs file under properties...
I've also commented out the assembly line per a different answer, and still it failed:
// <autogenerated />
using System;
using System.Reflection;
//[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v3.1", FrameworkDisplayName = "")]
Here are my .csproj files:
Project1:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.10" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DI\DI.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="HttpTrigger1/readme.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Project2:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Files.DataLake" Version="12.6.0" />
<PackageReference Include="Azure.Storage.Queues" Version="12.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DI\DI.csproj" />
</ItemGroup>
</Project>
I got this error because I integrated two projects by removing the csproj file from Project A then including the root folder in Project B. I failed to remove the .bin and .obj folders from Project A. Hope this saves somebody some unnecessary grief.
Deleting Assembly files from Release and Debug folder resolved the issue. They must've been added at some point when I built the project.
Solved by running git clean -xdf to remove artefacts from previous builds. After that, built successfully.
I got the same problem after suppressing a level of hierarchy in my solution. The folder structure was like
/Project
/WebApi
/WebApi
/WebApi
Program.cs
webapi.csproj
I wanted to suppress a level of hierarchy so I copied the last WebApi under the first WebApi folder. After copying the projects I forgot to delete the source folders and began to experience the same error as you.
It was due to duplicated project folders :
/Project
/WebApi
/WebApi
Program.cs
webapi.csproj
/WebApi
Program.cs
webapi.csproj
After original folder deletion the problem was gone, final hierachy:
/Project
/WebApi
/WebApi
Program.cs
webapi.csproj

NuGet package install that inserts CallTarget nodes in the AfterBuild Target

I've built a NuGet package that packages managed and unmanaged dependencies, some of which are runtime dependencies, and so I have several Targets in my .targets file for the NuGet file which copy those dependencies to the bin folder of the project consuming the NuGet package, and I'd like for the consumer to not have to insert the CallTarget nodes in their .csproj file manually.
My package's .targets file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyDeviceIntegrationNativeDependencies">
<Message Text="Copying Device Integration native dependencies to $(OutDir)..." Importance="high" />
<ItemGroup>
<TDDeviceIntegrationNativeDependencies Include="$(MSBuildProjectDirectory)\..\Packages\TDDeviceIntegration*\lib\native\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(TDDeviceIntegrationNativeDependencies)" DestinationFiles="#(TDDeviceIntegrationNativeDependencies->'$(OutDir)\%(Filename)%(Extension)')" ></Copy>
</Target>
<Target Name="CopyDeviceIntegrationContentDependencies">
<Message Text="Copying Device Integration content dependencies to $(OutDir)..." Importance="high" />
<ItemGroup>
<TDDeviceIntegrationContentDependencies Include="$(MSBuildProjectDirectory)\..\Packages\TDDeviceIntegration*\content\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(TDDeviceIntegrationContentDependencies)" DestinationFiles="#(TDDeviceIntegrationContentDependencies->'$(OutDir)\%(Filename)%(Extension)')" ></Copy>
</Target>
<Target Name="CopyDeviceIntegrationManagedDependencies">
<Message Text="Copying Device Integration managed dependencies to $(OutDir)..." Importance="high" />
<ItemGroup>
<TDDeviceIntegrationManagedDependencies Include="$(MSBuildProjectDirectory)\..\Packages\TDDeviceIntegration*\lib\*.*" />
</ItemGroup>
<Copy SourceFiles="#(TDDeviceIntegrationManagedDependencies)" DestinationFiles="#(TDDeviceIntegrationManagedDependencies->'$(OutDir)\%(Filename)%(Extension)')"></Copy>
</Target>
</Project>
My consuming .csproj file needs to have this in it for those copies to happen:
<Target Name="AfterBuild">
<CallTarget Targets="CopyDeviceIntegrationNativeDependencies" />
<CallTarget Targets="CopyDeviceIntegrationContentDependencies" />
<CallTarget Targets="CopyDeviceIntegrationManagedDependencies" />
</Target>
Considering the fact that there can only be one AfterBuild target in this .csproj file (as far as I know), is there anyway that I can insert those CallTarget nodes for the consumer upon installation of the NuGet package so that the consumer doesn't have to add those in manually? I've never run across a NuGet package that forces the consumer to have to make changes to their .csproj file after installation.
Thanks!
You can make all of the targets hook into the build themselves, not requiring any changes by project authors:
<Target Name="Foo" AfterTargets="AfterBuild"> …
Note that it looks like you just want to include files to the output directory, which can be done without targets as static item groups:
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)path\relativetotargetsfile\somecontent\**"
Link="\%(Filename)%(Extension)"
Visible="false"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
This will support incremental build. Change the Link metadata if you need the content to be put into subdirectories.

MSBuild is saying I need a Main method for a library compilation

I'm trying to use MSBuild to compile my ASP.NET MVC3 applicaiton. Since DLL's don't require a Main method and I have specified that the target is a Library, why is the compiler throwing the following exception:
CSC : error CS5001: Program 'c:\MvcApplication1\web\bin\MvcApplication1.dll' does not contain a static 'Main' method suitable for an entry point[C:\MvcApplication1\web\MvcApplication1.csproj]
Here's the .csproj file:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Library</OutputType>
<AssemblyName>MvcApplication1</AssemblyName>
<OutputPath>bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="*.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="..\lib\*.dll" />
</ItemGroup>
<Target Name="Build">
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<Csc References="#(Reference)" Sources="#(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).dll" />
<Copy SourceFiles="#(Reference)" DestinationFolder="$(OutputPath)" />
</Target>
</Project>
Csc should have a TargetType of library. The default is supposed to be Library (see MSDN below) although in this case it doesn't seem to be the case.
Change you <Csc step as follows:
<Csc TargetType="library" References="#(Reference)" .... />
From MSDN re TargetType:
Specifies the file format of the output file. This parameter can have
a value of library, which creates a code library, exe, which creates a
console application, module, which creates a module, or winexe, which
creates a Windows program. The default value is library. For more
information, see /target (C# Compiler Options).

C# application not recognizing satellite resource assemblies

Due to the extreme amount of .resx files in our application, I have created the following MSBuild script to compile all language .resx files into .resource, then embed them into satellite resource assemblies.
<Project DefaultTargets="Main" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Res Include = "Dialog\*.ja-JP.resx">
<Culture>ja-JP</Culture>
<Project>Dialog</Project>
</Res>
</ItemGroup>
<Target Name="Main">
<Message Text="$(destination)"/>
<CallTarget Targets="CompileResources" />
<CallTarget Targets="BuildSatelliteAssemblies" />
<CallTarget Targets="CopyToFolder" Condition="$(destination)!=''"/>
<CallTarget Targets="CleanUp" />
</Target>
<Target Name="CompileResources">
<GenerateResource Sources="#(Res)" PublicClass="true" >
<Output ItemName="Resources" TaskParameter="OutputResources"/>
</GenerateResource>
</Target>
<Target Name="BuildSatelliteAssemblies" DependsOnTargets="CompileResources">
<MakeDir Directories="%(Res.Culture)"/>
<AL OutputAssembly="%(Culture)\%(Project).resources.dll"
Version="0.0.0.0"
Culture="%(Culture)"
ProductName="%(Project)"
Title="%(Project)"
EmbedResources="#(Resources)"/>
</Target>
<Target Name="CopyToFolder" DependsOnTargets="BuildSatelliteAssemblies">
<MakeDir Directories="$(destination)\%(Res.Culture)"/>
<CreateItem Include="%(Res.Culture)\*.dll" AdditionalMetadata="Culture=%(Res.Culture)">
<Output ItemName="SatelliteAssemblies" TaskParameter="Include"/>
</CreateItem>
<Copy DestinationFolder="$(destination)\%(Culture)"
SourceFiles="#(SatelliteAssemblies)" />
</Target>
<Target Name="CleanUp">
<Delete Files="#(Resources)"/>
</Target>
</Project>
The satellite assemblies seem to compile and embed correctly however when I place them with my application, they are not recognized and it defaults back to the default culture resources. If I build the project with Visual Studio and use the assemblies it creates with that, they load fine.
I must be missing something in causing the application to recognize my externally built assemblies. They are all named the same and the sizes are nearly the same.
In the AL target, you can set an internal namespace to be used by each resource file in the assembly. Setting the correct namespace allowed the application to correctly find the resources in the assemblies.

Categories

Resources