Referencing assemblies under dotnet installation directory - .net-core

Wondering if there is any legitimate reason for a .csproj to contain an assembly reference to an assembly w/ a hint path under the dotnet installation directory (default: c:\Program Files\dotnet on Windows).
In particular, the directories
packs
sdk
shared
An example of such a reference:
<ItemGroup>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions">
<HintPath>..\..\..\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.1.0\ref\netcoreapp3.1\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>

Surely not. This application would not work on other machines.
It looks like someone inserted code that uses Microsoft.Extensions.Configuration.Abstractions package which was not referenced and then probably applied "Quick fix" action from Resharper/Rider. Sometimes it leads not to referencing Nuget package
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" />
</ItemGroup>
but to referencing locally placed assembly.

Related

DotNet Core Create Proto message common library

The use case is pretty simple:
I have two projects (ProtoProvider & ProtoConsumer).
ProtoProvider has the proto file (to_import.proto) and the message I want to use on the ProtoConsumer.
ProtoConsumer has a referrence on ProtoProvider and attempts to use the ProvidedMessage in the imported.proto.
I cannot use the the message because I get "File not found." on the impoort and "ProvidedMessage is not defined" on the compiler for the imported.proto.
EDIT2>>>
To clarify I want to create a message like google's google.protobuf.Timestamp and distribute it to another project or projects without the other projects while having the project/projects (consumer) getting the message from the dll. The whole premise of the question is how to use the message defined in to_import.proto in another project through the dll (think of it as a common.grpc lib).
EDIT1>>>
The error messages I'm getting
Is there a solution that allows the importing of the proto files from a project reference?
I'm looking for something like google's solution for the well-known-types
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
source: https://developers.google.com/protocol-buffers/docs/csharptutorial#where-to-find-the-example-code.
(Copying the proto files or moving the files is not an elegant solution).
Below I'll provide the .csproj files
ProtoProvider:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="to_import.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="to_import.proto" GrpcServices="None" />
</ItemGroup>
</Project>
ProtoConsumer:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Protos\imported.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.27.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProtoProvider\ProtoProvider.csproj" />
</ItemGroup>
</Project>
Edit>>3
Some context : The purpose of this question is to help me understand a clearer way to implement decimal once (as specified here) and reuse them in each project.
AFAIK, compiling proto files requires all files (including imports) to exist on disk.
The way this works for the well known types is that they are included in Grpc.Tools nuget package.
So its not possible to ship a class library that accomplishes what you want.
Discussion on a related grpc-dotnet issue suggests using a combination of:
Building a nuget package containing your common proto and associated class library
In the consuming code's package reference, use GeneratePathProperty to generate a variable holding the path to the nuget package content
In the consuming code's Protobuf Include, use AdditionalImportDirs to include the common proto from the nuget package.

.NET Core 3 Invalid reference from Common Library

I need 2 assemblies for my .NET Core 3 WPF App - System.Windows.Forms and System.Drawing.Common.
When I try to add them as references in Visual Studio 2019 from the common shared folder (C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\3.0.0) i get an exception message box saying "The reference is invalid or unsupported".
I would expect this kind of thing to happen with framework mismatches, but this is from the dotnet core v3 shared folder, so everything should line up.
Is there any particular trick to adding these references that I am unaware of?
csproj file:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="logo.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
In the .NET Core, the project system does not handle well binary assembly references. It may not always work and is an unsupported and unrecommended way to reference assemblies. The proper way is to use package references or framework references. The latter are expressed at the top level of the project via the Sdk attribute i.e. <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">.
First of all, you should not add assembly references but add package references either manually or using the package manager. The reference to System.Drawing.Common assembly for .NET Core 3.0 target should look as follows:
<PackageReference Include="System.Drawing.Common" Version="4.6.0" />

dotnet core nuget package copying content files on restore

