Issues with MsBuild, SpecificVersion, and VSTS - msbuild

The scenario is as follows:
We have a set of common .net libraries:
CommonLib.Main
CommonLib.Specialized
We have a CI build that builds both of these libraries, and places them into our NuGet repo. Both are available as individual NuGet packages - a user may want to load just Main, or they can pull the Specialized package, which will include Main.
Specialized references Main as a Nuget package.
I'm currently making some upgrades to these packages.
First, I upgraded Main. I updated the version of Main in AssemblyInfo from 1.1.0. to 2.0.0.
MsBuild will include the build number in the "*" location.
The CI Build ran, and a version of Main called "CommonLib.Main, version=2.0.0.345" was published to our NuGet repo. On the Nuget repo, the version is listed as "2.0.0", as I would expect.
Next, I upgraded CommonLib.Specialized, and I updated the NuGet reference to CommonLib.Main, version=2.0.0.
I checked in these changes, and the CI build ran again.
So now, the CI build has create a new version of Main, with version 2.0.0.346, and placed it on the NuGet repo.
Here's the problem:
Now, when we run our CI build again, the build of CommonLib.Specialized fails, because in the .csproj, it looks like this:
<Reference Include="CommonLib.Main, Version=2.0.0.345, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\CommonLiib.Main-2.0.0\lib\net461\CommonLib.Main</HintPath>
</Reference>
But, in packages.config, it has
<package id="CommonLib.Main" version="2.0.0" targetFramework="net461" />
Which pulls down CommonLib.Main, Version=2.0.0.346.
Our build fails here:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\amd64\Microsoft.Common.CurrentVersion.targets(1964,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "CommonLib.Main, Version=2.0.0.345, Culture=neutral, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
For SearchPath "{HintPathFromItem}".
Considered "..\packages\CommonLib.Main-2.0.0\lib\net461\CommonLib.Main.dll",
but its name "CommonLib.Main, Version=2.0.0.**346**, Culture=neutral, PublicKeyToken=null"
didn't match the expected name "CommonLib.Main, Version=2.0.0.**345**, Culture=neutral, processorArchitecture=MSIL".
I think I could fix this by setting SpecificVersion to false in the project, but that seems rather crude. Is there a better way to resolve this issue? I feel like I shouldn't have to refresh the NuGet references after every build.

Related

Nuget dependencies loading except for ConfigCat in GitHub Actions

For some reason GitHub Actions is not pulling in one Nuget package ConfigCat.Client but works fine for the remaining 20 packages. This is one solution with many projects. It works fine in VS Build as well as local msbuild command. I have another simple solution in GitHub Actions that works fine as well. I'm using a win-2019 server runner with .NET SDK 5.0. I get:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "ConfigCat.Client, Version=6.5.2.0, Culture=neutral, PublicKeyToken=d28b16a067d7bbe2, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
I'm running this (restore & build):
msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
msbuild $env:Solution_Path /p:Platform="Any CPU" /p:Configuration=Release /p:UapAppxPackageBuildMode=SideloadOnly /p:AppxBundle=Always /p:PackageCertificateKeyFile=$certificatePath /p:PackageCertificatePassword=${{ secrets.Pfx_Key }}
Errors from log file (could it be related to processorArchitecture=MSIL?)
2022-08-28T03:05:23.6891561Z Primary reference "ConfigCat.Client, Version=6.5.1.0, Culture=neutral, PublicKeyToken=d28b16a067d7bbe2, processorArchitecture=MSIL".
2022-08-28T03:05:23.6894672Z C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "ConfigCat.Client, Version=6.5.1.0, Culture=neutral, PublicKeyToken=d28b16a067d7bbe2, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. [D:\a\DataProduction\DataProduction\BigLebowski\Services\FeatureFlagService\FeatureFlagService.csproj]
2022-08-28T03:05:23.6896617Z For SearchPath "{HintPathFromItem}".
2022-08-28T03:05:23.6897448Z Considered "D:\a\DataProduction\DataProduction\BigLebowski\packages\ConfigCat.Client.6.5.1\lib\net45\ConfigCat.Client.dll", but it didn't exist.
I've also tried changing the Platform to x64 with the same results.
Any insight or pointers is greatly appreciated.
Thanks to Péter Csajtai for solving the problem. The project was using packages.config and not restoring the nuget package as a result. Adding the parameter /p:RestorePackagesConfig=true to the restore resolved the issue. See also this question.

msbuild refuses to copy unsigned dll if it is of lower version than demanded by one of the project dependencies - is it by design?

I have the following situation:
All the involved dlls are unsigned
All the projects in the solution depend on version 1.0.21221.1 of Shared.dll
Some NuGet dependencies of some projects in the solution depend on version 1.0.21237.1 of the same dll.
When the web application is built (let us name it Api) it is expected to copy Shared.dll from $(OutDir) to the $(OutDir)_PublishedWebsites\Api\bin folder. The Shared.dll found in $(OutDir) has the version 1.0.21221.1.
The Shared.dll is NOT copied and the web application fails to run.
Here is the evidence from the binary log:
Exhibit A - The conflict of versions:
Exhibit B - ResolveAssemblyReference instructs NOT to copy Shared.dll:
I understand that msbuild does not like the idea of conflicting versions, but NOT copying the dll produces a downright bug, because the application fails to start.
I understand one can resolve it by adding an assembly binding redirect. But I thought it was unnecessary for unsigned assemblies. Am I understanding wrong or am I missing something?
EDIT 1
Here are my answers to the questions posted in the comments:
(Unfortunately I was asked to obfuscate some keywords, I do not know why)
How exactly does the Api project reference Shared.dll?
As we can see in the exhibit B Shared.dll is a transitive dependency of Api. Indeed, Api depends on Xyz.BusinessApi like this:
<Reference Include="Xyz.BusinessAPI" />
Now that DLL depends on Shared.dll through the respective NuGet dependency, here is a snippet from the project.assets.json file of Xyz.BusinessAPI:
What other projects reference Shared.dll and how?
There are a lot of projects referencing it as a NuGet package at version 1.0.21221.1. The problem is that some projects also reference two other NuGet packages which in turn depend on the version 1.0.21237.1 of the same NuGet package. This is indicated in the RAR output - see the exhibit A.
I would like to emphasize - no project references Shared.dll as a raw dll, only either as NuGet package or indirectly through other NuGets or projects or project dlls. Project dll is a dll of a project from a previously built solution - we do not allow project references to other solutions, so if a project is built in a previous solution, then it would be referenced as DLL in subsequent solutions.
What is the mechanism used to copy from OutDir to _PublishedWebsites\api\bin?
This is the standard web application publishing target _CopyFilesMarkedCopyLocal from C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\WebApplications\Microsoft.WebApplication.targets:
<!-- copy any referenced assemblies to _PublishedWebsites\app\bin folder -->
<Copy SourceFiles="#(ReferenceCopyLocalPaths)"
DestinationFiles="#(ReferenceCopyLocalPaths->'$(WebProjectOutputDir)\bin\%(DestinationSubDirectory)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"/>
How does Shared.dll end up in OutDir?
All of our code is built into the shared bin directory - we set OutDir to the same value for all the projects. Thus all the project binaries and their dependencies, including Shared.dll first end up there.
Are there any double-writes in the binlog?
Yes, but I do not think they are relevant:
The short answer is that your projects indirectly depend on two versions of Shared.dll: 1.0.21221.1 and 1.0.21237.1.
RAR (the MSBuild ResolveAssemblyReference task) inspected all the references of all .dlls and found these two versions. It reported a conflict:
Pay attention how it reported the found file path in square brackets for Shared.dll 21221 and reported [] (meaning no file of such version was found) for 21237.
It's useful to search for these using There was a conflict under($rar) or $warning under($rar).
Now, the OutDir only contains the Shared.dll 21221, so the Shared.dll with version 21237 couldn't be found anywhere.
The trick is to search for Shared.dll under($rar project(api.csproj)) You will find the relevant messages from RAR:
Considered "C:\Xyz\61\bin.link\Shared.dll",
but its name "Shared, Version=1.0.21221.1, Culture=neutral, PublicKeyToken=null"
didn't match the expected name "Shared, Version=1.0.21237.1, Culture=neutral, PublicKeyToken=null".
So, it saw a conflict, decided to unify on a later version (21237), but didn't find the file of that version. So the reference of 21221 was not CopyLocal because it didn't unify on that version, and the reference to 21237 was not resolved because a file of that version was not found.
To resolve this, I recommend adding an explicit reference to Shared.dll of the version 21237 (either via NuGet or via GeneratePathProperty metadata on the package reference: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#generatepathproperty). If you use GeneratePathProperty you can then reference the .dll directly using $(PkgFoo_Bar)\lib\net472\Shared.dll or similar. Also add a binding redirect from 21221 to 21237 to resolve the conflict. Once the correct version (21237) will be in your OutDir, it will get copied to output correctly.
Hope this clarifies.

VS2017 Found Conflicts between different versions of "System.Runtime" that could not be resolved

I had a Visual Studio 2015 solution with 3 projects and then started using VS 2017 adding 2 new xunit projects. When I build everything succeeds but the tests are being discovered in Test Explorer.
I reviewed this question Found conflicts between different versions of the same dependent assembly that could not be resolved and set my Build output to Diagnostic and I am getting a warning saying:
1> C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(2052,5): warning MSB3277: Found conflicts between different versions of "System.Runtime" that could not be resolved. These reference conflicts are listed in the build log when log verbosity is set to detailed.
i have updated the 3 .csproj files from
Project ToolsVersion="14.0"to
Project ToolsVersion="15.0"
added <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> to the 2 VS2017 projects which did not have it
set Test -> Test Settings -> Default Processor Architecture to x64 and my Build -> Configuration Manager -> Platform to x64 or Any CPU (some projects do not allow x64?)
I have reinstall nuget packages across the solutions with Update-Package -reinstall
updated and repaired VS2017
I can see my tests on solution load but once I build the solution the tests are grayed out. Then I tried to run one and they say
4/4/2018 4:34:25 PM Warning] Test run will use DLL(s) built for framework Framework45 and platform X86. Following DLL(s) will not be part of run:
DatabaseRestoreManager.exe, RestoreBaseLib.IntegrationTests.dll, RestoreBaseLib.Tests.dll, RestoreBaseLib.dll, Restores.exe are built for Framework Framework45 and Platform X64.
Go to http://go.microsoft.com/fwlink/?LinkID=236877&clcid=0x409 for more details on managing these settings.
[4/4/2018 4:34:26 PM Warning] [xUnit.net 00:00:00.1993869] Exception discovering tests from RestoreBaseLib.IntegrationTests: System.BadImageFormatException: Could not load file or assembly 'RestoreBaseLib.IntegrationTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.
File name: 'RestoreBaseLib.IntegrationTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
Most people with this issue seem to have the problem in a nuget package but my issue seem to be a msbuild or VS15 to VS17 upgrade with testing and System.Runtime.
Is there anything that can fix this? I want to be able to run xunit tests in VS17.

.net core msbuild nuget with additional assemblies

This sample shows a .NET Core project which can be packaged into a nuget package just using dotnet pack, and when restored in another project, it integrates in the msbuild pipeline. One of the great things about this sample is it creates a nuget package that integrates with msbuild on linux, mac and Windows. However, the custom build code doesn't have dependencies on any other assemblies.
How can I adapt this sample to use code that uses a dependency?
Here are my failed attempts:
Attempt 1
I added a package reference to Newtonsoft.Json and changed the code to do some JSON serialisation. However, in the project that uses the build nuget, when I do a dotnet publish, I get the following error:
error MSB4018: The "Zip" task failed unexpectedly. [C:\git\MSBuild-Features-With-Nate-McMaster\Video-2\1-NuGet\Web.csproj]
error MSB4018: System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified. [C:\git\MSBuild-Features-With-Nate-McMaster\Video-2\1-NuGet\Web.csproj]
Additionally, if my project didn't already have a dependency on JSON.NET, adding the build nuget would unnecessarily add it.
Attempt 2
I used nuget.exe spec to create a .nuspec file. At the end of the file, I added:
<files>
<file src="bin\Release\**" target="build" />
<file src="build\**" target="build" />
</files>
However, both "dotnet pack" and "msbuild /t:pack" ignore the file, and nuget.exe pack fails with the error Unable to find 'bin\Release\0-WriteATask\bin\Release\'. Make sure the project has been built..
If I try nuget.exe pack Zipper.nuspec or msbuild /t:pack /p:NuspecFiles=Zipper.nuspec, they both fail with the message Value cannot be null or an empty string..
Attempt 3
I edited the nuspec to remove all of the placeholders that are normally calculated from the project (any string starting and ending with a $). Then, doing a nuget.exe pack Zipper.nuspec created a nupkg file, and the net46 folder contains Newtsonsoft.Json.dll, but the netstandard1.3 folder does not.
The way MSBuild loads a task assembly can make it tricky to load additional assemblies that you may depend on.
Typically, the easiest way to solve this is to ship a copy of your dependencies inside your NuGet package. But your dependencies alongside your task assembly file in the package. There may be some additional complications that require you to use AssemblyLoadContext or the AppDomain.AssemblyResolve event.
You can do this without a nuspec file by forcing MSBuild to copy your assemblies into the local build output, and then copying them into your package. Set CopyLocalLockFileAssemblies=true, and add the items to _PackageFiles
Here's an example of how to do that: https://github.com/madskristensen/BundlerMinifier/blob/3333b5c38289a247391966443370ee6f4a29bf26/src/BundlerMinifier/BundlerMinifier.csproj#L35-L47
Hopefully, this will be addressed in the future, https://github.com/Microsoft/msbuild/issues/1312, and the task assembly resolution will use the NuGet cache.
Try it with the 9.0.1 version of Newtonsoft.Json, it worked for me, all these dll load problems went away, and it still targets .NET Standard. Although I did copy all the dependencies next to the task dll, but with the 10.x version even that didn't help.

TeamCity - MSBuild unable to locate NuGet references

Attempting to build a C# project which has numerous references to assemblies in NuGet packages fails in TeamCity but works fine in Visual Studio.
Found in the log;
For SearchPath "{HintPathFromItem}".
[13:48:15][ResolveAssemblyReference]
Considered "..\packages\AspNetMvc.4.0.20126.16343\lib\net40\System.Web.Mvc.dll", but it didn't exist.
The reference in the project file is;
<Reference Include="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\AspNetMvc.4.0.20126.16343\lib\net40\System.Web.Mvc.dll</HintPath>
</Reference>
Any ideas? It seems like it's not starting from the correct directory so can't resolve "../packages" which exists one level above the .csproj file.
I know this has been answered, but maybe someone else has had the same problem I did.
My hint paths in my project file were incorrectly pointing to packages and changing it to ..packages fixed it for me.
So changing it from this:
<Reference Include="Newtonsoft.Json">
<HintPath>packages\Newtonsoft.Json.5.0.5\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
To this:
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.5.0.5\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
Fixed it.
I had restructured my projects since installing the NuGet packages so even though '../packages' was correct for the main project, it wasn't for the other projects which had been moved.
Uninstalling and re-installing the NuGet packages writes the paths correctly or more straightforward, doing a find and replace on the paths in each .csproj file.
My understanding at this point is based on the information here: http://youtrack.jetbrains.com/issue/TW-20525
But I am just diving into both TeamCity and NuGet at the same time (coming from CruiseControl.NET)
So what I did for the time being is to add a "NuGet Installer" build step before my vs.net solution build step and everything worked great.
You either need to add the packages directory to source control or enable nuget to automatically download packages (its a feature in the right click menu of nuget 1.6)
See http://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages
Sorry for resurrecting this old post, but in addition to the above excellent points (Tjaart, SeeNoWeevil, Luke), you might also want to check the property CopyLocal=true for the references that you nuget'ed down.
For myself, this has often been the one tiny oversight that leads to exactly the error that the OP was mentioning.
You can highlight the file in Solution Explorer and got to Properties, and verify that Copy to Output Directory is set to True
Ensure that the .dll and .pdb files are included in source control (or have been downloaded).
For TFS (not TeamCity), by default, .pdb files and .dll files are excluded. So double-check that all files for each package sub-directory have been included, not just the nuget .xml file.
Background: I came to this question with the same thought as some other posters - that the relative reference in the .csproj file might be incorrect. After using a path in the .csproj file to ensure that the reference was absolute with regards to the project...
<HintPath>$(MSBuildProjectDirectory)\..\.nuget\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll</HintPath>
..only to get the same error, I double-checked that the required files existed. I also did an MSBuild build on my local machine (as opposed to Visual Studio build), and it worked. Further investigation on the build server revealed that the specified files did not exist, even though the directory, and .nuget package .xml files did.