The tree of my solution looks like :
Project A
References Nuget Package "Some Package"
Project B
References Project A
When building, project B produces a package, let's call it PackageB
In ProjectB.csproj I have used the following:
<ProjectReference Include="ProjectA.csproj">
<PrivateAssets>All</PrivateAssets>
</ProjectReference>
Meaning PackageB, in addition to ProjecdtB.dll, includes ProjectA.dll
However it does not include "Some Package", so when I launch a client that references PackageB, I get a runtime error complaining that the dll contains in "Some Package" is missing.
How can I make sure "Some Package" is added as a depencency of PackageB. I'd like to do this in csproj, without relying on a nuspec file. Is this possible ?
[EDIT]
In order to get ProjectA included in the PackageB, I also need to mention that I'm using the Teronis.MSBuild.Packaging.ProjectBuildInPackage.
Thanks for using my package.
Let's first assume the following:
<!-- Project A -->
<ItemGroup>
<PackageReference Include="SomePackage" Version="*" />
</ItemGroup>
<!-- Project B -->
<ItemGroup>
<ProjectReference Include="ProjectA" PrivateAssets="all">
<!--<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="0.1.7" />-->
</ItemGroup>
You are telling NuGet that you don't want to have Project A to be picked up as NuGet-dependency. This is implicit, you don't have control about that. The down-side is the assmeblies of Project A, but not the assemblies of the packages of Project A, are not present in package of Project B.
By removing PrivateAssets="all" you disable the implicit behaviour of NuGet and the Project A will be picked up as NuGet dependency and EACH non-dependency package (also called transitive package).
Now let's asumme this:
<!-- Project A -->
<ItemGroup>
<PackageReference Include="SomePackage" Version="*" />
</ItemGroup>
<!-- Project B -->
<ItemGroup>
<ProjectReference Include="ProjectA" PrivateAssets="all">
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="0.1.7" />
</ItemGroup>
By having installed my package I assist in the implicit behaviour of NuGet: By not picking up Project A as NuGet-dependency copy over the direct assemblies produced by Project A to the bin-folder of Project B. This has the following drawback:
Because of the implicit behaviour and the usage of my package you have assemblies of Porject A in Project B that are in need of the assemblies provided by packages (in your example "Some Package") you referenced in Project A. So a workaround is to add the packages from Project A in Project B explicitly as shown here:
<!-- Project A -->
<ItemGroup>
<PackageReference Include="SomePackage" Version="*" />
</ItemGroup>
<!-- Project B -->
<ItemGroup>
<ProjectReference Include="ProjectA" PrivateAssets="all">
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="0.1.7" />
<!-- Use the SAME version like in Project A. -->
<PackageReference Include="SomePackage" Version="*" />
</ItemGroup>
This should solve your problem. Please provide feedback when it does NOT work.
In the PackageReference documentation, PrivateAssets is described as:
These assets will be consumed but won't flow to the parent project
Meaning the dependencies of Project A won't be copied over in Package B.
If you remove the PrivateAssets node, it should flow the dependencies properly.
Related
I'm making a nuget package which only includes references to a bunch of analyzers and a ruleset file.
I am struggling with getting it to add the <CodeAnalyzersRuleSet> tag to the .csproj file during package install.
After searching for a few hours I stumbled upon this 5 year old question which attempts to solve the same thing but I can't get it to work.
I've configured my NuGet project as follows:
Foo.csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Author, Description, ect removed for brevity -->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.6.0">
<IncludeAssets>analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.2.0">
<IncludeAssets>analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<IncludeAssets>analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
build\Foo.targets file:
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Foo.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>
And then the build\Foo.ruleset itself.
I run dotnet pack (dotnet version 7.0.102) in order to create the nuget package.
During package install the only thing that happens is that the package is added like a normal <PackageReference>, and I get all the analyser warnings but it doesn't add the ruleset file, and it doesn't add the <CodeAnalyzerRuleSet> tag to the .csproj file.
I've inspected the nuget package and it doesn't include the .targets and .ruleset files unless I add the following to my .csproj file as well:
<ItemGroup>
<None Include="build\**" Pack="True" PackagePath="build\" />
</ItemGroup>
This adds the files to the .nupkg but they are still not added or applied to my project during package install.
Any help or pointers are greatly appreciated.
Using .NET Core 5, is there a way to set a minimum version for a PackageReference via a Directory.Build.targets file?
We have a set of projects, most of which need to use a specific version of a package that is referenced by default by the compiler (FSharp.Core). However, one or two projects need a higher version. Therefore, we have a Directory.Build.targets that has:
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
Most project files therefore don't need any mention of FSharp.Core, but a couple would like a higher version, so they have this in their project files:
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="5.0.2" />
</ItemGroup>
However, the Directory.Build.targets file then downgrades the version as you'd expect. I don't want it to do this. I instead want the Directory.Build.targets file to impose a minimum version of 4.7.2.
I figured I could put a Condition on the PackageReference that only applies if the existing PackageReference has a Version < 4.7.2. But I haven't been able to figure out the MSBuild way of doing that, and am rapidly coming to the conclusion that it may not even be possible.
Here's where I'm at so far:
<Project>
<ItemGroup>
<FSharpCoreReferencesRequiringUpgrading Include="#(PackageReference)" Condition="$(%(Identity)) == 'FSharp.Core'"/>
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
By using an MSBuild Message task I've been trying to figure out what incantations are required to modify the Condition on FSharpCoreReferencesRequiringUpgrading such that it:
filters out all package references other than FSharp.Core
filters out all package references that are 4.7.2 or higher
I'm stuck on the first step because doing a simple string comparison as above does not work, and attempting to invoke ToString() or Include on the PackageReference does not work:
<!--
error MSB4184: The expression "%(Identity).ToString()" cannot be evaluated.
-->
Condition="$(%(Identity).ToString()) == 'FSharp.Core'"
Does anyone know if this is possible and how to go about it?
UPDATE 1: I've created a repro here
UPDATE 2: I've added an example of a fix suggested by David Kean (#davkean) here. However, I've definitely not implemented it correctly yet as I've obviously misunderstood him
UPDATE 3: I've added an example of another fix that works with all my testing, this time based on a recommendation from #Taskkant here. The fix is here
UPDATE
Try this in Directory.Build.targets:
<Project>
<PropertyGroup Condition="'$(UseHigherFSharpCoreVersion)' != 'true'">
<FSharpCorePackageVersion>4.7.2</FSharpCorePackageVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(UseHigherFSharpCoreVersion)' == 'true'">
<FSharpCorePackageVersion>5.0.2</FSharpCorePackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="$(FSharpCorePackageVersion)" />
</ItemGroup>
</Project>
Then in fsproj where higher version should be used:
<PropertyGroup>
<UseHigherFSharpCoreVersion>true</UseHigherFSharpCoreVersion>
</PropertyGroup>
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.
I'm making a core package for all the test projects in several solutions. A dependency graph is like:
MyTests.csproj -> MyTestFramework (nuget package) -> JUnitTestLogger (nuget package)
The problem is JUnitTestLogger.dll has to be copied to the output folder on the build of MyTests.csproj, or it just doesn't work. OK, I add:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
to MyTests.csproj and build again. As a result, there is every transitive dependency dll in the output folder... except for JUnitTestLogger.dll. I've checked its source code JUnitTestLogger.csproj and found nothing special.
What's wrong with this package, why is it not copied? I'm asking here, not on Github because of low activity at the project's repo.
MyTests.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MyTestFramework" Version="1.2.3" />
</ItemGroup>
</Project>
MyTestFramework.csproj (part):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<IsPackable>true</IsPackable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JUnitTestLogger" Version="1.1.0" />
</ItemGroup>
</Project>
Auto-generated MyTestFramework.nuspec (part):
<dependencies>
<group targetFramework=".NETCoreApp2.2">
<dependency id="JUnitTestLogger" version="1.1.0" exclude="Build,Analyzers" />
</group>
</dependencies>
I'm a maintainer on JunitXml.TestLogger (A newer package than the one you mentioned, but both were forked from the same source in Github/Spekt and share some code). The main thing I am aware of that is unusual with the test loggers is that they are referenced in your project, but not used by the code.
I haven't seen this specific issue, but there have been several in the past like this one where the library isn't copied on build. When I first used these libraries I had to put extra steps in my CI builds to copy the library in. From what I recall, my solution was the same as the one in the issue, which was to switch from msbuild to dotnet build. So maybe that or one of the other closed issues there will give a clue.
I'm hoping someone has some advice on the best way to use Teamcity to build and publish a solution that has both .NET Core/standard 2.0 projects and .NET framework 4.6.x projects in it.
Currently, I can build the project, run tests, but I can't figure out a way to publish it via the dotnet-cli. We have a relatively large solution, approximately 75 projects in .NET core/standard and 5 or some framework projects. Running dotnet publish on our solution results in the following error on the .NET framework projects:
error: C:\Program Files\dotnet\sdk\2.0.3\Microsoft.Common.CurrentVersion.targets(3861,5): error MSB4062: The "Microsoft.Build.Tasks.ResolveManifestFiles" task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
It would be ideal if the cli could attempt to ignore publishing the .NET Framework projects, but it doesn't seem to be possible. I'm thinking about writing a powershell script to check all csproj files in our solution for an appropriate TargetFramework value (i.e netstandard2.0/netcoreapp2.0), and publish them individually, but maybe someone knows a better way?
If anyone is facing the same issue, you need to restructure your csproj file as suggested by #nvoigt.
You can follow the steps as described in the post Old csproj to new csproj
You can start clearing out your csproj file and start with below format.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net462</TargetFramework> // if your target is 4.6.2
</PropertyGroup>
</Project>
And now you can add remaining of your dependency like below.
...
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.4" />
<PackageReference Include="Microsoft.Azure.Storage.Blob" Version="11.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
<PackageReference Include="Microsoft.Azure.KeyVault" Version="2.0.6" />
<PackageReference Include="NLog" Version="4.7.5" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.5" />
</ItemGroup>
...
you can find more details on the post.