So I feel like I have come to the end of the rope here, but hoping someone knows more than I do here. I have some Typescript files, though that is mostly irrelevant as I am having this problem with all content files.
I am able to generate a nuget, or more precisely dotnet pack, nuget package that includes my content files in the package by using this in the .csproj of my parent project:
<ItemGroup>
<Content Include="Scripts\Utility.ts">
<Pack>true</Pack>
<PackagePath>contentFiles\Scripts\;content\Scripts</PackagePath>
</Content>
</ItemGroup>
I can browse the generated .nupkg and see that indeed the file was added to the package in both the content\Scripts and contentFiles\Scripts locations
The problem is that whenver I consume this package in my 'child' progect, that Typescript never gets copied into any folder of the child project, though I can see it extracted in the .nuget\packages\parent\... folders.
At first I thought it was something with my initial settings in the parent project, and it may be, but after trying what seems like everything in the book, that fails to copy the content files to the child project. I then tried going the dark path of trying to use Init.ps1 in the tools folder of my package, and though it was impossible to debug, it also seemed to run sporatically (I completely unistalled and reinstalled the package and it still failed to run most of the time.) This could be the way but I don't know why I can't get it to output to the Package Manager Console... maybe there's still hope with Init.ps1 but I can't seem to figure it out. Finally I see some potential with a nuget .targets file but I can's seem to grasp how to use it for my purpose either! I would love some feedback as to how to get this done.
From: Announcing NuGet 3.1 with Support for Universal Windows Platform
Importing content from a Nuget package was depreciated for projects using a project.json file in Nuget v3.1. Since then the project.json file has been dropped in favour of the new .csproj format. Importing content from a Nuget package should still work though if you're using the packages.config file instead.
Also mentioned is the fact that there are other package managers available for delivering content.
It looks to me like the answer in the new world is to create a node module containing utility.js and let npm deliver it to your project.
Possible Workaround:
I've looked at .targets to copy files and got this working, but it does run on each build - which may or may not be a problem for you. I can't do what I want with it.
In [PackageId].targets:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Either do this for all scripts in the Scripts/js folder -->
<Target Name="CopyScriptsToProject" BeforeTargets="Build">
<Message Text="Copying scripts to project" />
<ItemGroup>
<SourceScripts Include="$(MSBuildThisFileDirectory)..\..\content\Scripts\js\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(SourceScripts)" DestinationFiles="#(SourceScripts -> '$(MSBuildProjectDirectory)\wwwroot\js\%(RecursiveDir)%(Filename)%(Extension)')" Condition="!Exists('$(MSBuildProjectDirectory)\wwwroot\js\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<!-- Or do this for the individual script -->
<Target Name="CopyUtilityScriptToProject" BeforeTargets="Build">
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\..\content\Scripts\js\Utility.js" DestinationFiles="$(MSBuildProjectDirectory)\wwwroot\js\Utility.js" Condition="!Exists('$(MSBuildProjectDirectory)\wwwroot\js\Utility.js')" />
</Target>
</Project>
<!-- Note: condition can be removed from either if you want it to overwrite each build -->
and in the .csproj file (replacing [PackageId] with the name of your package):
<Project Sdk="Microsoft.NET.Sdk">
... any Globals for source control stuff ...
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<Version>7.0.0</Version>
<PackageId>[PackageId]</PackageId>
</PropertyGroup>
... any PackageReference stuff ...
<ItemGroup Label="Packaging">
<Content Include="build\netcoreapp2.0\[PackageId].targets" PackagePath="build\netcoreapp2.0\[PackageId].targets" />
<!-- Either -->
<Content Include="Scripts\js\**\*.*" PackagePath="content\Scripts\js;contentFiles\Scripts\js" />
<!-- or -->
<Content Include="Scripts\js\Utility.js" PackagePath="content\Scripts\js;contentFiles\Scripts\js" />
</ItemGroup>
</Project>
There seemed to be a bug whereby when the <PackageId>[PackageId]</PackageId> wasn't set explicitly in the .csproj, the build targets didn't work. Although that may well be an issue with my development environment.
Apparently you need the any\any in the path (learn more) as well as to include <PackageCopyToOutput>true</PackageCopyToOutput>, like this:
<ItemGroup>
<Content Include="Scripts\js\Utility.js">
<Pack>true</Pack>
<PackagePath>contentFiles\any\any\wwwroot\js\;content\any\any\wwwroot\js\</PackagePath>
<PackageCopyToOutput>true</PackageCopyToOutput>
</Content>
</ItemGroup>
You'll also need to precompile your TypeScript before including the .js files in the package
However, this still doesn't create a file there, just some strange reference to it.
In the end, we got it working with a .targets file, you can find a working repo here: https://github.com/NuGet/Home/issues/6743
Serj Sagan's answer got me on the right track, but it wasn't sufficient to deploy the content file to the bin directory (as he noted). I was able to get the file to be deployed by changing the package reference options in the consuming project's .csproj file, as follows:
<PackageReference Include="MyNuGetPackage" Version="0.0.0.1">
<IncludeAssets>all</IncludeAssets>
<PrivateAssets>analyzers;build</PrivateAssets>
</PackageReference>
It seems like the default for PrivateAssets is contentfiles;analyzers;build (documentation), which is not what we want in this case.
Simplified code and explanation from #PurplePiranha
TL;DR:
Basic .NET6 simplified sample code on Github
Step by Step guide
Selection of the files
First we need to select all the files that needs to get into the nuget package.
Add this to the <LibraryPackageName>.csproj:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="<Your directory path>\<your file(s)>" />
</ItemGroup>
Multiple content lines are allowed.
Write a target
Make a target file to copy the files before (or after) the build to the bin directory:
The location and name of this file is important:
<root>\build\<LibraryPackageName>.targets
Now, make sure that it will get executed by referencing it in the <LibraryPackageName>.csproj by adding a content line:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="build\<LibraryPackageName>.targets" PackagePath="build\<LibraryPackageName>.targets" />
<Content Include="filesToAdd\*.txt">
<Pack>true</Pack>
</Content>
</ItemGroup>
Eg: From the code in github:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="Packaging">
<Content Include="build\PackageToGenerateFile.targets" PackagePath="build\PackageToGenerateFile.targets" />
<Content Include="filesToAdd/*.txt">
<Pack>true</Pack>
</Content>
</ItemGroup>
NOTE: By copying the files to the bin directory, the files are not part of your version control, but your package is!
Build and pack
In Visual Studio, right-click on the package name and select "Pack".
A new nuget package should be created in the bin directory of your library.
Use the nuget package
Install the nuget package now in your destination package.
Notice that the files are in the solution explorer, but not in a directory on your disk. They have a shortcut symbol.
Build the destination package
Check the bin directory.
The files should be copied to the location mentioned in the targets.

