WinUI3のコントロールのnupkgを作って使ったときに出てくる「.xbfがない」エラーの対応

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

WinUI3のUserControlを作って、それを複数のWinUI3アプリで共用したいなと思い、UserControlをdllにして、それをnupkgにして他アプリでも使えるようにしようとした。

いざ、UserControlを含むnupkgを作ってWinUI3アプリから使おうとすると、下図のようなエラーが出た。

どうにかしたい。

前提

  • .net6
  • WindowsAppSDK 1.1.3
  • 2022/12/21時点で試した内容

原因

どうも、作った.nupkgの中に、「XXXXX.xbf」というファイルが含まれていないのが原因らしい。

本当は、nupkgの中の下記のフォルダに、この場合で行くと「MyControl.xbf」というファイルが無いといけないが、これがないためにエラーが起きてしまう。

対応策

このやり方がいいかどうかはおいといて、こうやったら動いた。

VSのプロジェクトのプロパティのビルド操作中にパッケージファイルを生成しますをONにする。 これをONにすると、ビルドすると自動でnupkgを作ってくれる。

dotnet packコマンドでもできるので、別の方法でnupkg作りたい場合はこのチェック無しでもOK。

次に、 UserControlを含むプロジェクトのcsprojのPropertyGroupに、

<GenerateLibraryLayout>true</GenerateLibraryLayout>

を追記する。
※ただ、これをやらなくても動く気がする。下に挙げた参考ページではやれとあるので、一応書いておく。

ビルドする。 ビルドすると、出力先フォルダに.nupkgができる。

この.nupkgを、解凍する。
nupkgは、拡張子を.zipに変えて、zipとして解凍しれやれば、中身を見ることができる。

その中の、下の「★★ココ」のところに、.xamlと並んで、本当は「MyControl.xbf」があってほしいのだが、ない。

│  WinUI3Controls.nuspec
│  [Content_Types].xml
│
├─lib
│  └─net6.0-windows10.0.19041
│      │  WinUI3Controls.dll
│      │  WinUI3Controls.pri
│      │
│      └─WinUI3Controls
│              MyControl.xaml  ←★★ココ
│
├─package
│  └─services
│      └─metadata

「MyControl.xbf」は、nupkgの中ではなく、普通にビルドした出力フォルダの方には入っている。

ので、それをコピーして、nupkgを解凍したフォルダの中の「★★ココ」に貼り付ける。

その後、そのフォルダを再度zipして、拡張子を.nupkgにして、それを使いたいWinUi3プロジェクトから見ると、エラーなく使うことができた。

※再度zipして.nupkgにするとき、中身のフォルダ階層が間違えてると下図のようなエラーになる。地味にハマったので注意。


22/12/25追記

一つ、マシなやり方を見つけた。
nuspecファイルを作成して、それを使ってnupkgをつくる。

マシなやり方内容

まず、下記のようなnuspecファイルを作る。

ファイル名は何でもいいが、いったんWinUI3Controls.nuspecにする。

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  <metadata>
    <id>WinUI3Controls</id>
    <version>1.0.0</version>
    <authors>WinUI3Controls</authors>
    <description>Package Description</description>
    <dependencies>
      <group targetFramework="net6.0-windows10.0.19041">
        <dependency id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.755" exclude="Build,Analyzers" />
        <dependency id="Microsoft.WindowsAppSDK" version="1.2.221209.1" exclude="Build,Analyzers" />
      </group>
    </dependencies>
  </metadata>
  <files>
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\*.dll" target="lib\net6.0-windows10.0.19041\" />
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\*.pri" target="lib\net6.0-windows10.0.19041\" />
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\WinUI3Controls\*.*" target="lib\net6.0-windows10.0.19041\WinUI3Controls" />
  </files>
</package>

上記の.nuspecを、csprojファイルと同じ階層に置く。

VisualStudioから、WinUI3Controlsのプロジェクトをビルドして、出力フォルダ(binフォルダ)ができた状態にしておく。

