How to change SpecificVersion to false for NuGet packages? - c#

I would like to change SpecificVersion to false for internally used NuGet packages.
I am using PackageReference and not packages.config, if that makes a difference.
While searching a solution for this topic, I have found those results
GitHub Nuget: https://github.com/NuGet/Home/issues/1380
Which states
In project.json (NuGet3) we are moving to a mode where NuGet does not touch the csproj file at all (where scenarios you are describing are partly the inspiration for the change).
I didn't manage to find the mentioned "project.json" file, where this could be possible? (Notice: the linked url is 7+ years old)
What can you do
You probably need to come up with a different way to define the
settings in your csproj file. Instead of putting them on the reference
that we know if going to change, we are going to use an msbuild
feature that lets you apply the settings to a reference.
You can go with the approach outlined by this SO post and use an
msbuild target.
I did try to read the linked StackOverflow post but frankly speaking I don't understand how this can be used for my scenario.
Also I found this:
Why is the NuGet Package Manager removing SpecificVersion False from the project file
Where it states
You would probably have to write a PowerShell script to fix up the references that are changed on updating.
But I seem to fail to understand where a powershell script should write the necessary changes to make SpecificVersion false?
As I mentioned at the beginning, I am talking about internally used NuGet packages, so if there is a solution revolving around defining something in the nuspec or in the csproj file that gets packed into a NuGet package this would also be a approach I can take.

Taking "whatever necessary steps" literally, you could explicitly reference the assemblies within the package instead of relying on PackageReference default behavior. This ties your csproj to the folder structure of the package, though.
It will also probably break anything the package does to the consumer's csproj with its own .props and .targets files.
I did not test this:
<!-- Define assets so that the package is basically ignored,
because we want to manually reference its assemblies. -->
<PackageReference Include="MyPackage.SomeWhere" PrivateAssets="all" IncludeAssets="none" GeneratePathProperty="true" />
<!-- Reference assemblies manually with the path property from above as base folder
Repeat for all assemblies in the package -->
<Reference Include="$(PkgMyPackage_SomeWhere)/lib/net461/SomeAssembly.dll" SpecificVersion="false" />

Related

Specifying files to add to a nuget package in .csproj file

I am creating a nuget package from some code, but also need to deploy some tools with the package.
In a .nuspec file, I can do this with the <files> element, and this all works well.
However when using a .nuspec file, the packageReferences from the csproj file aren't included, and I am seeing some problems when including them manually (with the <dependencies> element).
The package created also always seems to restore as a .net framework package, even though it is targetting .net, as in this question.
I am hoping that all these problems would go away if I moved to using the .csproj format for specifying the nuget package details, but having read the docs I can't find out how to do it.
Does anyone know how it is done?
If not, can anyone shed any light on created a .net framework / .net core nuget package from a .nuspec file, that restores to the correct target version and respects package dependencies?
It's not easy to find/discover, but NuGet's MSBuild tasks docs page has a section called "including content in a package", which tells you about the PackagePath metadata on MSBuild items, that NuGet uses to copy files into the package.
So, in your csproj, you could have something like this:
<ItemGroup>
<None Include="..\MyTool\Tool.exe" PackagePath="tools" Pack="true" />
</ItemGroup>
and then your package will contain tools\Tool.exe. The Pack="true" attribute is required for None elements.
You can use MSBuild's globbing to copy entire directories, if that's easier. Include="..\MyTool\*". My MSBuild skills are not so advanced, so I don't know how to glob ..\MyTool\**\*, which means all files in all subdirectories, while maintaining the correct directory layout in the PackagePath="???" metadata. So the best I can suggest is one glob per directory.

The missing file is packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props

As i have tried to restructure the path using the ..\ in the csproj file after building the project
it still shows the error as stated after building the project here is the error below.
Also i have complete package for Microsoft.Net.Compilers.props as per the path which i have checked in the system where project resides, here is the path of the project below.
Now if I put ..\ or without it still won't find the path of the system here is the code after unloading the .csproj file below.
<Import Project="..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\build\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
<Import Project="..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
The missing file is
packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props
First, glad to know that you have solved your issue by yourself.
Actually, this target node is from a file packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props which is in your nuget package and it will add a target called EnsureNuGetPackageBuildImports into your xxx.csproj file when you install Microsoft.Net.Compilers nuget package.
Besides, since you have changed the default <Error Condition="xxxx"> node under this target due to some reasons(maybe migrate this project from somewhere into your new agent), the nuget mechanism does not recognize it and when you want to uninstall this package, the node cannot be deleted automatically, it can only be modified manually.
In addition, the Error task in MSBuild is equivalent to interrupting the construction generation based on certain judgment conditions. Therefore, in your current environment, that is, if you cannot find the specified Microsoft.Net.Compilers.props file, you cannot build your project.
Suggestion
1) So to solve it, you can just edit the condition to the correct path of Microsoft.Net.Compilers.props as you did.
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.4.0\build\Microsoft.Net.Compilers.props')" xxxx />
2) Or if your project has a lot of that, I suggest you could first delete these targets in xxx.csproj file and then run update-package -reinstall under Tools-->Nuget Package Manager-->Package Manager Console.
And this will reshape the nuget package according to the current environment and it can also fix DLL addresses that reference the wrong DLL and so on.

