Skip to content

テナントごとの Favicon ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.1.01.5.8.1

ブラウザのタブに出る Favicon を、テナントの管理画面からアップロードして切り替えられるようにする設計メモです。本体の標準機能ではありません。 テナントのロゴ画像(CorpLogo)と同じ作りにすると、DB のスキーマを変えずに実装できます。調査は 1.5.1.0 で行い、前提にした部分を 1.5.8.1 のソースで確かめています。

前提にした現行実装 ​

Favicon ​

<head> の Favicon は HtmlHeadLinks.LinkedHeadLink が出力します。パスは favicon.ico で固定です(HtmlHeadLinks.cs#L105-L119)。

html
<link href="/favicon.ico" rel="shortcut icon">
項目現行
ファイルwwwroot/favicon.ico の 1 つだけ
テナント・ユーザーごとの切り替えなし
パラメータでの差し替えなし
apple-touch-icon・Web App Manifest出力しない

いまできるのは wwwroot/favicon.ico を差し替えることだけで、全テナント共通になり、本体の更新で元に戻ります。<head> に <link> を足す拡張機能(ExtendedHeadLinks)はソースにあるものの動きません(拡張ヘッドリンク(ExtendedHeadLinks)は動かない)。

部品1.5.8.1 のソース内容
表示の種類TenantModel.cs#L1774-L1778LogoTypes(ImageOnly / ImageAndTitle)
有無の確認BinaryUtilities.cs#L81ExistsTenantImage(BinaryType が TenantImage の行)
保存BinaryModel.cs#L1047-L1078UpdateTenantImage。ロゴのサイズにリサイズした PNG を、ReferenceId(テナント ID)と BinaryType で UpdateOrInsert。ローカル保存のプロバイダーならファイルに書く
削除BinaryModel.cs#L1112DeleteTenantImage
出力HtmlHeaders.cs#L176-L200画像があれば Binaries/TenantImageLogo/?yyyyMMddHHmmss(更新日時でキャッシュを破る)、なければ logo-corp.png などの既定画像
配信BinariesController.cs#L56-L71[ResponseCache(Duration = int.MaxValue)] を付けた GET
アップロード・削除の口BinariesController.cs#L88、#L116UpdateTenantImage(POST)・DeleteTenantImage
画像の種類ImageData.cs#L36-L48Types(SiteImage / TenantImage)、SizeTypes(Regular / Thumbnail / Icon / Logo)

図を読み込み中…

改修の方針 ​

ロゴと同じ流れを、BinaryType を TenantFavicon にして足します。Binaries テーブルの BinaryType で区別するので、スキーマの変更は要りません。

ファイル改修種別
Libraries/HtmlParts/HtmlHeadLinks.csLinkedHeadLink で、テナントの Favicon があればその URL を出す既存の改修
Models/Binaries/BinaryModel.csUpdateTenantFavicon / DeleteTenantFavicon追加
Models/Binaries/BinaryUtilities.cs有無の確認・取得・更新日時・アップロード・削除追加
Models/Binaries/BinaryValidators.cs形式・サイズのチェック追加
Controllers/BinariesController.cs取得(GET、長期キャッシュ)・アップロード(POST)・削除の 3 つ追加
Models/Tenants/TenantUtilities.csテナントの管理画面にアップロード欄を足す(ロゴの設定欄と同じ作り)追加
Libraries/Images/ImageData.cs必要なら Types に値を足す既存の改修

LinkedHeadLink の改修イメージです。

csharp
public static HtmlBuilder LinkedHeadLink(
    this HtmlBuilder hb, Context context, SiteSettings ss)
{
    var faviconHref = BinaryUtilities.ExistsTenantFavicon(
        context: context,
        referenceId: context.TenantId)
            ? Responses.Locations.Get(
                context: context,
                parts: new string[]
                {
                    "Binaries",
                    "TenantFavicon",
                    BinaryUtilities.TenantFaviconUpdatedTime(context: context)
                        .ToString("?yyyyMMddHHmmss")
                })
            : Responses.Locations.Get(
                context: context,
                parts: "favicon.ico");
    return hb
        .Link(href: faviconHref, rel: "shortcut icon")
        .EsModuleLinks(/* 既存のまま */);
}

決めておくこと ​

項目内容
形式ICO(1 つのファイルに複数の解像度を持てる)と PNG を受け付けたい。ロゴは ImageSharp でリサイズして PNG で保存するが、Favicon はアップロードされたものをそのまま保存し、Content-Type も保存時のもの(image/x-icon / image/png)で返す
キャッシュロゴと同じく長期キャッシュ+更新日時のクエリ文字列で破る。ただしブラウザは Favicon を強くキャッシュするので、変更後にすぐ変わらないことがある
apple-touch-iconiOS のホーム画面用に <link rel="apple-touch-icon"> も出すかどうか。出すなら同じ仕組みで別のサイズの画像を返す

テナントごとに Favicon が変わると、マルチテナントの環境でどのテナントのタブかを見分けやすくなります。

関連ページ ​

変更履歴

第1版Markdown の描画の仕組み・ショートカットキー・アイコン・公式マニュアルに無い $p 関数の解説と、Markdown 拡張・画像形式・ファビコン・テーマ・和暦などの改修・設計メモを追加