VisualStudioの「開発者用Powershell」で、cdでそのcsprojファイルと同じ階層に行く。

そこで、コマンドdotnet pack -p:NuspecFile=.\WinUI3Controls.nuspecを実行する。

すると、xbfが含まれたnupkgが作成される。

やったこと

nuspecの中の、下記がキモ。
(それ以外の部分は、デフォルト?で出力される(VSが吐いたnupkgの中に含まれる)nuspecと同じ内容。)

  <files>
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\*.dll" target="lib\net6.0-windows10.0.19041\" />
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\*.pri" target="lib\net6.0-windows10.0.19041\" />
    <file src=".\bin\Debug\net6.0-windows10.0.19041.0\WinUI3Controls\*.*" target="lib\net6.0-windows10.0.19041\WinUI3Controls" />
  </files>

やったのは、 出力先フォルダの中から、nupkgに含めるファイルを指定した、ということ。

上記をnuspecに書いてあげれば、xbfを含む今回必要なファイルが入ってくれた。

のところをなにもかかないと、標準的に必要なファイルをVSが自動的にnupkgに含めてくれる様子。

さらにもう少しましなnuspec

下記のnuspecでいけそう。

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  <metadata>
    <id>WinUI3Controls</id>
    <version>1.0.0</version>
    <authors>WinUI3Controls</authors>
    <description>Package Description</description>
    <dependencies>
      <group targetFramework="net6.0-windows10.0.19041">
        <dependency id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.755" exclude="Build,Analyzers" />
        <dependency id="Microsoft.WindowsAppSDK" version="1.2.221209.1" exclude="Build,Analyzers" />
      </group>
    </dependencies>
  </metadata>
  <files>
    <file src=".\bin\Debug\**\*.*" exclude="**/*.pdb;**/*.json" target="lib\" />
  </files>
</package>

出力先フォルダの中身全部を、nupkgのlibフォルダの下に、pdbとか、不要なもの以外全部入れてやるイメージ。

これで、必要なものが一式入る。

「ビルド操作中にパッケージファイルを生成します」のチェックを外しておいて、ビルド後イベントにdotnet pack -p:NuspecFile=.\WinUI3Controls.nuspecを入れておいてあげれば、ビルドするごとに新しいnupkg作れるようになりそう。

参考

参考

〇nuspecに好きなアセンブリファイルを含める方法(MS公式)

https://learn.microsoft.com/ja-jp/nuget/reference/nuspec#including-assembly-files

XAML コンポーネントを含む NuGet パッケージがある場合は、XAML バイナリ ファイル (.xbf) を手動で含める必要があります。そうしないと、解析が失敗します。よくわかりましたが、なんと頭の痛い問題でしょう。

https://stackoverflow.com/questions/34742349/how-to-reference-a-usercontrol-from-an-external-class-library-through-a-nuget-p

Windows Phone 8.1 NuGet packages with XAML components
そんなに昔から引きずっている現象なのか??

https://dschenkelman.github.io/2014/06/25/windows-phone-8-1-nuget-packages-with-xaml-components/

〇How can I add my UserControl to my NugetPackage?

UWPでもWPFでもなんでも、UserControlをNupkgにしようと思うと、手動で必要なものを含めないといけないっぽい。

https://stackoverflow.com/questions/40182778/how-can-i-add-my-usercontrol-to-my-nugetpackage

UWPのControlをnupkgにしたいときの調査記事。具体的でわかりやすい。

https://blog.tmyt.jp/entry/2015/11/03/040916

上記記事の、nuspecにfilesを書く書き方が、下記の公式にあるっぽい。(まだあまり見てない)

https://learn.microsoft.com/ja-jp/nuget/reference/nuspec?source=recommendations#including-assembly-files

〇nugetパッケージの作成方法公式

https://learn.microsoft.com/ja-jp/nuget/create-packages/creating-a-package