How to package projects and used NuGet packages + files?

I'm working on a .NET Standard 2.0 project called ComputeSharp and I'm having some trouble creating a NuGet package from it. Some info:
The project only targets .NET Standard 2.0
The project uses 2 referenced projects in the same solution, each using some other NuGet packages. Here is a screen of my current solution.
One of the project, ComputeSharp.Shaders also references two .dll files, dxcompiler.dll and dxil.dll. These two are referenced by that project with the following snipped in its .csproj file. I made a PR to DotNetDxc with the update .dll files, so I'll no longer need to manually bundle the two .dll files into my project. So this is no longer an issue ✅
In the folder for the main ComputeSharp project, I also have a .nuspec file with the following structure, which also lists all the NuGet packages used by all 3 projects (note that the path for the *.mustache file goes up one directory because it's inside the ComputeSharp.Shaders project, and not the one from which I'm building the NuGet package, which is just ComputeSharp:
<?xml version="1.0"?>
<package >
<metadata>
<id>ComputeSharp</id>
...
<dependencies>
<dependency id="SharpDX.Direct3D12" version="4.2.1-beta0-gab36f12303" />
...
</dependencies>
<contentFiles>
<files include="..\ComputeSharp.Shaders\Renderer\Templates\*.mustache" buildAction="None" copyToOutput="true" />
</contentFiles>
</metadata>
</package>
In order to create the NuGet package, I first build ComputeSharp in Release mode, then open a cmd in the folder for that project, and run:
nuget pack ComputeSharp.csproj -Prop Configuration=Release -IncludeReferencedProjects
This does create a package that kinda looks ok. It contains the assemblies for all 3 projects, the two .dll files I use and the .mustache content file from the ComputeSharp.Shaders project.
Once uploaded to NuGet I can see the list of all the dependencies for the package, as you can see in this screen. So, that looks is ok as well.
PROBLEM: once I create a test project and install the NuGet package, I notice two things: first get this nice exception when I try to use any APIs, which makes me thing the other NuGet packages haven't been installed correctly at all, and then I can't find any of the APIs from either of those packages (eg. I don't see the SharpDX namespace at all), which makes me thing the previous point is probably correct. I have one last issue: the .mustache file (and relative parent folders) are not created in the build output directory, so I can't load it at runtime. I'm not sure why that is, since I did specify copyToOutputDirectory="true" in the .nuspec file.
I might be missing something obvious here, and I did check both the documentation and countless other SO questions on NuGet packages and whatnot, but I really couldn't figure out what I'm doing wrong here. I do have other NuGet packages uploaded, using the same method of including the referenced NuGet packages in the .nuspec file, and they work just fine when installed.
Thank you for your help!
EDIT #1: the indirect dependencies are now loaded correctly, so the last remaining issue is the content file not being copied to the build output directory (see changes above).
EDIT #2: closing this as it's too broad in scope, and the first part has been resolved already (.dll files and indirect package references). Opening a follow up question just for the issue about the content files not being copied here.

Is there a way to tell Visual Studio to use only specific kinds of references in a .Net Core solution?

I keep running into an issue in Visual Studio where I reference a NuGet package that is installed in my local NuGet cache, but is not added as a reference in the NuGet package references for the project. Visual Studio defaults to adding a hint path reference to the package on my local file system instead of a package reference. IE this
<ItemGroup>
<Reference Include="Awesome.Package.dll">
<HintPath>local/path/to/NuGet/cache/Awesome.Package.dll</HintPath>
</Reference>
</ItemGroup>
instead of this
<ItemGroup>
<PackageReference Include="awesome-package" Version="x.y.z" />
</ItemGroup>
Now, I know how to install NuGet packages correctly, that's not the issue. I want to prevent Visual Studio/.Net (whichever is the responsible party) from reaching outside the solution for dll references. In my projects there should only be 3 valid kinds of references:
other projects in the solution
.Net Core SDK
NuGet packages referenced with a <PackageReference> tag
If VS/.Net can't reference code like this, I need it to raise an error or otherwise indicate that the code I am trying to use does not exist. Assuming that it is OK to just reach out wherever it feels like to find dlls is not acceptable. The bad references get committed, which cause my build system to fail and other team members to get errors when they pull down commits containing the bad references.*
Is there a way to whitelist/blacklist particular means of referencing external code in Visual Studio and/or .Net Core?
*yes, we can do a better job filtering these issues out when committing code or doing PRs, but that is relying on humans to catch errors that could be prevented from occurring in the first place by software
Is there a way to tell Visual Studio to use only specific kinds of
references in a .Net Core solution?
I'm afraid the answer is negative. As I know there's no such option in VS can manage references in .net core projects in this way.
The original issue you encountered may have something to do with the way you consumed the package. In a .net core project, if you add reference to that nuget package by Nuget Package Manager UI or Package Manager Console, it should be normal PackageReference format. So actually what you need to do is use the right way to consume nuget packages since VS don't support the behavior you want in any option as I know.
*yes, we can do a better job filtering these issues out when committing code or doing PRs, but that is relying on humans to catch
errors that could be prevented from occurring in the first place by
software
For now, since VS supports the scenario in which we reference normal assemblies in Reference format, so the Intellisense won't raise error when you have that kind of reference in .net core project file. As an alternative, maybe you can build the project locally before committing it to repos.
Try a Directory.Build.props file. Create a text file and rename it as Directory.Build.props, you can add content into it like:
<Project>
<Target Name="CheckIfThereExistsNotValidReferences" BeforeTargets="build">
<ItemGroup>
<InValidReferences Include="#(Reference)" />
<SdkReferences Include="#(Reference)" Condition="$([System.String]::new('%(Reference.HintPath)').Contains('C:\Program Files\dotnet\sdk\NuGetFallbackFolder'))" />
<InValidReferences Remove="#(SdkReferences)" />
</ItemGroup>
<Message Text="aaaaaaaaa #(InValidReferences)" Importance="high" Condition="'#(InValidReferences)'!=''" />
<Error Text=" Raise the error cause there exists invalid references!" Condition="'#(InValidReferences)'!=''" />
</Target>
</Project>
Put this file in solution directory, then it will help check if there exists the reference format you don't want in project file. If it exists, it will raise error. It works in my machine locally.With this file in solution directory, every time you build it locally before committing the changes, it there's exists the Reference format you dislikes, the build will fail and raise error. But it's only for build time, to raise error like Intellisense way, this is not supported now. You can post Suggest a Feature request in Developer Community. Hope it helps.

How to create symbols for multi-project Nuget package?

So I'm really struggling to figure this out.
I have a solution with a few projects, say, A, B, and C. A references and uses B and C (both project references). I wanted to create a Nuget package from A, and I did so, successfully, although I had to jump a few hoops, using things like this:
<ProjectReference Include="..." PrivateAssets="All" />
...
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" />
</ItemGroup>
</Target>
However, I would like to also debug through my Nuget package, so I found a few tricks to do so. One would be to copy the pdb into the nupkg, although that's not recommended. It supposedly works with this line in your csproj file. That adds the pdb to the nupkg, but only A.pdb is added.
Otherwise one could/should create a A.symbols.nupkg file. I tried doing that using tags like DebugSymbols, DebugType, EmbedSources, and IncludeSymbolsInPackage, but to no avail.
I also tried > dotnet pack A.csproj --include-symbols --include-source, and that generates a A.nupkg and a A.symbols.nupkg, but within the symbols, only A.pdb and not B.pdb and C.pdb.
So I guess my question is: How to create a nuget package from a multi-project solution which you can debug into (so including either pdb's or symbols/sources, not one, but from all referenced projects)?
TLDR: I've already seen a lot of potential solutions, but so far, none worked.
Nuget git issue thread
StackExchange thread
Some blog on GeekLearning.io
And many more...
Some of my last resorts may be: just adding all contents of B and C to A, so that there's only one project left, or creating a powershell script to manually add all the pdb's in the the A.symbols.nupkg. Of course, I'd like a more straightforward solution, if there is any.
The steps that should work:
Ensure that the references are indeed project references and not referencing the built DLLs directly.
Ensure that all of the PDBs are being copied to the output folder after building.
Use either of the methods you have tried (symbols package or hardcoding the inclusion of the .pdb extension).
If this is not working as expected, I would recommend providing additional details such as the csproj file for 'A' and any nuspecs tried.

Categories

Resources