Aplicar asp-append-version además de los archivos estáticos en la carpeta wwwroot

Fecha de creación de la página :

medio ambiente

Estudio visual
  • Visual Studio 2019
Núcleo de ASP.NET
  • 3.1 (Página de Razor, MVC)

Los archivos estáticos colocados fuera de la carpeta wwwroot no reflejan asp-append-version

app.UseStaticFiles Al especificar una llamada adicional StaticFileOptions al método Los archivos estáticos también se pueden colocar en carpetas distintas de wwwroot. Sin embargo, para los archivos estáticos colocados fuera de la carpeta wwwroot, las etiquetas de enlace y script asp-append-version Establecer el atributo no agrega información de versión a la dirección URL.

Lo intentaré. Los archivos se organizan en las siguientes configuraciones:

Startup.Configure método para publicar también la carpeta Areas/Site1/Content.

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

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

Se ha agregado el código siguiente index.cshtml a . Se añaden cada asp-append-version uno.

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

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

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

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

Al ejecutarla, la imagen se muestra correctamente.

Sin embargo, si observa el CÓDIGO HTML de la página, puede ver que la cadena solo se expande a los archivos colocados en wwwroot.

Causas en las que asp-append-version no se refleja

Depende de la propiedad que determina si se refleja la versión env.WebRootFileProvider IFileProvider asp-append. De forma predeterminada, la wwwroot PhysicalFileProvider especificada se establece para que no se refleje en otras carpetas.

Hay una clase IFileProvider que puede tener más de CompositeFileProvider una Puedes empacar más de uno aquí PhysicalFileProvider y dárselo a env.WebRootFileProvider . Solo se puede pasar una ruta de carpeta física a la última, StaticFileOptions.RequestPath No es posible especificar más de uno, por lo que no creo que vaya a ser la acción prevista.

* env.WebRootFileProvider se recibe por Startup.Configure IWebHostEnvironment env método.

Herede IFileProvider y cree sus propias clases

ASP.NET fileProvider porque no puede ser compatible con características estándar solo en 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);
    }
  }
}

Debido a que es largo, no voy a explicar los detalles, pero para explicar brevemente, Primero, StaticFileOptions tendré toda la lista de la que creé en esta clase. Pondré esta clase env.WebRootFileProvider en una propiedad más tarde.

Un cliente llama a cada método, por lo que busque el archivo estático al StaticFileOptions que accedió en función de la dirección URL. Devuelve la StaticFileOptions ruta relativa al archivo estático y de FileProvider acceso. Si staticFileOptions no se alcanza, la configuración wwwroot se aplica devolviendo el FileProvider predeterminado.

Devolver la información de archivo correcta para cada operación asp-append-version reflejará el atributo.

Por cierto, este código puede estar en cualquier lugar.

Aplique su propia clase (CompositeStaticFileOptionsProvider)

Startup.Configure Vamos a arreglarlo de la siguiente manera: Como está escrito, no hay nada que explicar. StaticFileOptions Sólo los estoy resumiendo en una matriz.

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

Si lo ejecuta ahora, puede ver que el atributo se refleja en archivos asp-append-version estáticos colocados en carpetas distintas de wwwroot.