I have a solution with two nuproj projects, say A and B.
Both projects contain only props and targets files (so NO assemblies or PDB files) and they both generate NuGet packages.
Now, A has no reference and it is an internal dependency, whereas B references A plus other external NuGets.
Then I have an MSTest project that dynamically invokes MSBuild on a project which references B.
All works fine in Visual Studio and the tests pass. However, NCrunch compiles with warnings for the project B.
WARNING - ........\program files (x86)\microsoft visual studio\2017\professional\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets (2110, 5): MSB3246: Resolved file has a bad image, no metadata, or is otherwise inaccessible. Could not load file or assembly 'A.nupckg' or one of its dependencies. An attempt was made to load a program with an incorrect format.
Infact, no NuGet package is generated for the A project in the NCrunch solution directory (the package is correctly generated in Visual Studio).
I have also tried to set the following properties for the A and B projects:
Instrument assembly = false
Prevent signing of output assembly = false
Implicit project dependencies = true
nothing changes and the warning is still there and no NuGet is generated for the A project (all the source files and dependent assemblies are in the NCrunch solution folder).
And Copy referenced assemblies to workspace is set to true.
Is there any known issue with using NCrunch with .nuproj?
Related
How can I <Import> a .targets file that is included in <PackageReference>d NuGet package in a non-SDK-style web application project that targets .NET 4.7.2?
Background
The web application project is not an SDK-style project. It references a class library project in the same solution. This class library project is an SDK-style project. It has a package reference to Microsoft.Data.SqlClient version 4.1.0, which depends on Microsoft.Data.SqlClient.SNI.runtime 4.0.0. The latter contains native binaries which are automatically copied to the bin directory of the project.
The native binaries are not copied to the bin directory of the web application project. This is probably because of this:
SNI is the native C++ library that SqlClient depends on for various network operations when running on Windows. In .NET Framework applications that are built with the MSBuild Project SDK, native DLLs aren't managed with restore commands. So a ".targets" file is included in the "Microsoft.Data.SqlClient.SNI" NuGet package that defines the necessary "Copy" operations.
The included ".targets" file is auto-referenced when a direct dependency is made to the "Microsoft.Data.SqlClient" library. In scenarios where a transitive (indirect) reference is made, this ".targets" file should be manually referenced to ensure "Copy" operations can execute when necessary.
Recommended Solution: Make sure the ".targets" file is referenced in the application's ".csproj" file to ensure "Copy" operations are executed.
Source
Not sure what "built with the MSBuild Project SDK" means exactly, but I think my scenario qualifies.
Now I'm trying to implement the recommended solution, but I cannot get it to work.
What I did
Step 1: add package reference to Microsoft.Data.SqlClient.SNI version 4.0.0:
<PackageReference Include="Microsoft.Data.SqlClient.SNI">
<GeneratePathProperty>true</GeneratePathProperty>
<Version>4.0.0</Version>
</PackageReference>
I added <GeneratePathProperty> because of step 2 below. According to the documentation this should make a property available that can be used to refer to files in the package:
Sometimes it is desirable to reference files in a package from an MSBuild target. In packages.config based projects, the packages are installed in a folder relative to the project file. However in PackageReference, the packages are consumed from the global-packages folder, which can vary from machine to machine.
To bridge that gap, NuGet introduced a property that points to the location from which the package will be consumed.
Step 2: import the targets file:
<Import Project="$(PkgMicrosoft_Data_SqlClient_SNI)\build\net46\Microsoft.Data.SqlClient.SNI.targets" Condition="Exists('$(PkgMicrosoft_Data_SqlClient_SNI)\build\net46\Microsoft.Data.SqlClient.SNI.targets')" />
You can see that the package contains this targets file using the NuGet package explorer (link). The PkgMicrosoft_Data_SqlClient_SNI property is named according to the documentation (linked above) and based on their example:
MSBuild properties and package identities do not have the same restrictions so the package identity needs to be changed to an MSBuild friendly name, prefixed by the word Pkg.
Step 3: verify the tool versions on our agent:
MSBuild 16.11.2.50704 (installed on the agent C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin)
NuGet 6.1.0.106 (installed via a pipeline task)
According to the documentation linked above, these fulfil the minimum requirements (MSBuild 16 and NuGet 5).
Step 4: run nuget restore on our build agent and then build the project using the Azure DevOps MSBuild#1 task with msbuildArguments: '/t:Build'.
Step 4: collect output and publish as an artifact.
Outcome:
The SNI files are not present in the output. When building locally with MSBuild 17.0.0.52104 (installed in 'C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\bin') I do see the SNI files.
I have a Visual Studio solution with a number of projects, two of which are configured as Web Applications.
Project A is used as a class library, but it includes TypeScript files. In order to get the .ts files compiling into .js files, the .csproj file was updated so that it imports Microsoft.WebApplication.targets as well as Microsoft.TypeScript.targets. (The generated .js files are configured as 'Embedded Resources').
Project B is a regular Web Application and references Project A.
Compiling with msbuild /p:DeployOnBuild=true causes the Web Publishing Pipeline to be invoked on both projects (packaging up the contents).
Is there a way to prevent (or minimise) WPP running on Project A?
Is it possible in MSBuild 4.0 and/or 4.5 to specify additional files to be treated as a manifest output of a project by its dependencies, and copied with the binary project output, whenever that is copied? Ideally, I want to create some files beside a .dll during build, and would like these files to stay in the same folder as the .dll whenever it is copied to a directory of a project depending on it.
If this is not clear, I am thinking of .pdb and documentation .xml files created by the C# compiler. These files treated specially: Whenever another project requests the .dll be copied locally into its binary directory, these files go with the .dll. Can I augment this set with my own special files?
This is not possible, and here is why. Actually, there is no concept of project output accessible externally between MSBuild projects. Rather, when a reference to a project is added, the SDK-provided build framework (based on MSBuild scripts) looks for a few specific files matching the name of the referenced DLL, and copies these files with the DLL itself into the current project output directory (assuming CopyLocal is set, which is probably true for a referenced project).
In framework v4.0, this is done by the task ResolveAssemblyReference which is called from an identically named target from the file %windir%\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets. The task looks for specially named files placed beside the target DLL, including its matchin PDB files and an XML documentation file. Other files are also discovered, as I infer from the decompiled source.
So nothing in a given project specifically marks these files as somehow "exported" from the project. The magic happens on the pulling side.
Project A references Projects B. Project B references Project C. Project A does not reference Project C.
This builds fine locally. However, on the build server it errors out because Project A does not reference Project C.
Error:
error BC30009: Reference required to assembly 'ProjectC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' containing the implemented interface 'ProjectC.IFoo'. Add one to your project.
How can I catch this before committing?
Edit:
Here's more info on my issue: http://sstjean.blogspot.com/2006/11/msbuild-cant-find-secondary-references.html
Here are two things you can do as a best practice to ensure your projects are referenced correctly and MSBuild will be able to find your referenced projects correctly.
Use project references instead of referencing dll's. Create a folder called dependencies or libs and place any referenced dll's within this folder.
Check the build order and project dependencies tab for each project by right clicking project and selecting project build order. Ensure that every reference in your project is being built by that project.
MSBuild does not know what a .sln file is. MSBuild reads and parses the .sln file to determine the build order of projects. By having project references MSBuild will be able to traverse and build the projects in the correct order. See below link for more information.
This link also helps explain why you would see different behavior and how to catch it.
Visual Studio Integration (MSBuild)
Within Visual Studio, the solution file and project build ordering are controlled by Visual Studio itself. When building a solution with msbuild.exe on the command line, MSBuild parses the solution file and orders the project builds. In both cases the projects are built individually in dependency order, and project to project references are not traversed. In contrast, when individual projects are built with msbuild.exe, project to project references are traversed.
When building inside Visual Studio, the property $(BuildingInsideVisualStudio) is set to true. This can be used in your project or .targets files to cause the build to behave differently.
Go to your project references and right click Oracle.DataAccess then go to properties and in properties page make sure that specific version is false and copy to local is set to true.
I'm not able to build solution incrementally. I checked diagnostic log and I found that every project containing workflows are always rebuild because of this:
Input file ".NETFramework,Version=v3.5" does not exist.
Workflows are always recompiled, new temporary files are created and project is build again.
Building target "WorkflowCompilation" completely.
Input file ".NETFramework,Version=v3.5" does not exist.
Using "CompileWorkflowTask" task from assembly "System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35".
Task "CompileWorkflowTask"
No files found with '.xoml' extension in the set of input files.
Generated temporary code file: C:\Users\Ludwo\AppData\Local\Temp\uwdnm5th.cs
Workflow markup validations completed with 0 errors and 0 warnings.
Done executing task "CompileWorkflowTask".
Done building target "WorkflowCompilation" in project "Delta.Workflow.Common.Merged.csproj".
Target "CoreCompile" in file "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.targets" from project "h:\Prj\R4x\M\CountrySystems\Delta\Common\Delta.Workflow.Common\Delta.Workflow.Common.Merged.csproj" (target "Compile" depends on it):
Building target "CoreCompile" completely.
Input file "C:\Users\Ludwo\AppData\Local\Temp\uwdnm5th.cs" is newer than output file "obj\Debug\Delta.Workflow.Common.pdb".
I'm building my projects using MSBuild 4.0. My projects are set to build with v3.5 TargetFrameworkVersion, unit tests projects are build with TargetFrameworkVersion set to v4.0. I tried to build it on different PC but the result is still the same. I also played with references in my projects. It seems to be like v4.0/v3.5 conflict, but I don't know how to fix it. Any ideas?
I found it. The root cause is wrong version of Workflow.targets file imported inside my workflow (.csproj) projects. Workflow.targets for .NET v4.0 was imported instead of v3.5. It should be related to projects upgrade from VS2008 to VS2010 I did some time ago.
I changed Workflow.targets Import from
<Import Project="$(MSBuildToolsPath)\Workflow.targets"/>
to
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.5\Workflow.targets" />
Hope it helps someone...