NuGet Versioning with ProjectReference Dependencies - c#

I have a solution containing several projects. Let's say PackageA and PackageB, where PackageB depends on PackageA with a ProjectReference.
Each project is set to also output a NuGet package on build. This process itself works perfectly but I am unable to specify a package version-range for individual builds.
E.g. I'd like to restrict PackageB to only refer to PackageA version 1.0.* (patch steps).
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup
<TargetFrameworks>netstandard2.0;netcoreapp2.0;net46</TargetFrameworks>
<RootNamespace>PackageB</RootNamespace>
<Company>MyCompany</Company>
<Authors>John Doe</Authors>
<Description>This package depends on a specific version of PackageA.</Description>
<Version>1.1.0</Version>
<Copyright>Copyright © 2018 John Doe</Copyright>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PackageA\PackageA.csproj" />
</ItemGroup>
</Project>
MSBuild seems to ignore any Version="1.0.*" or AllowVersion="1.0.*" arguments within the ProjectReference tag.
Is there a possibility to specify a version range without breaking the ProjectReference or using PackageReference?

Short Answer
No, there is no way to limit a project reference by a version attribute of that project.
Longer Answer
If you want your dependent package to vary independently from its dependency and limit the range of changes it will depend upon, you are very much in need of using a package reference rather than a project reference (yes, even if those projects are in the same solution).
Project Reference Now
When you reference a project, you're making a declaration to your IDE that you want to include the referenced projects design time state in your dependent projects design time state so that you can use it and see changes to it in your IDE before it's built. When your dependent project is built, its dependency is built too. So, A project reference is always a latest-version reference. You cannot reference a previous version of a project, but you can reference the versioned result of a project that was built previously.
Packing a Project Reference
In line with project references being built when the dependent project is built, when you pack a project with a dependency upon another project using a project reference, dotnet pack and nuget pack assume that you're going to also be packing each of those projects as packages as well, and writes the project reference as a package dependency at the same version of the dependent project package. So, if you pack projB # v1.2.3 the package will have a dependency reference to projA # v1.2.3. If you don't pack projA # v1.2.3 or you don't publish that package (because maybe there weren't any changes to it), consumers of projB # v1.2.3 will fail the install because nuget won't find projA # v1.2.3. If you're going to insist on using project references for packages, those referenced projects should also be packages that are versioned with their host (whether they change or not).
A minor exception to the above reference rule
The exception to project references listed as package dependencies of the same version as the host is a project reference that has its assets marked as private. In those situations you either need to create a build target that will include those assets in the package or have some other convention in place to deliver the dependency to the runtime. Using the private assets route does not allow you to do what you're asking, but it is an exception to the rule of project reference becoming a LISTED dependency of your package.

