Include referenced project's .config file - visual-studio-2010

Rather than excluding a file from the referenced output of an assembly, I want to add one!
I have a console application project (BuildTest1) that references a second class library project (ClassLibrary1). The Visual Studio solution looks like this:
I have a class library project that has an app.config. I want this .config file copied to the referring project's output, just like the .dll and .pdb files are. The config file for the class library is copied to the class library output directory as 'ClassLibrary1.dll.config'
I've tried adding this to the .exe project's .csproj file but it doesn't seem to make any difference:
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>
.pdb;
.xml;
.config
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>

I was so close... I tracked this down to the MSBuild ResolveAssemblyReference task that is called from the ResolveAssemblyReferences target in Microsoft.Common.targets. This is what populates the ReferenceCopyLocalPaths item.
So looking at the pattern of files it was matching I discovered that the file extension .dll.config (rather than just .config) did the trick:
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>
.pdb;
.xml;
.dll.config
</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>

Related

How do I configure Visual Studio 2022 to build projects on another drive?

I have a system with a 1 TB SATA-connected SSD as the system disk and a 256 GB M.2 SSD as an auxiliary data disk/scratch drive. I would like to configure Visual Studio 2022 to create all project build directories (but not the projects themselves) inside a folder on this scratch drive (F:\build). From what I can tell, CMake-based projects can achieve this by creating a global CMakeSettings.json template; however, I haven't found anything for MSBuild-based projects. Is it possible to configure the MSBuild defaults to do this?
A folder tree of what I'm trying to do would look a little like this:
F:\
|- foo
|- bar
|- build
|- Project1
|- Project2
MSBuild is not a build script generator like CMake. When you create a project file with Visual Studio or the dotnet tool, the project itself is an MSBuild script. The project file should be source controlled. It is not a 'scratch' file.
Generally, MSBuild projects use an 'intermediate' directory and an 'output' directory. By default, the intermediate directory is obj\ and the output directory is bin\. These defaults can be changed by changing the BaseIntermediateOutputPath and BaseOutputPath properties. (See List of common properties and parameters.)
You can set or change properties globally by using a Directory.Build.props file. (See Customize your build.) The Directory.Build.props file is imported very early which is important because there are numerous properties defined based on the BaseIntermediateOutputPath and BaseOutputPath properties.
You might create a Directory.Build.props file like the following:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<Acme-Drive Condition="'$(Acme-Drive)' == ''">F:</Acme-Drive>
<Acme-BuildDir Condition="'$(Acme-BuildDir)' == ''">$(Acme-Drive)\build\</Acme-BuildDir>
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(Acme-BuildDir)$(MSBuildProjectName)\bin\</BaseOutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(Acme-BuildDir)$(MSBuildProjectName)\obj\</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>
Some notes on this MSBuild code:
MSBuild will search up the directory structure and will load the first Directory.Build.props file found. The Import will search for and if present will load the next file. It's a good practice to always add the Import when creating a Directory.Build.props file (or a Directory.Build.targets file). The chain of imports will continue to work if Directory.Build.* files are added or removed in the directory tree.
Acme-Drive and Acme-BuildDir are custom properties. 'Acme-' is used as a prefix. The prefix can be anything that is appropriate for your organization or product. The prefix both provides a lower chance of a property name collision and indicates this is a custom property.
The Condition="'$(Acme-Drive)' == ''" tests if the property is unset. The value F: is only set if the Acme-Drive property doesn't already have a value. Properties can be redefined and overridden from other files and from the command line. For example, passing /p:"Acme-Drive=z:" on the MSBuild command line would switch the drive for that one run.
The value of the $(MSBuildProjectName) property is the name of the current project.
If
Your local working directory for the source code is C:\repos\MyProduct.
The code above is saved as C:\repos\MyProduct\Directory.Build.props.
You have project files:
C:\repos\MyProduct\project1\Project1.csproj
C:\repos\MyProduct\project1\Project2.csproj
then
Both projects will use the same Directory.Build.props file.
For Project1, $(BaseOutputPath) will be F:\build\project1\bin.
For Project2, $(BaseOutputPath) will be F:\build\project2\bin.

Why does Visual Studio 2019 deletes my referenced assemblies after the build?

I have a Visual Studio 2019 solution that I inherited from someone else with multiple projects.
I'm trying to build one of the projects in particular.
I have a reference to an external assembly with "copy local" set to true.
When I build my project, my referenced assembly gets copied over tot he output folder but then it gets deleted.
I know it gets copied because I have tried using the post build event "dir $(TargetDir)" and it shows the dll.
Any idea why it would get deleted afterward?
The problem was caused by by these lines in my csproj file:
<Target AfterTargets="AfterBuild;NonWinFodyTarget" Name="CleanReferenceCopyLocalPaths">
<Delete Files="#(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
The solution was using Fody to weave the assemblies.
I had removed the weaving, but this line in the csproj file was a left over from the use of Fody.
The issue is that you have used some nuget packages like Costura.Fody which could merge your specific external assembly into the main output file while it is set to Copy Local True.
So please check if your FodyWeavers.xml file has any merge operation of your external assembly.
In my side, I have an external assembly called ClassLibrary22.dll and set it to CopyLocal to true.
And add these on FodyWeavers.xml file:
So the assembly ClassLibrary22.dll will be merged into the main project exe or dll output file and did not exist under output folder.
That is the cause.

