I have solution that uses clean architecture, so I have following projects:
Core
Application
that depends on Core
Infrastructure
that depends on Application
Web
that depends on Application
and Infrastructure
I need to create NuGet package so I have went to folder with my Web.csproj
and I typed following command in PowerShell:
.\nuget pack Web/Web.csproj -IncludeReferencedProjects
Seems that all should work, but when I install this NuGet package into another project I'm getting following warnings:
Warning NU1603 Web 1.0.0 depends on Infrastructure (>= 1.0.0) but Infrastructure 1.0.0 was not found. An approximate best match of Infrastructure 1.0.0.1 was resolved.
Warning NU1603 Web 1.0.0 depends on Application (>= 1.0.0) but Application 1.0.0 was not found. An approximate best match of Application 1.2.1 was resolved.
Warning NU1701 Package 'Infrastructure 1.0.0.1' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8, .NETFramework,Version=v4.8.1' instead of the project target framework 'net7.0'. This package may not be fully compatible with your project.
All of above projects (Core
, Application
, Infrastructure
, Web
) uses NET 7. What's wrong with my NuGet package? How can I fix it?
These are my current .csproj:
Web.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>true</IsPackable>
<Version>1.3.2</Version>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
</ItemGroup>
</Project>
Application.csproj
:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="NSec.Cryptography" Version="22.4.0" />
<PackageReference Include="Paseto.Core" Version="1.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
Infrastructure.csproj
:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
</ItemGroup>
And the Core.csproj
:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Base64-Url" Version="1.0.0" />
</ItemGroup>
</Project>
From what I've been researching, there isn't a good way to do this. However, it is possible to get around it in two different ways.
1. Edit the .csproj posted by teneko
Where you should edit the .csproj
adding PrivateAssets="All”
in all references and adding the <TargetsForTfmSpecificBuildOutput>
into web.api
followed by <target>
block.
Web.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>true</IsPackable>
<Version>1.3.2</Version>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" PrivateAssets="All"/>
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" PrivateAssets="All"/>
</ItemGroup>
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
<ItemGroup>
<!-- Filter out unnecessary files -->
<_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))"/>
</ItemGroup>
<!-- Print batches for debug purposes -->
<Message Text="Batch for .nupkg: ReferenceCopyLocalPaths = @(_ReferenceCopyLocalPaths), ReferenceCopyLocalPaths.DestinationSubDirectory = %(_ReferenceCopyLocalPaths.DestinationSubDirectory) Filename = %(_ReferenceCopyLocalPaths.Filename) Extension = %(_ReferenceCopyLocalPaths.Extension)" Importance="High" Condition="'@(_ReferenceCopyLocalPaths)' != ''" />
<ItemGroup>
<!-- Add file to package with consideration of sub folder. If empty, the root folder is chosen. -->
<BuildOutputInPackage Include="@(_ReferenceCopyLocalPaths)" TargetPath="%(_ReferenceCopyLocalPaths.DestinationSubDirectory)"/>
</ItemGroup>
</Target>
</Project>
application.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="NSec.Cryptography" Version="22.4.0" />
<PackageReference Include="Paseto.Core" Version="1.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" PrivateAssets="All"/>
</ItemGroup>
infrastructure.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" PrivateAssets="All"/>
</ItemGroup>
The core.csproj does not change.
And apply the command dotnet pack --output C:/MySampleApi -p:PackageVersion=1.3.2
This approach relies on you editing the .csproj, this can interfere with test references. I believe it's wrong to have to edit code that works to be able to provide it in a different way.
2. The nuspec approach
You will need create a nuspec file into your /project/web
folder and add the <files>
tag to add your dlls from /bin/release
into C:/users/<username>/.nuget/packages/<project-name>/<version>/lib/net7.0
(if you are using windows), the nuspec file should seems like this.
web.nuspec (you can get an real example into
C:/users/<username>/.nuget/packages/<project-name>/<existing-version>
)
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>web</id>
<version>10.0.6</version>
<authors>api</authors>
<description>Package Description</description>
<dependencies>
<group targetFramework="net7.0">
<dependency id="Swashbuckle.AspNetCore" version="6.2.3" exclude="Build,Analyzers" />
</group>
</dependencies>
<frameworkReferences>
<group targetFramework="net7.0">
<frameworkReference name="Microsoft.AspNetCore.App" />
</group>
</frameworkReferences>
<contentFiles>
<files include="any/net7.0/appsettings.Development.json" buildAction="Content" />
<files include="any/net7.0/appsettings.json" buildAction="Content" />
</contentFiles>
</metadata>
<files>
<file src="bin\Release\net7.0\api.dll" target="lib\net7.0" />
<file src="bin\Release\net7.0\core.dll" target="lib\net7.0" />
<file src="bin\Release\net7.0\infrastructure.dll" target="lib\net7.0" />
<file src="bin\Release\net7.0\application.dll" target="lib\net7.0" />
</files>
</package>
note that the version is specified in this file and will no longer work in .csproj
or by command line.
Run this command into project/web
folder: dotnet pack --output C:/MyNugetSource -c Release -p:NuspecFile=web.nuspec
This approach doesn't mess up the code but relies on manipulating a configuration file and being careful with directory names. This can impact CI pipelines.
Finally, I believe that the best approach would be to create nuget packages for each project in the solution, in practice versioning the core, infrastructure and application and installing each one separately, it is worth evaluating the feasibility of this.
This answer was based on this post
Sorry for my english and i hope this helps.