Použití asp-append-version kromě statických souborů ve složce wwwroot

Datum vytvoření stránky :

Prostředí

Visual Studio
  • Visual Studio 2019
ASP.NET jádro
  • 3.1 (Stránka břitvy, MVC)

Statické soubory umístěné mimo složku wwwroot neodrážejí asp-append-version

app.UseStaticFiles Zadáním dalšího StaticFileOptions volání metody Statické soubory lze také umístit do jiných složek než wwwroot. U statických souborů umístěných mimo složku wwwroot však spojovací a skriptovací značky asp-append-version Nastavení atributu nepřidá informace o verzi na adresu URL.

Zkusím to. Soubory jsou uspořádány v následujících konfiguracích:

Startup.Configure také publikovat složku Oblasti/Web1/Obsah.

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

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

Do aplikace index.cshtml byl přidán následující kód. Každý asp-append-version z nich je přidán.

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

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

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

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

Při spuštění se obraz zobrazí správně.

Pokud se však podíváte na kód HTML stránky, uvidíte, že řetězec je rozbalen pouze na soubory umístěné v adresáři wwwroot.

Příčiny, kdy se neodráží verze asp-append

Záleží na vlastnosti, která určuje, zda se verze asp-append env.WebRootFileProvider IFileProvider odráží. Ve výchozím nastavení je zadaná PhysicalFileProvider webová_složka nastavena tak, aby se neodrážela v jiných složkách.

Existuje třída, IFileProvider která může mít více než CompositeFileProvider jednu Zde si můžete zabalit více než jeden PhysicalFileProvider a dát jej společnosti env.WebRootFileProvider . Do poslední cesty lze předávat pouze cestu fyzické složky. StaticFileOptions.RequestPath Není možné specifikovat více než jeden, takže si nemyslím, že to bude zamýšlená akce.

* env.WebRootFileProvider je Startup.Configure přijata IWebHostEnvironment env metodou.

Zdědit IFileProvider a vytvořit si vlastní třídy

ASP.NET fileProvider, protože nemůže být podporován standardními funkcemi pouze v jádru.

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);
    }
  }
}

Protože je to dlouhé, nevysvětlím detaily, ale stručně vysvětlím, Nejdřív StaticFileOptions budu mít seznam toho, co jsem vytvořil v této třídě. Dám tuhle třídu na env.WebRootFileProvider pozemek později.

Každá metoda je volána při přístupu klienta, takže vyhledejte, StaticFileOptions ke kterému statickému souboru jste přistupovali na základě adresy URL. Vrátí relativní StaticFileOptions cestu k souboru, který byl zasažen, a FileProvider statickému souboru. Pokud staticFileOptions není zasažen, nastavení wwwroot se použije vrácením výchozího FileProvider.

Vrácení správných informací o souboru pro každou asp-append-version operaci bude odrážet atribut.

Mimochodem, tento kód může být kdekoli.

Použijte vlastní třídu (CompositeStaticFileOptionsProvider)

Startup.Configure Opravme to takto: Jak bylo napsáno, není co vysvětlovat. StaticFileOptions Jen je shrnuji do pole.

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();
  // 省略
}

Pokud jej nyní spusťte, uvidíte, že se atribut odráží ve statických souborech asp-append-version umístěných v jiných složkách než wwwroot.