最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

.net - Create a Nuget package with just a resources file using dotnet pack - Stack Overflow

programmeradmin1浏览0评论

A couple years ago, I set up my build to create separate packages for a main library a number of language resource files.

Project structure:

- proj
  - localization
    - lib.nuspec
    - lib.de.nuspec
    - lib.es.nuspec
    - ...

One of the language nuspec files

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata minClientVersion="2.12">
    <id>JsonSchema.Net.de</id>
    <version>1.0.0</version>
    <!-- ... -->
    <language>de</language>
    <dependencies>
      <dependency id="JsonSchema.Net" version="6.0.0" />
    </dependencies>
  </metadata>
  <files>
    <file src="..\bin\Release\netstandard2.0\de\lib.resources.dll" target="lib\netstandard2.0\de" />
  </files>
</package>

Creates multiple nuget packages

lib.nupkg - contains lib.dll and lib.resources.dll
lib.de.nupkg - contains only de/lib.resources.dll
lib.es.nupkg - contains only es/lib.resources.dll
...

I use a GitHub Actions matrix build to fan out packing the languages using nuget pack, passing the nuspec file, and everything worked really well.

But recently, nuget.exe stopped working on ubuntu because apparently it requires mono, which isn't supported anymore and has been removed from the ubuntu image.

Now I have to figure out how to do this with dotnet pack, which requires a csproj file and doesn't support nuspec files.

I've tried creating a lib.de.csproj file that just includes the resx file. It builds and includes the de/lib.de.resources.dll, but it also includes a lib.de.dll file, and I'm guessing that de/lib.de.resources.dll won't be loadable by the lib.dll. I don't think this is going to work in the end.

I've also considered creating different build profiles to the lib project, but I can't figure out how to exclude the lib.dll from the language packs, or if doing this is even supported.

I may end up needing to raise an issue in the dotnet cli repo, but I thought I'd ask here first.

A couple years ago, I set up my build to create separate packages for a main library a number of language resource files.

Project structure:

- proj
  - localization
    - lib.nuspec
    - lib.de.nuspec
    - lib.es.nuspec
    - ...

One of the language nuspec files

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata minClientVersion="2.12">
    <id>JsonSchema.Net.de</id>
    <version>1.0.0</version>
    <!-- ... -->
    <language>de</language>
    <dependencies>
      <dependency id="JsonSchema.Net" version="6.0.0" />
    </dependencies>
  </metadata>
  <files>
    <file src="..\bin\Release\netstandard2.0\de\lib.resources.dll" target="lib\netstandard2.0\de" />
  </files>
</package>

Creates multiple nuget packages

lib.nupkg - contains lib.dll and lib.resources.dll
lib.de.nupkg - contains only de/lib.resources.dll
lib.es.nupkg - contains only es/lib.resources.dll
...

I use a GitHub Actions matrix build to fan out packing the languages using nuget pack, passing the nuspec file, and everything worked really well.

But recently, nuget.exe stopped working on ubuntu because apparently it requires mono, which isn't supported anymore and has been removed from the ubuntu image.

Now I have to figure out how to do this with dotnet pack, which requires a csproj file and doesn't support nuspec files.

I've tried creating a lib.de.csproj file that just includes the resx file. It builds and includes the de/lib.de.resources.dll, but it also includes a lib.de.dll file, and I'm guessing that de/lib.de.resources.dll won't be loadable by the lib.dll. I don't think this is going to work in the end.

I've also considered creating different build profiles to the lib project, but I can't figure out how to exclude the lib.dll from the language packs, or if doing this is even supported.

I may end up needing to raise an issue in the dotnet cli repo, but I thought I'd ask here first.

Share Improve this question asked Feb 4 at 7:39 gregsdennisgregsdennis 8,4285 gold badges41 silver badges76 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

It turns out there is some support for building custom packages directly from the project file. Here's what I did.

To start, in the .csproj file, I set <IncludeBuildOutput>false</IncludeBuildOutput>. This prevents the packing step from using the build output.

The next step is to define what goes into the nuget files. This can be done with a bunch of this line inside an ItemGroup:

<None Include="README.md" Pack="true" PackagePath="\" />

You have to include all of the files since there's no dedicated properties like in the nuspec file. The dotnet pack command will automatically infer the files' purposes so long as you get them all in the right places.

Next up, you don't want all of these files to appear in your project in Visual Studio, so you'll want to put a condition on the ItemGroup:

<ItemGroup Condition="'$(ResourceLanguage)' == 'base'">

