How do I include .deps and .runtimeconfig files as project dependencies? - c#

Visual Studio creates two files along with the .exe for my project that are required to run the exe: a deps.json and a runtimeconfig.json. A second project in my solution has the first project as a project reference, but those two files aren't being copied to my second project's output directory. How can I tell Visual Studio that it should copy these files into the output directory of the second project, because the referenced project depends on them?
Output directory of my first project:
Foo.exe
Foo.deps.json
Foo.runtimeconfig.json
Output directory of my second project:
Bar.exe
Foo.exe
Should contain deps and runtimeconfig files, but does not

The solution I found is to manually edit my .csproj file to add the following target:
<Target Name="AddRuntimeDependenciesToContent"
Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'"
BeforeTargets="GetCopyToOutputDirectoryItems"
DependsOnTargets="GenerateBuildDependencyFile;
GenerateBuildRuntimeConfigurationFiles">
<ItemGroup>
<ContentWithTargetPath Include="$(ProjectDepsFilePath)"
Condition="'$(GenerateDependencyFile)' == 'true'"
CopyToOutputDirectory="PreserveNewest"
TargetPath="$(ProjectDepsFileName)" />
<ContentWithTargetPath Include="$(ProjectRuntimeConfigFilePath)"
Condition="'$(GenerateRuntimeConfigurationFiles)' == 'true'"
CopyToOutputDirectory="PreserveNewest"
TargetPath="$(ProjectRuntimeConfigFileName)" />
</ItemGroup>
</Target>
This solution came from https://github.com/dotnet/sdk/issues/1675#issuecomment-658779827.
There were other somewhat similar solutions posted in that thread, but this is the only one that worked for me. The others would either not consistently copy the files to my second project, or cause the first project to fail to build due to attempting to access a file that didn't yet exist. The key difference with this one is the inclusion of the correct "BeforeTargets" property (and possibly also "DependsOnTargets"), controlling at which point in the build process the files are included.

Related

msbuild cannot copy manifest because it was not found

We have a c# framework (not .core) solution with several projects in it. It is build by TFS. Sometimes (not all the times) I got a build error:
error MSB3030: Could not copy the file
"c:\BuildAgent_work\27\b\Console.Admin\Product.Admin.exe.manifest"
because it was not found.
[c:\BuildAgent_work\27\s\Console.Admin\Console.Admin.csproj]
The app.manifest file is added to the project Properties folder, and I checked it exists on buildagent source folder. I checked it is not exists on the binaries folder. I don't know why it is not copied there during the build.
In fact I don't know if I need this manifest thing at all. I think I don't. This whole thing was added to the project by one of my collegaue for a reason is unknown for me. Is it required to create publish package for web projects? In this case why it is required for a console project? For what reason is it added?
The msbuild parameters (for building the solution) are the following, and the [x] Clean option is checked in the TFS build solution step.
/p:OutDir=$(Build.BinariesDirectory)
/p:GenerateProjectSpecificOutputFolder=true
/p:DeployOnBuild=true /
p:PackageAsSingleFile=true
/p:GenerateDocumentation=true
/p:DisableAllVSGeneratedMSDeployParameter=true
/t:Clean,Build,Publish
/p:RunCodeAnalysis=$(CodeAnalysis.Run);CodeAnalysisRuleSet=$(CodeAnalysis.RuleSet).ruleset;CodeAnalysisIgnoreGeneratedCode=true
/p:IncludeAppPool=true
/p:PrecompileBeforePublish=true;EnableUpdateable=false
An application manifest is an XML file that describes and identifies the shared and private side-by-side assemblies that an application should bind to at run time. These should be the same assembly versions that were used to test the application. Application manifests may also describe metadata for files that are private to the application. You can refer to this document.
So, you first need to check in csproj for any additional operations on the manifest. When the MSBuild creates the publish files it copies files base on the build definition , you can try to edit the .csproj file as bellow which copied the relevant files. app.manifest is your file path .
<ItemGroup>
<None Update="app.manifest">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

How to have a Project Reference without referencing the actual binary

Following works fine but it does not copy the .pdb file for Asp.net Core 2.0 project.
<ProjectReference Include="..\ProjectA\ProjectA.csproj">
<Project>{b402782f-de0a-41fa-b364-60612a786fb2}</Project>
<Name>ProjectA</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Targets>Build;DebugSymbolsProjectOutputGroup</Targets>
</ProjectReference>
https://blogs.msdn.microsoft.com/kirillosenkov/2015/04/04/how-to-have-a-project-reference-without-referencing-the-actual-binary
So, what should we do for copying the pdb file?
So, what should we do for copying the pdb file?
Just as Marc and that bolg pointed out this method not work in the Visual Studio to copy the .pdb file. Because we set <ReferenceOutputAssembly>false</ReferenceOutputAssembly>, the project reference without referencing the actual binary, VS/MSBuild will not copy the .pdb file.
many people have asked how to also copy the .pdb file in addition to
the .exe/.dll. Turns out there is a trick, but it doesn’t work when
building in VS. But it’s OK since you don’t really need the .pdb in VS
anyway, since the debugger will find the .pdb at its original path
anyway.
If you still want to copy this .pdb file, you can use MSBuild copy task or a build event for your project:
MSBuild copy task:
To accomplish this, unload your project. Then at the very end of the project, just before the end-tag , place below scripts:
<Target Name="CopyPDBfile" AfterTargets="Build">
<Copy SourceFiles="$(SolutionDir)ProjectA\bin\Debug\ProjectA.pdb" DestinationFolder="$(TargetDir)" />
</Target>
Build event:
Add following build command line in the Pre-build/Post-build event:
xcopy /y "$(SolutionDir)ProjectA\bin\Debug\ProjectA.pdb" "$(TargetDir)"
Note: Do not ignore double quotes and spaces in the build command line.
Hope this helps.

