Blazor アプリケーションを "http://example.​com/foo/bar/" のような Sub Path に配置するために必要な実装

# はじめに

Blazor アプリケーションを、`http://example.com/foo/bar/` のような Sub Path 以下に配置したい場合があります。

しかし、普通にプロジェクトテンプレートから新規作成しただけの Blazor アプリケーションでは、発行後にそのような Sub Path に配置しても、うまく動作してくれません。
(状況によってどのように "うまく動作しない" かはまちまちですが、"Sorry, there's nothing at this address" と表示されてしまうとか HTTP 404 が発生したりとかがよくある例です)

以降では、Blazor アプリケーションをそのような Sub Path に配置できるようにするために必要なプログラムや設定項目の変更について記します。
なお本記事で説明している内容は、基本的には下記公式ドキュメントにて説明されています。

https://docs.microsoft.com/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-6.0&tabs=visual-studio

# その前に: GitHub Pages に配置したい場合

もしも、Blazor WebAssembly スタンドアロンアプリを GitHub Pages の Project Site (つまり、URL が `https://***.github.io/foo` のようになる) として発行したいがために本記事を参照されているなら、本記事ではなく、下記記事を参照してください。
本記事で記載している手順をくどくど施すことなく、NuGet パッケージを 1 つ追加するだけで、GitHub Pages 用に Blazor WebAssembly スタンドアロンアプリを発行できます。

https://qiita.com/jsakamoto/items/0be0005d9b30acbfe1e4

# Blazor WebAssembly スタンドアロンの場合

## wwwroot/index.html の `<base href="..."/>` に配置先 Sub Path を記述

プロジェクトテンプレートから新規作成したての Blazor WebAssembly プロジェクトでは、wwwroot/index.html 中の base タグには、ベースパスとしてルート (`/`) が指定されていますが、これを、配置先の Sub Path をベースパスとするよう変更します (下記例)。

```html:wwwroot/index.html
<html>
<head>
  ...
  <!-- 👇 ここに配置先 Sub Path を記述 - ⚠️注意! 末尾のスラッシュは必須! -->
  <base href="/foo/bar/" />
  ...
```

## Properties/launchSettings.json を変更

Blazor WebAssembly (スタンドアロン) については、配置先で "動作させるだけ" なら、上記のとおり index.html の base タグを書き換えるだけで充分です。

しかし実際問題としては、base タグを `<base href="/foo/bar/" />` のように書き換えてしまった状態で、開発やデバッグ実行すると、それはそれで正常動作しません。
index.html の base タグを書き換えた状態でも、デバッグ実行等ができるよう、開発環境を調整する必要があります。

具体的には、Properties/launchSettings.json に対して、以下の追加・変更を施す必要があります。

- "launchUrl" (もしなければ追加して) に配置先 Sub Path を記載 (行頭・行末にスラッシュは付けない)
- 環境変数 "ASPNETCORE_PATHBASE" の項目を追加し、配置先 Sub Path を記載 (行頭のスラッシュ必須、行末にスラッシュは付けない)
- "inspectUri" に Sub Path を挿入

具体例は下記のとおりとなります。

```jsonc:Properties/launchSettings.json
{
  ...
  "profiles": {
    "BlazorWasmStandAloneApp": {
      ...
      // 👇 "launchUrl" に配置先 Sub Path を指定 - ⚠️注意! 行頭・行末にスラッシュは付けない!
      "launchUrl": "foo/bar",

      // 👇 "inspectUri" が示す URL に配置先 Sub Path を挿入
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/foo/bar/_framework/debug/ws-proxy?browser={browserInspectUri}",
      ...
      "environmentVariables": {
        ...
        // 👇 環境変数 "ASPNETCORE_PATHBASE" の設定を追加、配置先 Sub Path を指定
        // ⚠️注意! 行頭のスラッシュは必須、行頭のスラッシュは付けない!
        "ASPNETCORE_PATHBASE": "/foo/bar"
      }
    },
    // 以下、"IIS Express" 用の構成にも、上記と同じ変更を施す
    ...
```

以上の変更を施した状態で、`dotnet watch` を実行したり、Visual Studio 上でこの Blazor WebAssembly スタンドアロンプロジェクトを実行すれば、期待どおりに "/foo/bar" の Sub Path でアプリが開かれ動作します。
もちろん、ホットリロードも機能しますし、Visual Studio や Visual Studio Code によるデバッグ実行もできます。

