Applicare asp-append-version oltre ai file statici nella cartella wwwroot

Data di creazione della pagina :

ambiente

Visual Studio
  • Visual Studio 2019
ASP.NET Nucleo
  • 3.1 (pagina Razor, MVC)

I file statici posizionati all'esterno della cartella wwwroot non riflettono asp-append-version

app.UseStaticFiles Specificando una chiamata StaticFileOptions aggiuntiva al metodo I file statici possono anche essere inseriti in cartelle diverse da wwwroot. Tuttavia, per i file statici posizionati all'esterno della cartella wwwroot, dei tag di collegamento e script asp-append-version L'impostazione dell'attributo non aggiunge informazioni sulla versione all'URL.

Ci proverò. I file sono disposti nelle configurazioni seguenti:

Startup.Configure per pubblicare anche la cartella Aree/Sito1/Contenuto.

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

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

Il codice index.cshtml seguente è stato aggiunto a . Ognuno asp-append-version viene aggiunto.

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

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

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

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

Quando la si esegue, l'immagine viene visualizzata correttamente.

Tuttavia, se si esamina il codice HTML della pagina, è possibile vedere che la stringa viene espansa solo ai file inseriti in wwwroot.

Causa quando asp-append-version non viene riflessa

Dipende dalla proprietà che determina se la versione asp-append viene env.WebRootFileProvider IFileProvider riflessa. Per impostazione predefinita, il codice wwwroot PhysicalFileProvider specificato viene impostato in modo che non si rifletta in altre cartelle.

C'è una IFileProvider classe che può avere più di CompositeFileProvider una Puoi imballare più di uno PhysicalFileProvider qui e darlo a env.WebRootFileProvider . Solo un percorso di cartella fisica può essere passato all'ultimo, StaticFileOptions.RequestPath Non è possibile specificarne più di uno, quindi non credo che sarà l'azione prevista.

* env.WebRootFileProvider viene ricevuto per Startup.Configure IWebHostEnvironment env metodo.

Ereditare IFileProvider e creare classi personalizzate

ASP.NET fileProvider perché non può essere supportato da funzionalità standard solo in Core.

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

Perché è lungo, non spiegherò i dettagli, ma per spiegare brevemente, Innanzitutto, StaticFileOptions avrò tutta la lista di ciò che ho creato in questa classe. Ho impostato questa classe su una env.WebRootFileProvider proprietà più tardi.

Ogni metodo viene chiamato quando si accede da un client, quindi cercare il StaticFileOptions file statico a cui si accede in base all'URL. Restituisce StaticFileOptions il percorso relativo al file hit e FileProvider static. Se staticFileOptions non viene raggiunto, l'impostazione wwwroot viene applicata restituendo il FileProvider predefinito.

La restituzione delle informazioni corrette sul file per ogni operazione asp-append-version rifletterà l'attributo.

A proposito, questo codice può essere ovunque.

Applicare una classe personalizzata (CompositeStaticFileOptionsProvider)

Startup.Configure Risolviamolo come segue: Come scritto, non c'è nulla da spiegare. StaticFileOptions Li sto solo riassumendo in un array.

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

Se lo si esegue ora, è possibile vedere che l'attributo viene riflesso in file asp-append-version statici inseriti in cartelle diverse da wwwroot.