VS 2015 project not rebuilt when I delete a file

I have a config file in my C# project that is excluded from source control (it's local to each developer). However, if the file doesn't exist I want it to be copied from the corresponding ".template" file (which is in source control). To do this, I added an MSBuild item type and target, like this:
<ItemGroup>
<AvailableItemName Include="LocalConfigTemplate" />
</ItemGroup>
<Target Name="CopyFromTemplateIfNeeded" BeforeTargets="BeforeBuild" Inputs="#(LocalConfigTemplate)" Outputs="#(LocalConfigTemplate->'%(FileName)')">
<Copy Condition="!Exists(%(LocalConfigTemplate.Filename))" SourceFiles="#(LocalConfigTemplate)" DestinationFiles="#(LocalConfigTemplate->'%(FileName)')" />
</Target>
(Based on How to hide files generated by custom tool in Visual Studio) This is in a separate file, included from the project file (before Microsoft.CSharp.targets, if that matters).
It works, but when I delete the target file (local.config) and build the project VS thinks it's "up to date" and does not build. How do I get it to detect that the output file is missing and build in that case?
Try doing a Clean before the rebuild, maybe Visual Studio is picking the file up from the bin directory.

How to build all projects in one single folder?

Is there a way to build solution into a single folder? I have several projects in this solution and each access a config file that should be in the current directory. I just move each project's build files into one and it still works, however, it looks so unorganized and messy. I just want to know it there are other ways on how to do it.
You can set output directory in the settings of every project in solution (if we are about Visual Studio). Menu: Project -> properties -> Build -> Output path. For example, I use ..\Build\ to build projects into Build directory of solution root.
This MSDN article explains how to do it in a nice, DRY way:
https://blogs.msdn.microsoft.com/kirillosenkov/2015/04/04/using-a-common-intermediate-and-output-directory-for-your-solution/
It allows you to specify those directories only once, and use those settings in multiple projects.
Steps:
Create a single common.props file in solution, that will specify and overwrite output and intermediate paths for a project to a common directory (like "Solution/bin").
Here is a sample *.props file that I found linked in the article:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
<Configuration Condition="$(Configuration) == ''">Debug</Configuration>
<OutputPath>$(SolutionDir)\bin\$(Configuration)\</OutputPath>
<OutDir>$(OutputPath)</OutDir>
<OutDir>$(OutputPath)</OutDir>
<IntermediateOutputPath>
$(SolutionDir)\obj\$(Configuration)\$(MSBuildProjectName)\
</IntermediateOutputPath>
<UseCommonOutputDirectory>False</UseCommonOutputDirectory>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
</Project>
Include this file into every *.csproj that you want to set the common output dirs for, by adding this line (the actual path may differ): <Import Project="..\Common.props" />
You can change projects "Output path", by default it's bin directory of given project.
Right click on each project, select Properties from context menu, then select Build tab.
Ont the bottom in Output section change Output path:. Set same path for each project.
I agree with comments under your question, you should not change it. Instead you may create post build action (PS script) that will copy all files from project's bin directories to one designated by you.
Update:
Set this script as Post Build command (Project's properties->Build Events tab->Post build event command line):
xcopy "$(TargetDir)*" "$(SolutionDir)Build" /s /i /Y
For each project:
Go into the project properties, in the "Build" tab.
Choose "All configurations", "all platforms", just in-case.
In the output folder write "..\bin\" (or any path which is uniform for all of them - not in the current project directory). Alternatively, to organize DLLs in sub-folders you can write "..\bin\Sub-project-directory" in the output path. Then you should add an App.config file for the EXE project with a probing to all DLLs so they can be found and loaded on runtime.
Note that if we're talking about building multiple executables into the same output directory, you can also add them as project references to the main (startup) project. They will be automatically copied to the main project output directory everytime you build it.
(note: this applies to .NET Core projects in VS 2017 or VS 2019. I'm not sure if it would work for .NET Framework projects)

ensuring c# project dependencies are copied to output directory in Visual Studio and TFS

I am working on a project which has many dependencies which are developed on a separate team from me. We use TFS 2010. Many of my applications depend on libraries and xml files which are under active development, so I want to keep them up to date. I also don't want to create separate copies of the dll's and xml files for each application/project, but rather source them from their respective locations within the same source control repository. This should be possible using a relative path.
I tried putting the following in my .csproj file
<ItemGroup>
<Dependencies Include="..\..\Driver\Driver.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Dependencies>
</ItemGroup>
this doesn't work, either on my workstation or on the build server, however, the files show up as dependencies in the Solution Explorer, and it allows me to change the copy to output property and shows the full path the to files, which is valid.
Another thing I tried was just running xcopy as a pre-build event, which works on my local machine but does NOT copy the files to the output/TFS drop folder, so it isn't picking it up as a dependency.
Try using the Private Element instead, set to True.
<ItemGroup>
<Dependencies Include="..\..\Driver\Driver.dll">
<Private>True</Private>
</Dependencies>
</ItemGroup>
See http://msdn.microsoft.com/en-us/library/bb629388.aspx

Categories