## 注意点

index.html や launchSettings.json のいずれの設定追加や変更においても、Sub Path の指定時、**行頭・行末のスラッシュ有無は、各設定項目が求める仕様のとおり、間違いのないよう指定する必要があります。**
このスラッシュ有無を誤って設定すると、正常動作しません。

## 補足1: Properties/launchSettings.json が存在しない場合

Properties/launchSettings.json を作成せずに開発する場合は、

- 予め環境変数 `ASPNETCORE_PATHBASE` に配置先 Sub Path を設定しておいてから (⚠️行頭のスラッシュは必須、行頭のスラッシュは付けない)、`dotnet watch` や `dotnet run` を実行するか、
- あるいは、`dotnet run --pathbase=/foo/bar` のように、`dotnet` コマンドの引数に `--pathbase` オプションを付記して配置先 Sub Path を指定 (⚠️行頭のスラッシュは必須、行頭のスラッシュは付けない) して実行するか

上記いずれかの方法で Blazor WebAssembly スタンドアロンプロジェクトを実行できます。

## 補足2: 発行後に index.html を書き換える方法でも可能です

Blazor WebAssembly のスタンドアロンプロジェクトでは、開発中は Sub Path はルート (`/`) のまま、つまりプロジェクトテンプレートから新規作成した状態のまま開発を行ない、発行後に、発行先フォルダにある index.html 中の base タグを配置先 Sub Path に書き換えてから配置することでも構いません。

# Blazor WebAssembly + ASP.NET Core ホストの場合

## Client プロジェクトの wwwroot/index.html の `<base href="..."/>` に、配置先 Sub Path を記述

プロジェクトテンプレートから新規作成したての Blazor WebAssembly + ASP.NET Core ホストプロジェクトでは、Client プロジェクト内の wwwroot/index.html 中の base タグには、ベースパスとしてルート (`/`) が指定されていますが、これを、配置先の Sub Path をベースパスとするよう変更します (下記例)。

```html:Client プロジェクト内の wwwroot/index.html
<html>
<head>
  ...
  <!-- 👇 ここに配置先 Sub Path を記述 - ⚠️注意! 末尾のスラッシュは必須! -->
  <base href="/foo/bar/" />
  ...
```

## Server プロジェクトのミドルウェア構成時、`UsePathBase("...")` 呼び出しを追加

Server 側 (ASP.NET Core ホスト側) プロジェクトにて、HTTP 要求パイプラインのミドルウェア構成時に、`UsePathBase("...")` 拡張メソッド呼び出しを、パイプラインの早い段階に追加して、配置先 Sub Path を指定します。

```csharp:.NET 6 の場合の Server/Program.cs
...
var app = builder.Build();
// 👇 UsePathBase() 呼び出しを追加、配置先 Sub Path を指定
// ⚠️注意! 行頭スラッシュ必須/行末スラッシュは付けない!
app.UsePathBase("/foo/bar");
...
```

```csharp:.NET 5 や .NET Core 3.1 の場合の Server/Startup.cs
...
public class Startup {
  ...
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    // 👇 UsePathBase() 呼び出しを追加、配置先 Sub Path を指定
    // ⚠️注意! 行頭スラッシュ必須/行末スラッシュは付けない!
    app.UsePathBase("/foo/bar");
    ...
```


## Server プロジェクトの Properties/launchSettings.json を変更

ここまでの処置で、Blazor WebAssembly + ASP.NET Core ホストプロジェクトを発行すれば、発行後コンテンツは Sub Path "/foo/bar" に配置された状態で動作するようになります。
しかしここまでの処置だけだと、開発時の実行やデバッグ実行が正常動作しません。

そこで開発環境での実行やデバッグ実行ができるようにするために、Server 側 (ASP.NET Core ホスト側) Properties/launchSettings.json に対して、以下の追加・変更を施す必要があります。

- "launchUrl" (もしなければ追加して) に配置先 Sub Path を記載 (行頭・行末にスラッシュは付けない)
- "inspectUri" に Sub Path を挿入

具体例は下記のとおりとなります。

