Zastosuj asp-append-version oprócz plików statycznych w folderze wwwroot

Data utworzenia strony :

Środowiska

Visual Studio
  • Visual Studio 2019
Rdzeń ASP.NET
  • 3.1 (strona razor, MVC)

Pliki statyczne umieszczone poza folderem wwwroot nie odzwierciedlają asp-append-version

app.UseStaticFiles Określając dodatkowe StaticFileOptions wywołanie metody Pliki statyczne mogą być również umieszczane w folderach innych niż wwwroot. Jednak w przypadku plików statycznych umieszczonych poza folderem wwwroot, znacznikami linków i skryptów asp-append-version Ustawienie atrybutu nie powoduje dodania informacji o wersji do adresu URL.

Dam mu szansę. Pliki są rozmieszczone w następujących konfiguracjach:

Startup.Configure również opublikować folder Obszary/Site1/Content.

// wwwroot フォルダで静的ファイル参照を有効にする
app.UseStaticFiles();

// Site1 用の物理コンテンツフォルダと参照 URL を紐づける
app.UseStaticFiles(new StaticFileOptions()
{
  FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Areas/Site1/Content")),
  RequestPath = "/Site1",
});

Następujący index.cshtml kod został dodany do . Każdy z nich asp-append-version jest dodawany.

<!-- ここから追加 -->

<!-- wwwroot のファイル -->
<img src="~/image/sample.png" asp-append-version="true" />

<!-- wwwroot 以外のファイル -->
<img src="~/site1/image/sample1.png" asp-append-version="true" />

<!-- ここからまで -->

Po uruchomieniu obraz jest wyświetlany poprawnie.

Jeśli jednak spojrzysz na kod HTML strony, zobaczysz, że ciąg jest rozwinięty tylko do plików umieszczonych w wwwroot.

Przyczyny, gdy asp-append-version nie jest odzwierciedlony

To zależy od właściwości, która określa, czy asp-append-version env.WebRootFileProvider jest IFileProvider odzwierciedlone. Domyślnie określony identyfikator wwwroot PhysicalFileProvider jest ustawiony tak, aby nie był odzwierciedlany w innych folderach.

Istnieje IFileProvider klasa, która może mieć więcej niż CompositeFileProvider jedną Możesz spakować więcej niż jeden tutaj PhysicalFileProvider i dać go do env.WebRootFileProvider . Tylko ścieżka folderu fizycznego może być przekazywana do ostatniego, StaticFileOptions.RequestPath Nie można określić więcej niż jednego, więc nie sądzę, aby było to zamierzone działanie.

* env.WebRootFileProvider jest Startup.Configure odbierany IWebHostEnvironment env metodą.

Dziedzicz IFileProvider i tworzenie własnych klas

ASP.NET fileProvider, ponieważ nie może być obsługiwany przez standardowe funkcje w samym rdzeniu.

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Primitives;

namespace Microsoft.Extensions.FileProviders
{
  /// <summary>
  /// wwwroot フォルダ以外のファイルで "asp-append-version”を有効にするための複数の <see cref="StaticFileOptions"/> を管理するファイルプロバイダです。
  /// </summary>
  class CompositeStaticFileOptionsProvider : IFileProvider
  {
    private readonly IFileProvider _webRootFileProvider;
    private readonly IEnumerable<StaticFileOptions> _staticFileOptions;

    /// <summary>
    /// コンストラクタです。
    /// </summary>
    /// <param name="webRootFileProvider">
    /// デフォルトの wwwroot が設定されている WebRootFileProvider を指定します。通常は env.WebRootFileProvider を指定してください。
    /// これは追加した <see cref="StaticFileOptions"/> がヒットしなかった場合に使用するためです。
    /// </param>
    /// <param name="staticFileOptions">
    /// 追加した静的ファイルオプションの一覧です。
    /// FileProvider と RequestPath が設定されている必要があります。
    /// </param>
    public CompositeStaticFileOptionsProvider(IFileProvider webRootFileProvider, IEnumerable<StaticFileOptions> staticFileOptions)
    {
      _webRootFileProvider = webRootFileProvider ?? throw new ArgumentNullException(nameof(webRootFileProvider));
      _staticFileOptions = staticFileOptions;
    }

    /// <summary>
    /// 指定されたパスにあるディレクトリを列挙します(存在する場合)。
    /// </summary>
    /// <param name="subpath">ディレクトリを識別する相対パス。</param>
    /// <returns>ディレクトリの内容を返します。</returns>
    public IDirectoryContents GetDirectoryContents(string subpath)
    {
      var result = GetFileProvider(subpath);
      return result.FileProvider.GetDirectoryContents(result.StaticFileRelativePath);
    }