SGEN error on Build of Release version of mixed ASP.Net and .Net Standard 2.0 projects Solution

I am working on a Visual Studio 2017 Solution that contains 3 projects:
Two Class Libraries in .Net Standard 2.0 (Any CPU)
One ASP.Net in .Net Framework 4.6.1 (Any CPU)
If I Build All in Debug (Any CPU), all runs fine.
But if I Build All in Release (Any CPU), then this error shows in the Output Window:
3>SGEN : error : An attempt was made to load an assembly with an incorrect format: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\ref\netfx.force.conflicts.dll.
How to solve it?
The error stems from confusion between NETStandard and NuGet libraries when resolving dlls. Put this into your failing project's .csproj file (Unload project, Edit .csproj file):
<Target Name="ReplaceNetFxNetStandardRefWithLib" AfterTargets="ImplicitlyExpandNETStandardFacades">
<ItemGroup>
<Reference Remove="#(_NETStandardLibraryNETFrameworkReference)" Condition="'%(FileName)' != 'netfx.force.conflicts'" />
<Reference Remove="#(_NETStandardLibraryNETFrameworkReference)" Condition="'%(FileName)' != 'System.Configuration.ConfigurationManager'" />
<Reference Include="#(_NETStandardLibraryNETFrameworkLib)">
<Private>true</Private>
</Reference>
</ItemGroup>
</Target>
<Target Name="RemoveNetFxForceConflicts" AfterTargets="ResolveAssemblyReferences">
<ItemGroup>
<ReferencePath Remove="#(ReferencePath)" Condition="'%(FileName)' == 'netfx.force.conflicts'" />
<ReferencePath Remove="#(ReferencePath)" Condition="'%(FileName)' == 'System.Configuration.ConfigurationManager'" />
</ItemGroup>
</Target>
In my case, this error was reported due to incorrect package installed in the project. Though you uninstall the incorrect package installed it was still reporting error, the solution will be
Ensure to uninstall the package with the option "Force uninstall even if there are dependencies on it"
Even after following step 1 if you still encounter the same sgent error, then expand "References" node in solution explorer, remove the unwanted dlls that might have been installed as part of installing the incorrect package.

How do I specify dependencies in a .NET Standard Class Library?

A .NET Standard Class Library doesn't use a .nuspec file; there is a "Package" tab in the project settings where you enter all the metadata for the NuGet package. These go in the .csproj file.
I want to create a solution with projects A and B, where project B depends on project A. Both need to go on NuGet as separate packages. But if someone installs the NuGet package for B, it should also install the package for A.
How do you specify this simple dependency for a .NET Standard Class Library? I'm not assuming that adding a reference will be enough to do this.
NET Standard .csproj files use PackageReference and ProjectReference MSBuild items to control dependencies on packages loaded from NuGet or your solution, respectively. They both support metadata tags PrivateAssets, IncludeAssets, ExcludeAssets, which control what exactly and how your project depends on in those dependencies. By default, all dependencies are auto-generated by the Visual Studio with PrivateAssets, which means those dependencies are consumed, but they're not marked as dependencies for consumers of your project (which is gonna be a package in NuGet).
So, you just need to replace the PrivateAssets metadata with the IncludeAssets (maybe with proper values).
For example, my SuperPackage.csproj file looks like below:
..................
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2">
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<IncludeAssets>compile</IncludeAssets>
</ProjectReference>
</ItemGroup>
</Project>
So, I have the PackageReference to the 'Newtonsoft.Json' package from NuGet marked as a dependency, and the ProjectReference to the ClassLibrary1 project within the single solution.
When the SuperPackage project is built with checked 'Generate NuGet package on build', I get the following SuperPackage.nupkg:
Check this doc for more details: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files
From what I have found it is not yet supported in .csproj files and you should use .nuspec to specify dependencies. Have a look how they do it in xUnit, for example.

Resources