Existing NuGet targets don't support this directly. A couple of issues on GitHub (1, 2) requesting this functionality have been open for years. However, with a bit of MSBuild item trickery, I was able to 'extend' ProjectReference with two attributes, PackageVersion and ExactVersion:
<!-- MyProject.csproj -->
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ItemGroup>
<ProjectReference Include="..\MyProject1\MyProject1.csproj" PackageVersion="[1.1.0, 2.0.0)" />
<ProjectReference Include="..\MyProject2\MyProject2.csproj" ExactVersion="true" />
<ProjectReference Include="..\MyProject3\MyProject3.csproj" />
</ItemGroup>
...
<Target Name="UseExplicitPackageVersions" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_ProjectReferenceWithExplicitPackageVersion Include="#(ProjectReference->'%(FullPath)')"
Condition="'%(ProjectReference.PackageVersion)' != ''" />
<_ProjectReferenceWithExactPackageVersion Include="#(ProjectReference->'%(FullPath)')"
Condition="'%(ProjectReference.ExactVersion)' == 'true'" />
<_ProjectReferenceWithReassignedVersion Include="#(_ProjectReferencesWithVersions)"
Condition="'%(Identity)' != '' And '#(_ProjectReferencesWithVersions)' == '#(_ProjectReferenceWithExplicitPackageVersion)'">
<ProjectVersion>#(_ProjectReferenceWithExplicitPackageVersion->'%(PackageVersion)')</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferenceWithReassignedVersion Include="#(_ProjectReferencesWithVersions)"
Condition="'%(Identity)' != '' And '#(_ProjectReferencesWithVersions)' == '#(_ProjectReferenceWithExactPackageVersion)'">
<ProjectVersion>[#(_ProjectReferencesWithVersions->'%(ProjectVersion)')]</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferencesWithVersions Remove="#(_ProjectReferenceWithReassignedVersion)" />
<_ProjectReferencesWithVersions Include="#(_ProjectReferenceWithReassignedVersion)" />
</ItemGroup>
</Target>
...
</Project>
Given package versions specified in other projects like this
<!-- ..\MyProject1\MyProject1.csproj -->
<!-- ..\MyProject2\MyProject2.csproj -->
<!-- ..\MyProject3\MyProject3.csproj -->
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Version>1.1.3</Version>
</PropertyGroup>
...
</Project>
the generated MyProject.nuspec file will contain the following dependencies:
<?xml version="1.0" encoding="utf-8" ?>
<package>
<metadata>
<dependencies>
<group targetFramework="...">
<dependency id="MyProject1" version="[1.1.0, 2.0.0)" />
<dependency id="MyProject2" version="[1.1.3]" />
<dependency id="MyProject3" version="1.1.3" />
</group>
</dependencies>
</metadata>
</package>
This useful target can be put into Directory.Build.targets to cover all projects in your solution.

As far as i know it's not possible with ProjectReference, however there are some open issues in this topic on Github, so it might happen that they will implement it sometime.
But for now this functionality is only enabled on PackageReference. Docs.

Well let's think that through shall we? The project may have a version number embedded in in it somewhere, but it's likely to be the latest or previous version, which might not even build, and there's no guarantee that a subsequent build step won't update that value. The point at which a build system produces a versioned artifact is near the end of the build, usually the last step, which is normally the packaging or publishing step.
If your project must limit version ranges for any of its dependencies, it should take dependencies on other packages, not the projects that build them. This provides a natural asynchronous set of workflows to feed into a single product.
If you want the convenience of having dependencies built to their latest, then you must keep all the projects in sync with each other wrt compatibility. Project dependencies really only make sense for developer builds, not CI builds.
One thing you should never do, is produce two different packages with the same version numbers. Visual Studio projects are broken by design in the area of versioning, as they default to using a static version string that must be set prior to the build. If you happen to forget to bump that number, you will violate this semantic versioning rule.
Even if the Nuget/VS devs give you what you are asking for, it's not a good solution. What if the the currently checked out project is for a version outside of the specified range? Assuming the devs can figure out what code to check-out of revision control, is that really what you want to happen on your dev box? Any solution they come up with will be complex and prone to errors. Even if you've got the version checked-out, Nuget can't know you didn't make a breaking change to it.
It's better to run independent pipelines of code, review, build, package, test and publish, using only published packages as dependencies.

Are you basing your question on how NodeJS versioning works (^ and ~)? In .NET that's not possible, and not necessary.
NodeJS needs this because, you know, it's javascript. Since javascript doesn't have strict type-checking, you need some way of verifying whether packages are compatible with each other. Some properties, methods might or might not exist on certain objects. So the only way the build system (node) can verify this is through the package version selectors.
As I said, in .NET we don't need this, because it's a strict programming language. If a field, property or method doesn't exist on a class, the project simply won't build.

Related

Handling conditional package references in code and unit tests

I have a library project that extends some functionality on EntityFrameworkCore. I'm looking to support both 2.* and 3.*. My project is setup like so:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
[...]
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
</ItemGroup>
[...]
</PropertyGroup>
</Project>
In the code I'm using the function EntityTypeExtensions.FindProperty(...). The signature of this function changes between 2.2.6 and 3.0.0.
The project's code (incorrectly?) uses the signature for 2.2.6. This compiles properly (which shouldn't be the case?) in both target frameworks.
I have a unit test project that multi-targets and has conditional references, much like the original project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.0</TargetFrameworks>
[...]
</PropertyGroup>
[...]
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.6" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.0' ">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.0.0" />
</ItemGroup>
[...]
</Project>
All unit tests (incorrectly?) pass in both target frameworks.
Note that even though it builds and tests pass, when the library is used in a netcore3 project (which references efcore 3.0.0 directly) it throws the following exception. Which seems completely reasonable, I just don't understand why it allowed me to get to this point.
System.MissingMethodException: Method not found: 'Microsoft.EntityFrameworkCore.Metadata.IProperty Microsoft.EntityFrameworkCore.EntityTypeExtensions.FindProperty(Microsoft.EntityFrameworkCore.Metadata.IEntityType, System.Reflection.PropertyInfo)'.
Questions:
Is there a way around this so it gets picked up as an error/warning/something, at least, during the build?
Is the solution to this to use preprocessor directives around the call to .FindProperty(...) and based on the framework make the correct method call? Isn't there a way to do this based on the version of efcore instead of the dependency?
Is there a way to unit test this properly with the different packages? Right now as it is, I expected the unit tests to fail in one of the versions since the method does not exist.
Source repository and specifically the call to FindProperty can be found here.
Sample netcore3 project that results in a MissingMethodException when calling the library can be found here.
Stack trace of the exception can be found here.
I have good news and bad news. The good news is that the problem is with your package, and everything works just how you appear to believe it should work. The bad news is I don't know how your package got incorrectly authored.
Steps to verify:
Download Panner.Order version 1.1.0 from nuget.org (you've published 1.1.1 since asking this questions, which has the same, but different, problem). If you have NuGet Package Explorer installed, open the nupkg with that, expand the lib/ folder and double click each of the .dll files. Alternatively you can extract the nupkg as a zip file then use ILSpy or ILDasm or whatever else you want to inspect the assemblies. Notice that both the netstanard2.0 and netcoreapp3.0 assemblies have the same assembly references. In particular the Microsoft.EntityFrameworkCore.dll reference is for version 2.2.6.0, even though we'd expect the netcoreapp3.0 version to use version 3.0.0.0. Therefore I conclude that your netstandard2.0 assembly was copied incorrectly into the netcoreapp3.0 folder of your package. Your 1.1.1 package has the opposite problem. Both the netstandard2.0 and netcoreapp3.0 folders contain the netcoreapp3.0 assembly, so your package doesn't work with projects that try to use the netstandard2.0 assembly.
However, I have no idea why this happens. When I clone your repo and run dotnet pack and check the generated nupkg, I can see that the netstandard2.0 and netcoreapp3.0 assemblies have different references, so I'm confident that the package I generated locally should work. You need to investigate why the packages you publish are not being generated correctly.
To quickly answer your questions:
Is there a way around this so it gets picked up as an error/warning/something, at least, during the build?
It will, as the problem was not with the project, but with the package. If you multi-target your project and call an API that does not exist in at least one of the TFMs, you will get a compile error.
Is the solution to this to use preprocessor directives around the call to .FindProperty(...) and based on the framework make the correct method call? Isn't there a way to do this based on the version of efcore instead of the dependency?
When you call APIs that are different in different TFMs, yes, you can use #if to change your code per project TFM, as described in ASP.NET Core's docs when migrating to 3.0.
I'm going to ignore the "based on the version of efcore" because I'm a detail oriented person, and I don't want to write one thousand words for something that ultimately doesn't matter. The key is that in this scenario, you don't need to. You used conditions on your package references to bring in a different version of efcore per project TFM, so each time your project gets compiled, it's using a different version of efcore, but only one version per compile target. Therefore you don't need runtime selection of different versions of efcore.
Is there a way to unit test this properly with the different packages? Right now as it is, I expected the unit tests to fail in one of the versions since the method does not exist.
You multi-target your test project, but I see you've done that already. Since you're using a project reference, the test won't detect package authoring problems like what's happening.
If you really want to test the package, rather than your code, you could use a nuget.config file to add a local folder as a package source, then your multi-targeting test project references the package, not the project. You'd probably want to also use the nuget.config file to set the globalPackagesFolder to something that's in .gitignore because NuGet considers packages to be immutable and if a debug version of your package gets into your user profile global packages folder, every project you use on that machine (that uses your user profile global packages folder) will use that debug version, making it more difficult for you to make updates. For customers who want to test packages, rather than projects, I highly recommend using SemVer2's pre-release labels and create a unique package version for every single build to reduce the risk of testing a different version than you intend.
Using package reference rather than project reference is a pain, because it's no longer as simple as writing code and then running the test. You'll need to change code, compile the project that gets generated into a package, copy the package into the package source folder if you haven't automated that, update the package version in your test project, then compile and run the test project. I think you're better off keeping the project reference. Fix the package authoring problem and then trust the tooling works.
Not to directly answer all questions above one by one, just to describe the cause of the original issue and some suggestions.
In the code I'm using the function
EntityTypeExtensions.FindProperty(...). The signature of this function
changes between 2.2.6 and 3.0.0.
According to your description, I assume you may use code like EntityTypeExtensions.FindProperty(entityType, propertyInfo); in your original project.
For Microsoft.EntityFrameworkCore 2.2:
FindProperty (this Microsoft.EntityFrameworkCore.Metadata.IEntityType entityType, System.Reflection.PropertyInfo propertyInfo); second parameter=>PropertyInfo
For Microsoft.EntityFrameworkCore 3.0:
FindProperty (this Microsoft.EntityFrameworkCore.Metadata.IEntityType entityType, System.Reflection.MemberInfo memberInfo); second parameter=>MemberInfo
However, please check PropertyInfo Class, you'll find:
Inheritance: Object->MemberInfo->PropertyInfo
And I think that's the reason why the project's code uses the signature for 2.2.6 but it compiles properly in both target frameworks. And it's the cause of other strange behaviors you met after that...
So for this issue, you could use the signature for 3.0.0(MemberInfo) in code instead of 2.2.6(PropertyInfo) to do the test. I think the build will fall as you expected. And as Heretic suggests in comment, for multi-target project, use #if is a good choice.
Hope all above makes some help and if I misunderstand anything, please feel free to correct me :)