```jsonc:Server 側 Server/Properties/launchSettings.json
{
  ...
  "profiles": {
    "BlazorWasmAspNetCoreHostedApp": {
      ...
      // 👇 "launchUrl" に配置先 Sub Path を指定 - ⚠️注意! 行頭・行末にスラッシュは付けない!
      "launchUrl": "foo/bar",

      // 👇 "inspectUri" が示す URL に配置先 Sub Path を挿入
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/foo/bar/_framework/debug/ws-proxy?browser={browserInspectUri}",
      ...
    },
    // 以下、"IIS Express" 用の構成にも、上記と同じ変更を施す
    ...
```

以上の変更を施した状態で、`dotnet watch` を実行したり、Visual Studio 上でこの Server 側 (ASP.NET Core ホスト側) プロジェクトを実行すれば、期待どおりに "/foo/bar" の Sub Path でアプリが開かれ動作します。
もちろん、ホットリロードも機能しますし、Visual Studio や Visual Studio Code によるデバッグ実行もできます。

## 注意点

index.html や HTTP 要求パイプライン構成、launchSettings.json のいずれの設定追加や変更においても、Sub Path の指定時、**行頭・行末のスラッシュ有無は、各設定項目が求める仕様のとおり、間違いのないよう指定する必要があります。**
このスラッシュ有無を誤って設定すると、正常動作しません。


# Blazor Server の場合


## ミドルウェア構成時、`UsePathBase("...")` 呼び出しを追加

HTTP 要求パイプラインのミドルウェア構成時に、`UsePathBase("...")` 拡張メソッド呼び出しを、パイプラインの早い段階に追加して、配置先 Sub Path を指定します。

```csharp:.NET 6 の場合の Program.cs
...
var app = builder.Build();
// 👇 UsePathBase() 呼び出しを追加、配置先 Sub Path を指定
// ⚠️注意! 行頭スラッシュ必須/行末スラッシュは付けない!
app.UsePathBase("/foo/bar");
...
```

```csharp:.NET 5 や .NET Core 3.1 の場合の Startup.cs
...
public class Startup {
  ...
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    // 👇 UsePathBase() 呼び出しを追加、配置先 Sub Path を指定
    // ⚠️注意! 行頭スラッシュ必須/行末スラッシュは付けない!
    app.UsePathBase("/foo/bar");
    ...
```

## Properties/launchSettings.json を変更

以上の処置で、Blazor Server プロジェクトを発行すれば、発行後コンテンツは Sub Path "/foo/bar" に配置された状態で動作するようになります。
しかしここまでの処置だけだと、開発時の実行やデバッグ実行が正常動作しません。

そこで開発環境での実行やデバッグ実行ができるようにするために、Properties/launchSettings.json に対して、以下の追加・変更を施す必要があります。

- "launchUrl" (もしなければ追加して) に配置先 Sub Path を記載 (行頭・行末にスラッシュは付けない)

具体例は下記のとおりとなります。

```jsonc:Properties/launchSettings.json
{
  ...
  "profiles": {
    "BlazorServerApp": {
      ...
      // 👇 "launchUrl" に配置先 Sub Path を指定 - ⚠️注意! 行頭・行末にスラッシュは付けない!
      "launchUrl": "foo/bar",
      ...
    },
    // 以下、"IIS Express" 用の構成にも、上記と同じ変更を施す
    ...
```

以上の変更を施した状態で、`dotnet watch` を実行したり、Visual Studio 上でこの Blazor Server プロジェクトを実行すれば、期待どおりに "/foo/bar" の Sub Path でアプリが開かれ動作します。
もちろん、ホットリロードも機能しますし、Visual Studio や Visual Studio Code によるデバッグ実行もできます。

## 注意点

HTTP 要求パイプライン構成や launchSettings.json のいずれの設定追加や変更においても、Sub Path の指定時、**行頭・行末のスラッシュ有無は、各設定項目が求める仕様のとおり、間違いのないよう指定する必要があります。**
このスラッシュ有無を誤って設定すると、正常動作しません。

# おわりに

以上のとおり、

- Blazor WebAssembly スタンドアロン、
- Blazor WebAssembly + ASP.NET Core ホスト、
- Blazor Server 

のいずれの形態の Blazor アプリケーションであっても、指定の Sub Path へ配置しての実行、および、ホットリロードとデバッグ実行を含む開発作業ができるよう構成できます。

実際、今回説明した構成に基づいて、Windows OS の IIS 上で、異なる Sub Path に 複数の Blazor アプリケーションを配置して運用することも可能です。

以上、_Learn, Practice, Share!_ :)