简体   繁体   中英

Create nuget package while solution uses clean architecture

I have solution that uses clean architecture, so I have following projects:

  1. Core
  2. Application that depends on Core
  3. Infrastructure that depends on Application
  4. 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 do.net 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: do.net 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM