wwwroot 폴더의 정적 파일 외에 ASP 추가 버전 적용

페이지 생성 날짜 :

환경

비주얼 스튜디오
  • 비주얼 스튜디오 2019
ASP.NET 코어
  • 3.1 (면도기 페이지, MVC)

wwwroot 폴더 외부에 배치된 정적 파일은 asp-부속 버전을 반영하지 않습니다.

app.UseStaticFiles 메서드에 대한 추가 StaticFileOptions 호출을 지정하여 정적 파일은 wwwroot 이외의 폴더에 배치할 수도 있습니다. 그러나 wwwroot 폴더 외부에 배치된 정적 파일의 경우 링크 및 스크립트 태그가 있습니다. asp-append-version 특성을 설정 해도 URL에 버전 정보가 추가되지 않습니다.

나는 그것을 시도 줄 것이다. 파일은 다음 구성으로 정렬됩니다.

Startup.Configure 또한 영역/사이트1/콘텐츠 폴더를 게시하는 방법입니다.

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

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

다음 index.cshtml 코드가 추가되었습니다. 각각이 asp-append-version 추가됩니다.

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

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

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

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

실행하면 이미지가 올바르게 표시됩니다.

그러나 페이지의 HTML을 보면 문자열이 wwwroot에 배치된 파일로만 확장되는 것을 볼 수 있습니다.

asp-부속 버전이 반영되지 않은 원인

asp-부속 버전이 반영되는지 여부를 결정하는 속성에 따라 env.WebRootFileProvider IFileProvider 다릅니다. 기본적으로 PhysicalFileProvider 지정된 wwwroot가 다른 폴더에 반영되지 않도록 설정됩니다.

하나 이상의 IFileProvider 클래스를 가질 수 있습니다. CompositeFileProvider 여기에 하나 이상의 PhysicalFileProvider 팩을 하고 줄 수 env.WebRootFileProvider 있습니다. 물리적 폴더 경로만 마지막 경로로 전달할 수 있습니다. StaticFileOptions.RequestPath 하나 이상을 지정할 수 없으므로 의도된 작업이 될 것이라고 생각하지 않습니다.

env.WebRootFileProvider Startup.Configure 방법으로 수신 IWebHostEnvironment env 됩니다.

IFile공급자상속 및 사용자 고유의 클래스 만들기

ASP.NET 파일 공급자는 코어의 표준 기능만으로는 지원할 수 없기 때문입니다.

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

길기 때문에 세부 사항을 설명하지 않고 간단히 설명합니다. 첫째, StaticFileOptions 이 클래스에서 만든 모든 목록을 갖게 됩니다. 나중에 이 env.WebRootFileProvider 클래스를 속성으로 설정합니다.

각 메서드는 클라이언트에서 액세스할 때 호출되므로 StaticFileOptions URL을 기반으로 액세스한 정적 파일을 검색합니다. 상대 StaticFileOptions 경로를 적중 및 정적 FileProvider 파일로 반환합니다. staticFileOptions가 맞지 않으면 기본 FileProvider를 반환하여 wwwroot 설정이 적용됩니다.

각 작업에 대한 올바른 파일 정보를 asp-append-version 반환하면 특성이 반영됩니다.

그런데 이 코드는 어디에나 있을 수 있습니다.

자신의 클래스 적용 (합성 정적파일옵션공급자)

Startup.Configure 다음과 같이 수정해 보겠습니다. 서면으로 설명할 것이 없습니다. StaticFileOptions 난 그냥 배열에 그들을 요약.

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

지금 실행하면 특성이 wwwroot 이외의 폴더에 배치된 정적 파일에 반영되는 것을 볼 수 asp-append-version 있습니다.