Prevent duplicating files in NuGet content and contentFiles folders

My NuGet package needs to deliver some rather large files to build output directory.
In an old NuGet model, such files have to be stored in content folder of the .nupkg. While in a new model introduced in NuGet 3.3, such files have to be stored in contentFiles folder.
To maintain a compatibility with older versions of NuGet and mainly with Package.config package management format, I need to duplicate the files into both folders. That unfortunately almost doubles a size of the package.
Is there a way to prevent that? Can I somehow link contentFiles to content folder?
Found updated documentation describing this in detail at
MSBuild targets for NuGet.
By default, everything gets added to the root of the content and contentFiles\any\<target_framework> folder within a package and preserves the relative folder structure, unless you specify a package path:
<Content Include="..\win7-x64\libuv.txt">
<Pack>true</Pack>
<PackagePath>content\myfiles\</PackagePath>
</Content>
If you want to copy all your content to only a specific root folder(s) (instead of content and contentFiles both), you can use the MSBuild property ContentTargetFolders, which defaults to "content;contentFiles" but can be set to any other folder names. Note that just specifying "contentFiles" in ContentTargetFolders puts files under contentFiles\any\<target_framework> or contentFiles\<language>\<target_framework> based on buildAction.
If you only want to output the file to the build output (content only copies the file to the output directory but does cause it to be set as copy to output directory item), you can use a completely different approach by creating an msbuild file that will be included in the project.
You can do this by putting both the file - say test.jpg into the tools folder (you could also use build) and add a Your.Package.Id.targets file to the build folder (the name being the package id of your package with .targets as extension) with the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)..\tools\test.jpg">
<Link>test.jpg</Link>
<Visible>false</Visible>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>
This target will be automatically imported into the project files regardless of which "style" of NuGet reference is used (packages.config, PackageReference) and should be backwards compatible to older versions of VS as long as they support NuGet and ToolsVersion 4.0.
The Link metadata denotes where in the output / publish directories the file will end up. You could set it to e.g. defaultContent\images\foo.jpg to create a nested structure and rename the file. (you could even use MSBulid variables to use some of the referencing project's configuration). The Visible metadata prevents the solution explorer from showing the full relative path to the file, which could end up in lots of nested .. nodes. The CopyToPublishDirectory applies to .NET Core / ASP.NET Core apps or SDK-based projects using the Publish target for publishing.
Note that you can set the Inclue-path to anything depending on where in your package the file is. You can also use wildcards (but then set Link to %(Filename)%(Extension))

Error MSB4062 when trying to use ServiceController

I use Visual Studio 2010 with TFS 2010 on a x64 machine.
I am trying to use the MSBuild Community Tasks target in my build. This target exists in source control. So in my csproj file i am import that particular target but i now get the following error:
error MSB4062: The "MSBuild.Community.Tasks.Attrib" task could not be loaded from the assembly C:\Program Files (x86)\MSBuild\MSBuildCommunityTasks\MSB
uild.Community.Tasks.dll. Could not load file or assembly 'file:///C:\Program F
iles (x86)\MSBuild\MSBuildCommunityTasks\MSBuild.Community.Tasks.dll' or one of
its dependencies. The system cannot find the file specified. Confirm that the
declaration is correct, that the assembly and all its dependencies
are available, and that the task contains a public class that implements Micros
oft.Build.Framework.ITask. [C:\SampleTest\SampleTest.csproj]
Here is my code:
<Import Project="..\..\Builds\Common\MSBuildTasks\MSBuild.Community.Tasks\MSBuild.Community.Tasks.Targets" />
<Target Name="BeforeBuild">
<PropertyGroup>
<MyService>ServiceName</MyService>
</PropertyGroup>
<ServiceController ServiceName="$(MyService)" Action="Stop" />-->
</Target>
Any thoughts on the above?
Why is MSBuild trying to look for the dll elsewhere when i have specified it in the project file?
Thanks in advance,
I think the problem comes from within the MSBuild.Community.Tasks.Targets file - it is this file that actually references the MSBuild.Community.Tasks.dll assembly.
If you open the file you can see a bunch of UsingTask elements, such as:
<UsingTask AssemblyFile="$(MSBuildCommunityTasksLib)" TaskName="MSBuild.Community.Tasks.Attrib" />
The $(MSBuildCommunityTasksLib) property is defined at the top of the file as:
<PropertyGroup>
<MSBuildCommunityTasksPath Condition="'$(MSBuildCommunityTasksPath)' == ''">$(MSBuildExtensionsPath)\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
<MSBuildCommunityTasksLib>$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll</MSBuildCommunityTasksLib>
</PropertyGroup>
So it looks like you need to set the $(MSBuildCommunityTasksPath) property before calling <Import>.

Post build event to include a file to the project

I'd like to copy a file and include the file in the web project and would like to do this as a part of the Pre/Post build events.
My understanding is that these events support DOS commands and I can use xcopy for copying a file, but I am not sure how I would update the csproj file to include the file in the project.
Do you need the file to be in the output directory or actually be part of the .csproj file ?
If you really want to update the csproj file then try customising the AfterBuild target in the csproj file of the startup project in your solution. All csproj files are msbuild files and you can use the full power or msbuild including callling any task. Right click on the project in the solution explorer, select unload project and then edit project. Then customise the AfterBuild target to change the particular csproj file you want. Use built in tasks or the excellent extension pack for changing the file. Finally reload the project.

Resources