はじめに
Visual Studio Installer Projectsというのがある。要するにインストーラーを作れる機能である。
しかし↑にはこう書かれている。
注意
このワークフローは、ASP.NET Core アプリケーションには対応していません。Windows デスクトップ アプリケーションにのみ対応しています。
実際ASP.NET Coreプロジェクトのインストーラーをこの方法で作ってみるといろいろとおかしな事になる。インストールするとなぜか動かなかったり、さらには何もインストールしないインストーラーが作られたりする。
StackOverflowやGitHubやマイクロソフト コミュニティなどを追ったところ、同じ問題に悩む人々は見つかったが、対処法は見つからなかった。
その割にはMicrosoft公式のサンプルがあったりする。
信じがたいことに、こいつは正常に動く。
対処法
結論から言うとこの2点である。
- 「項目の公開」の
PublishProfilePath
を指定する -
.csproj
と.pubxml
を編集してなんとかする
対処法までの道のり
すでに動いている物があるのだから、これを見ながら問題を解決していけるはずである。
PublishProfilePath
を指定した場合の現象
公式サンプルでは指定されているので、とりあえず普通にやると作られるFolderProfile.pubxml
でも指定してみる。
すると何もインストールしないインストーラーが作られてしまう。これではだめである。
というわけで、PublishProfilePath
を外してみよう。
PublishProfilePath
を指定しない場合の現象
一見正常なインストーラーが作成されるように見えるが、次のような現象が発生し、実際には動作しない。
- ネイティブのライブラリが読み込まれず
DllNotFoundException
が発生する -
wwwroot
フォルダ等が含まれていない
結局だめである。
もう一度PublishProfilePath
を指定する
改めて考えると、公式サンプルではPublishProfilePath
を指定していても正常なインストーラーが作られているという重要な事実がある。
すなわち、ここで指定している.pubxml
に何かあるはずである。
公式サンプルの.pubxml
(↑のファイル)を自分のプロジェクトに丸ごとコピーし、これを「項目の公開」のPublishProfilePath
に指定したところ、とりあえず「何もしていないインストーラーが作られる」状態からは脱却した。
ここにもサンプルの.pubxml
を貼り付けておく。
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net8.0\publish\Fd_Win64</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
</Project>
公式サンプル内の.pubxml
に対し、普通に生成される.pubxml
はいくつか項目が多い。おそらく特定の項目があると何もインストールしないインストーラーが作られてしまうのだろう。
そして動作確認した結果はこうだ。
- ネイティブのライブラリは正常に読み込まれる
-
wwwroot
フォルダ等が含まれていない - Razor Pagesがいずれも表示されない
少なくとも重大な問題が一つ解決した。なお新たな問題も発生したが、これも最終的には解決した。
ちなみに、ネイティブのライブラリが読み込まれなかったのは.deps.json
が含まれていなかったのが原因である。
wwwroot
フォルダ等が含まれない問題
正確にはwwwroot
フォルダの他、appsettings.json
やweb.config
が含まれない。
↑を読むと、どうやらASP.NET Coreプロジェクトでは、デフォルトでビルド時に含めるファイルがいろいろと設定されているようだ。
しかし今までの様々な現象を見るに、インストーラーを作る時はこれが正常に反映されず、様々なファイルが不足してしまうようである。
つまり、これらのファイルを含める設定を自前で行えばよい。
なお、先のページにも.csproj
の断片があるが、これを丸ごと.csproj
に書き足すだけではだめである。
↓のようなエラーが発生する。
対策は、デフォルトでビルド時にファイルを含める機能を無効にすることである。このようになる。
<PropertyGroup>
<EnableDefaultContentItems>false</EnableDefaultContentItems>
</PropertyGroup>
ならばいっそ、これをtrue
にするだけで解決では?と思ってしまうが、残念ながらそうはいかなかった。というわけでまだ続きがある。
wwwroot
が含まれない問題は↓を参考にして解消した。
最終的に↓のようになった。これを.csproj
内に書き足す。
<PropertyGroup>
<EnableDefaultContentItems>false</EnableDefaultContentItems>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**" CopyToOutputDirectory="PreserveNewest" />
<Content Include="web.config" CopyToOutputDirectory="PreserveNewest" />
<!--ルートディレクトリの.jsonだけ含めるようにする-->
<Content Include="*.json" CopyToOutputDirectory="PreserveNewest" />
<_ContentIncludedByDefault Include="@(Content)" />
</ItemGroup>
Razor Pagesが含まれない問題
こちらは↓を参考にした。
↓を.csproj
内に書き足す。
</ItemGroup>
<Content Include="**\*.cshtml" ExcludeFromSingleFile="true" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(DefaultWebContentItemExcludes)" />
<Content Include="**\*.razor" ExcludeFromSingleFile="true" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(DefaultWebContentItemExcludes)" />
<None Remove="**\*.cshtml" />
<None Remove="**\*.razor" />
</ItemGroup>
これでようやく正常に動作するようになった。
Microsoftの公式サンプルはなぜ動くのか
.pubxml
が予め細工されており、さらに申し訳程度のWeb APIを提供するだけのプログラムなのでwwwroot
やappsettings.json
は必要ないしRazor Pagesも使っていないからである。
ASP.NET Coreプロジェクトの.exe
を直接起動するとproduction
環境になる
インストーラーの問題とは直接関係ないがこれも記載しておく。
これは↓の通り、意図的な仕様である。