The condition means the ItemGroup applies only when the ResourceLanguage property equals base, which we'll use to indicate the main library. What is the ResourceLanguage property? I made it up. It's not actually defined until you include it in the dotnet pack command:

dotnet pack -p:ResourceLanguage=base

The new section should look something like this:

<ItemGroup Condition="'$(ResourceLanguage)' == 'base'">
  <None Include="README.md" Pack="true" PackagePath="\" />
  <None Include="..\..\LICENSE" Pack="true" PackagePath="\" />
  <None Include="..\..\Resources\logo-256.png" Pack="true" PackagePath="\" />
  <None Include="bin\$(Configuration)\netstandard2.0\lib.dll" Pack="true" PackagePath="lib\netstandard2.0" />
  <None Include="bin\$(Configuration)\netstandard2.0\lib.xml" Pack="true" PackagePath="lib\netstandard2.0" />
  <None Include="bin\$(Configuration)\netstandard2.0\lib.pdb" Pack="true" PackagePath="lib\netstandard2.0" />
  <None Include="bin\$(Configuration)\net8.0\lib.dll" Pack="true" PackagePath="lib\net8.0" />
  <None Include="bin\$(Configuration)\net8.0\lib.xml" Pack="true" PackagePath="lib\net8.0" />
  <None Include="bin\$(Configuration)\net8.0\lib.pdb" Pack="true" PackagePath="lib\net8.0" />
  <None Include="bin\$(Configuration)\net9.0\lib.dll" Pack="true" PackagePath="lib\net9.0" />
  <None Include="bin\$(Configuration)\net9.0\lib.xml" Pack="true" PackagePath="lib\net9.0" />
  <None Include="bin\$(Configuration)\net9.0\lib.pdb" Pack="true" PackagePath="lib\net9.0" />
</ItemGroup>

You'll also want to include a PropertyGroup with the same condition that contains any package properties unique to the base package.

<PropertyGroup Condition="'$(ResourceLanguage)' == 'base'">
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
  <PackageId>lib-name</PackageId>
  <Description>lib description</Description>
  <Version>1.2.3</Version>
  <PackageTags>some tags</PackageTags>
  <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

That takes care of the main package. Now we need to do this again for the language packs.

<PropertyGroup Condition="'$(ResourceLanguage)' != '' And '$(ResourceLanguage)' != 'base'">
  <PackageId>lib.$(ResourceLanguage)</PackageId>
  <PackageTags>some tags language pack</PackageTags>
</PropertyGroup>

<ItemGroup Condition="'$(ResourceLanguage)' != '' And '$(ResourceLanguage)' != 'base'">
  <None Include="README.$(ResourceLanguage).md" Pack="true" PackagePath="\README.md" />
  <None Include="..\..\LICENSE" Pack="true" PackagePath="\" />
  <None Include="..\..\Resources\logo-256.png" Pack="true" PackagePath="\" />
  <None Include="bin\$(Configuration)\netstandard2.0\$(ResourceLanguage)\lib.resources.dll" Pack="true" PackagePath="lib\netstandard2.0\$(ResourceLanguage)" />
  <None Include="bin\$(Configuration)\net8.0\$(ResourceLanguage)\lib.resources.dll" Pack="true" PackagePath="lib\net8.0\$(ResourceLanguage)" />
  <None Include="bin\$(Configuration)\net9.0\$(ResourceLanguage)\lib.resources.dll" Pack="true" PackagePath="lib\net9.0\$(ResourceLanguage)" />
</ItemGroup>

And finally, because each language pack has its own version, and I like to have the language in the description, I used additional PropertyGroups for each language I support:

<PropertyGroup Condition="'$(ResourceLanguage)' == 'de'">
  <Description>lib Locale German (de)</Description>
  <Version>1.0.1</Version>
</PropertyGroup>

Now I can run a similar dotnet command for each of the languages I support:

dotnet pack -p:ResourceLanguage=de

The final process for my GH Action is

cd lib-proj-folder
dotnet restore                                              # restore packages
dotnet build -c Release --no-restore                        # build
dotnet pack -c Release --no-build -p:ResourceLanguage=base  # pack base lib
dotnet pack -c Release --no-build -p:ResourceLanguage=de    # pack language de
# ...

The only thing I wasn't able to figure out is the dependencies for the language packs. They're currently the dependencies of the main lib. I think it detects the dependencies from the obj/ folder. I tried putting the condition on the ItemGroups with the project and package references, but it didn't have any effect on the pack command.

You can view the final project file here and the GH Action file here.

发布评论

评论列表(0)

  1. 暂无评论