Roslyn analyzer missing assembly warning

After creating a Roslyn analyzer package targeting .Net Standard 2.0, when I reference the package in another project, I receive the following error:
'C:\Users\username.nuget\packages\analyzer4\1.0.0.1\analyzers\dotnet\cs\Analyzer4.dll' depends on 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' but it was not found. Analyzers may not run correctly unless the missing assembly is added as an analyzer reference as well.
A repro of the project using the Analyzer is here. This repro is a vanilla .Net Core 2.0 console app with a reference to the analyzer and no other code whatsoever. The analyzer itself was built simply by creating the default Analyzer project in Visual Studio, changing it so that it targets netstandard2.0 instead of netstandard1.3, and then building in release mode to generate the .nupkg file. The analyzer does work properly, as the repro demonstrates, but the warning is generated.
There are discussions of this warning at various places on Github, such as here, but in those cases, the analyzer author had deliberately stripped out some local library code. In this case, the analyzer does not reference any other library.
I am not clear on what exactly it means to add an analyzer as an "analyzer reference" rather than just a regular project reference. I did try changing
<PackageReference Include="Analyzer4" Version="1.0.0.1" />
to
<Analyzer Include="..\LocalPackages\Analyzer4.1.0.0.1.nupkg" />
but that resulted in another error message ("PE image doesn't contain managed metadata").
Can anyone explain what this error means and ideally how to fix it?
Some background on this issue is here. When an analyzer depends on another assembly, then both must be listed as analyzers, but there is generally an exception for the core system assemblies. Unfortunately, it does not appear that .Net standard 2.0 has yet been added to the exceptions list; presumably, that will occur at some point in the future. I was able to make code changes to target the analyzer to .Net Standard 1.3 instead, thus avoiding the warning.
This problem will also arise when adding other assemblies (such as Newtonsoft.Json) into your analyzer. One solution to this is simply not to do so; for example, StyleCop eliminated its dependence on Newtonsoft.Json and simply includes the code for LightJson directly in its assembly. Other solutions might be (1) to manually copy the dll you are depending on (taking it from your packages folder if necessary) into the .nupkg file, recognizing that .nupkg is really just a .zip file; or (2) to use a tool like ILMerge to merge the dependency into your DLL. I have not yet experimented with these approaches, so if someone else can produce a step-by-step explanation of how to integrate this into a build for an analyzer, I will mark that as a correct answer.
You can use the approach in the Source Generators Cookbook (Thanks to #mbabramo for the link!).
<ItemGroup>
<PackageReference Include="Analyzer4" Version="1.0.0.1" />
</ItemGroup>
Becomes:
<ItemGroup>
<PackageReference Include="Analyzer4" Version="1.0.0.1" PrivateAssets="all" GeneratePathProperty="true" />
<None Include="$(PkgAnalyzer4)\lib\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
This should add the package dlls into your analyzer's folder, and it should work.

NuGet package (.NET Standard 2.x) breaking ASP.NET MVC5 application (.NET full framework)

(updated - see below)
I have an ASP.NET MVC5 application (multiple Assemblies) all addressing the .NET Full Framework 4.7.1
I recently added a (private) NuGet package that we built using .NET Standard 2. From Quickstart: Create and publish a package using Visual Studio (.NET Framework):
Unless you have a reason to choose otherwise, .NET Standard is the preferred target for NuGet packages, as it provides compatibility with the widest range of consuming projects.
Since then, things just haven't been the same.....there are a list of errors that I mention below, but I suspect they're all symptoms of the same issue (discussed at the end).
Please note: I'm using Visual Studio 15.7.1, and all NuGet packages use the package.config manage format rather than PackageReference.
First problem
Method not found:
'System.Collections.ObjectModel.Collection`1
System.Web.Http.HttpConfiguration.get_MessageHandlers()'
My guess here is that there's a .NET Standard version of System.Web.Http that doesn't have this method, and my application has chosen to address this rather than the 4.7.1 framework.
I partially fixed this by adding the following to my web.config file:
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
I say "partially" fixed it, this fixes the problem when run in my DEV environment (with Visual Studio) but when published to our QA environment, the issue remains. Any ideas on how to fix this?
Note: The MVC project's reference to System.Net.Http exists in the following path (it is NOT a NuGet package):
C:\Program Files (x86)\Microsoft Visual
Studio\2017\Professional\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net471\lib\System.Net.Http.dll
Second problem
Two of the Assemblies are involved with pulling data from various web-sources (WCF, web-api, web-service). When compiling these in RELEASE mode (where I have code analysis etc turned on) I get the following error reported:
An attempt was made to load an assembly with an incorrect format:
C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework.NETFramework\v4.7.1\Facades\System.IO.Compression.ZipFile.dll. {Name
of the assembly} {Path to the assembly}\SGEN
I found one post had the following suggestion:
Another suggestion I saw (which didn’t help me at all), was to disable
the project from creating a serialization assembly. Follow these
steps to do that (it may or may not help, but it’s worth a try):
In Solution Explorer, right click on the project that has the error and go to Properties.
In the Build tab, scroll to the very bottom and change Generate
Serialization Assembly to Off
I tried this and yes, it worked for me. However, these are the two projects that are serializing objects to send to these various web sources, so the last thing I want to be doing is un-optimizing serialization within my application...
Any suggestions on what might be wrong, or how I should best proceed?
UPDATE 14-May-2018
I found a great article from Scot Hanselman regarding NuGet packages which states:
As Oren wisely says:
"Using .NET Standard requires you to use PackageReference to eliminate
the pain of “lots of packages” as well as properly handle transitive
dependencies. While you may be able to use .NET Standard without
PackageReference, I wouldn’t recommend it."
However, there's a catch.... In Visual Studio, there is now an easy way to migrate an assembly from the older package.config to PackageReference as detailed in this link, but that article clearly states:
Note that the migrator does not presently support C++, JavaScript, and ASP.NET (.NET Framework) projects.
And when attempting this, the migration tool duly notified me that for the NuGet packages Microsoft.AspNet.Mvc and Microsoft.AspNet.WebPages:
"content" assets are not available when the package is installed after the migration
UPDATE 23-May-2018 I found several other people are experiencing a similar issue. From GitHub: .NET 4.6.1/.NET Standard 2.0 build with SGen fails #1630. Their "solution" was again to disable the serialization (see above) which would ruin performance on my application.
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
Conclusion?
So, am I right to conclude that to consume a .NET Standard 2.x NuGet package in a .NET FullFramework application, I need to use PackageReference rather than package.config and this is currently not possible with AspNet.MVC applications? In other words, it's not currently possible.
I've got this problem with .Net Framework 4.8 application and System.Buffers assembly incorrect format
The MarkKharitonov advice has solved the error. With Directory.Build.targets file I can built a project without any problem.
<Project>
<ItemGroup>
<ReflectionOnlyAssemblyNames Include="Microsoft.Bcl.AsyncInterfaces"/>
<ReflectionOnlyAssemblyNames Include="System.Buffers"/>
<ReflectionOnlyAssemblyNames Include="System.Numerics.Vectors"/>
<ReflectionOnlyAssemblyNames Include="System.Runtime.CompilerServices.Unsafe"/>
</ItemGroup>
<Target Name="RemoveDesignTimeFacadesBeforeSGen" BeforeTargets="GenerateSerializationAssemblies">
<ItemGroup>
<_ReflectionOnlyAssembly_Names Include="#(_ReferencePath_Names)"
Condition="'#(ReflectionOnlyAssemblyNames)' == '#(_ReferencePath_Names)' And '%(Identity)' != ''"/>
</ItemGroup>
<ItemGroup>
<ReferencePath Remove="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
<ReferencePath Remove="#(_ReflectionOnlyAssembly_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Removing DesignTimeFacades from ReferencePath before running SGen." />
</Target>
<Target Name="ReAddDesignTimeFacadesBeforeSGen" AfterTargets="GenerateSerializationAssemblies">
<ItemGroup>
<ReferencePath Include="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
<ReferencePath Include="#(_ReflectionOnlyAssembly_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Adding back DesignTimeFacades from ReferencePath now that SGen has run." />
</Target>
</Project>

Why does my .NET Standard 2.0 (multi-targetting) project has a warning on one of the dependent assemblies?

I have a project that is currently targetting NetStandard1.4.
I'm trying to make it multi-target-frameworks for:
net461
netstandard14
netstandard20
the rational is for a particular framework (an app targets), only pull down the minimum number of assemblies. So in the example above, ns14 has a min framework of 461, but an app that is targeting net461 pulls down some core stuff which people are saying adds extra noise, when those assemblies are not getting used.
When I try and target those 3 frameworks, I get some warning in the NetStandard2.0 version.
I try hovering the mouse over that assembly in Visual Studio but no tool-tip displays. Also, the errorlist or output (build) window has no explanation there.
Is there a way I can see what the warning is? Maybe even via CLI?
You are referencing System.Net.Http in .netStandard projects. This reference is already present in NetStandard.Library, so you don't need to add it. Most of the time, you should only reference projects or NuGet package.
On my computer, dotnet build does fail with the following warning:
C:\Program Files\dotnet\sdk\2.1.100-preview-007326\Microsoft.Common.CurrentVersion.targets(2051,5): warning MSB3245: Could not resolve this reference. Could not locate the assembly "System.Net.Http". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
If you don't want to add a reference to NetStandard.Library, the solution is to add reference only to the net461 version using the Condition attribute:
<PropertyGroup>
<TargetFrameworks>net461;netstandard1.4;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="System.Net.Http" />
</ItemGroup>

Add project.json package references to a VSIX

When trying to add references to a VSIX, it normally pulls it from the references in the .csproj. However, if the references are not in the .csproj, because they now are in a project.json file, then they don't get pulled to the vsix. The solution then may compile, but then the extension fails with "file not found" errors when installed into Visual Studio (since the assemblies where not copied to the VSIX).
I tried with the section of the manifest like so:
<Asset Type="Microsoft.VisualStudio.Assembly" d:Source="Project" d:ProjectName="*PROJECTNAME*" Path="|*ASSEMBLYNAME*|" AssemblyName="|*ASSEMBLYNAME*;AssemblyName|" />
But it does not work, as it does not recognize the package references.
After some research I saw a similar issue with a PCL, however, without an answer and not the same type of problem: MEF With Portable Class library using Microsoft Composition MEF2 throws file not found exception
In the same note, this seems like an acceptable workaround: VSIX with Project Templates and NuGet Packages however, as far as I understood, it implies using the package during the installation. Besides that, it doesn't work for our case as they need to specify the package version and we are using project.json so we can use floating versions (ie: 2.0.*)
Is there a way to reference this project.json references that we are missing? Maybe a workaround? The solutions I have found seem to all require to "paste" de DLL somewhere, which for floating versions is not that convenient.
Thanks in advance for any help or input.
Edit/Update: Since VSIX automatically pushes any assembly referenced in the CSPROJ (and not the project itself), trying to get the DLLs at a project level seems unlikely. After many tries, I think that a valid workaround would be to get the assemblies from the Output Folder. However, to my knowledge, VSIX does not have a way of doing this, or does it?
I'm not sure I'm understanding your question correctly, but if you're trying to install a Project Template via a VSIX and you want the project template to include all it's nuget packages when you use it you could do something like this.
Edit your Project Template's xproj file and add the following lines:
<ItemGroup>
<None Include="project.json"/>
<None Include="project.lock.json"/>
</ItemGroup>
Edit your Project Template's vstemplate file and add the following lines in the Project node:
<ProjectItem ReplaceParameters="true" TargetFileName="project.json">project.json</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="project.lock.json">project.lock.json</ProjectItem>
That should be all you need to do. Now when you install the project template, then create a new project using that template it should include all the nuget packages that were in the project.json file.

Categories

Resources