    /// <summary>
    /// 指定されたパスでファイルを見つけます。
    /// </summary>
    /// <param name="subpath">ファイルを識別する相対パス。</param>
    /// <returns>ファイル情報。 発信者はExistsプロパティを確認する必要があります。</returns>
    public IFileInfo GetFileInfo(string subpath)
    {
      var result = GetFileProvider(subpath);
      return result.FileProvider.GetFileInfo(result.StaticFileRelativePath);
    }

    /// <summary>
    /// 指定されたフィルターの Microsoft.Extensions.Primitives.IChangeToken を作成します。
    /// </summary>
    /// <param name="filter">監視するファイルまたはフォルダーを決定するために使用されるフィルター文字列。 例:**/*.cs、*.*、subFolder/**/*.cshtml。</param>
    /// <returns>ファイル一致フィルターが追加、変更、または削除されたときに通知される Microsoft.Extensions.Primitives.IChangeToken。</returns>
    public IChangeToken Watch(string filter)
    {
      var result = GetFileProvider(filter);
      return result.FileProvider.Watch(result.StaticFileRelativePath);
    }

    /// <summary>
    /// 指定された相対 URL に含まれる <see cref="StaticFileOptions"/> を探し、その FileProvider と静的ファイルへの相対パスを返します。
    /// 見つからなかった場合は wwwroot を持つ FileProvider を返します。
    /// </summary>
    /// <param name="path">アクセスされたホスト名以降の相対 URL。</param>
    /// <returns>検索された <see cref="StaticFileOptions"/> の FileProvider と RequestPath から静的ファイルへの相対パス。</returns>
    private (IFileProvider FileProvider, string StaticFileRelativePath) GetFileProvider(string path)
    {
      if (_staticFileOptions != null)
      {
        foreach (var option in _staticFileOptions)
        {
          // 登録している RequestPath とアクセスされた URL の大文字小文字が異なる場合があるので OrdinalIgnoreCase を指定
          if (path.StartsWith(option.RequestPath, StringComparison.OrdinalIgnoreCase))
          {
            return (option.FileProvider, path[option.RequestPath.Value.Length..]);
          }
        }
      }
      return (_webRootFileProvider, path);
    }
  }
}

Ponieważ jest długa, nie będę wyjaśniać szczegółów, ale krótko wyjaśnić, Po pierwsze, StaticFileOptions będę miał całą listę, którą stworzyłem w tej klasie. Ustawię tę klasę env.WebRootFileProvider na właściwość później.

Każda metoda jest wywoływana, gdy dostęp do klienta, więc wyszukaj, StaticFileOptions który plik statyczny, do którego uzyskujesz dostęp na podstawie adresu URL. Zwraca StaticFileOptions ścieżkę względną do pliku trafienia i FileProvider statycznego. Jeśli staticFileOptions nie zostanie trafiony, ustawienie wwwroot jest stosowane przez zwrócenie domyślnego FileProvider.

Zwracanie poprawnych informacji o pliku dla każdej operacji asp-append-version będzie odzwierciedlać atrybut.

Nawiasem mówiąc, ten kod może być wszędzie.

Zastosuj własną klasę (CompositeStaticFileOptionsProvider)

Startup.Configure Naprawmy to w następujący sposób: Jak napisano, nie ma nic do wyjaśnienia. StaticFileOptions Jestem po prostu podsumować je w tablicy.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  // 省略
  app.UseHttpsRedirection();
  
  // ここから修正
  
  var staticOptions = new StaticFileOptions[]
  {
    // Site1 用の物理コンテンツフォルダと参照 URL を紐づける
    new StaticFileOptions()
    {
      FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Areas/Site1/Content")),
      RequestPath = "/Site1",
    },
    // 複数ある場合はこんな感じで追加
    //new StaticFileOptions()
    //{
    //  FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Areas/Site2/Content")),
    //  RequestPath = "/Site2",
    //},
  };
  
  // wwwroot フォルダで静的ファイル参照を有効にする
  app.UseStaticFiles();
  
  // 追加したい StaticFileOptions
  foreach (var option in staticOptions)
  {
    app.UseStaticFiles(option);
  }
  
  // StaticFileOptions を独自クラスでまとめて WebRootFileProvider にセットする
  var compositeProvider = new CompositeStaticFileOptionsProvider(env.WebRootFileProvider, staticOptions);
  env.WebRootFileProvider = compositeProvider;
  
  // ここまで修正
  
  app.UseRouting();
  // 省略
}

Jeśli uruchomisz go teraz, zobaczysz, że atrybut jest odzwierciedlony w asp-append-version plikach statycznych umieszczonych w folderach innych niż wwwroot.