다음을 통해 공유


ASP.NET Core 호스팅 Blazor WebAssembly 앱의 배포 레이아웃

비고

이 기사는 최신 버전이 아닙니다. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

경고

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

중요합니다

이 정보는 사전 출시 제품과 관련이 있으며, 상업적으로 출시되기 전에 상당히 수정될 수 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적이거나 묵시적인 보증도 하지 않습니다.

현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.

이 문서에서는 DLL(동적 연결 라이브러리) 파일의 다운로드 및 실행을 차단하는 환경에서 호스팅 Blazor WebAssembly 된 배포를 사용하도록 설정하는 방법을 설명합니다.

비고

이 지침은 클라이언트가 DLL을 다운로드하고 실행하지 못하도록 차단하는 환경을 다룹니다. .NET 8 이상 Blazor 에서는 웹실 파일 형식을 사용하여 이 문제를 해결합니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 호스트 및 배포를 참조하세요. 이 문서에서 설명하는 실험적 NuGet 패키지를 사용하는 멀티파트 번들링은 .NET 8 이상의 앱에서는 Blazor 지원되지 않습니다. 이 문서의 지침을 사용하여 .NET 8 이상용 고유한 멀티파트 번들링 NuGet 패키지를 만들 수 있습니다.

Blazor WebAssembly 앱이 작동하려면 DLL(동적 연결 라이브러리)이 필요하지만 일부 환경에서는 클라이언트가 DLL을 다운로드하고 실행할 수 없습니다. 보안 제품은 종종 네트워크를 통과하는 파일의 내용을 검사하고 DLL 파일을 차단하거나 격리할 수 있습니다. 이 문서에서는 보안 제한을 우회하여 DLL을 함께 다운로드할 수 있도록 앱의 DLL에서 멀티파트 번들 파일이 만들어지는 이러한 환경에서 앱을 사용하도록 설정하는 Blazor WebAssembly 한 가지 방법을 설명합니다.

Blazor WebAssembly 앱이 작동하려면 DLL(동적 연결 라이브러리)이 필요하지만 일부 환경에서는 클라이언트가 DLL을 다운로드하고 실행할 수 없습니다. 이러한 환경의 하위 집합에서는 DLL 파일(.dll)의 파일 이름 확장명을 변경하는 것만 으로도 보안 제한을 우회할 수 있지만 보안 제품은 네트워크를 통과하는 파일의 내용을 검사하고 DLL 파일을 차단하거나 격리할 수 있는 경우가 많습니다. 이 문서에서는 보안 제한을 우회하여 DLL을 함께 다운로드할 수 있도록 앱의 DLL에서 멀티파트 번들 파일이 만들어지는 이러한 환경에서 앱을 사용하도록 설정하는 Blazor WebAssembly 한 가지 방법을 설명합니다.

호스팅 Blazor WebAssembly 된 앱은 다음 기능을 사용하여 게시된 파일 및 앱 DLL의 패키징을 사용자 지정할 수 있습니다.

  • 부팅 프로세스를 사용자 지정할 수 있는 JavaScript 이니셜라이저입니다Blazor.
  • 게시된 파일 목록을 변환하고 게시 확장을 정의Blazor하기 위한 MSBuild 확장성. Blazor 게시 확장은 게시된 Blazor WebAssembly 앱을 실행하는 데 필요한 파일 집합에 대한 대체 표현을 제공하는 게시 프로세스 중에 정의된 파일입니다. 이 문서에서는 Blazor DLL을 함께 다운로드할 수 있도록 앱의 모든 DLL이 단일 파일로 압축된 멀티파트 번들을 생성하는 게시 확장을 만듭니다.

이 문서에서 설명하는 방법은 개발자가 자신의 전략과 사용자 지정 로드 프로세스를 고안할 수 있는 시작점 역할을 합니다.

경고

보안 제한을 우회하기 위해 취하는 모든 접근 방식은 보안에 미치는 영향을 신중하게 고려해야 합니다. 이 문서의 접근 방식을 채택하기 전에 조직의 네트워크 보안 전문가와 함께 이 주제를 자세히 살펴보는 것이 좋습니다. 고려해야 할 대안은 다음과 같습니다.

  • 보안 어플라이언스 및 보안 소프트웨어를 사용하여 네트워크 클라이언트가 앱에 필요한 정확한 파일을 다운로드하고 사용할 수 있도록 Blazor WebAssembly 합니다.
  • Blazor WebAssembly 호스팅 모델에서 호스팅 모델로Blazor Server 전환하면 서버에서 앱의 모든 C# 코드가 유지 관리되고 DLL을 클라이언트에 다운로드할 필요가 없습니다. Blazor Server 또한 앱에서 C# 코드 개인 정보 보호를 위해 웹 API 앱을 사용할 필요 없이 C# 코드를 비공개로 유지할 수 있는 Blazor WebAssembly 이점을 제공합니다.

실험적 NuGet 패키지 및 샘플 앱

이 문서에 설명된 방법은 .NET 6 이상을 대상으로 하는 앱의 NuGet.org( 실험적Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle 패키지) 에서 사용됩니다. 패키지에는 게시 출력을 사용자 지정 Blazor 하기 위한 MSBuild 대상과 사용자 지정 부팅 리소스 로더를 사용하도록 JavaScript 이니셜라이저가 포함되어 있으며, 각각은 이 문서의 뒷부분에 자세히 설명되어 있습니다.

경고

실험적 및 미리 보기 기능은 피드백을 수집하기 위해 제공되며 프로덕션 용도로는 지원되지 않습니다.

이 문서의 뒷부분에 있는 세 개의 하위 섹션이 있는 NuGet 패키지를 통해 로드 프로세스 사용자 지정 Blazor WebAssembly 섹션에서는 패키지의 구성 및 코드에 Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle 대한 자세한 설명을 제공합니다. 자세한 설명은 앱에 대한 Blazor WebAssembly 고유한 전략 및 사용자 지정 로드 프로세스를 만들 때 이해하는 것이 중요합니다. 사용자 지정 없이 게시된 실험적이고 지원되지 않는 NuGet 패키지를 로컬 데모로 사용하려면 다음 단계를 수행합니다.

  1. 기존 호스팅 Blazor WebAssembly 된 솔루션을 사용하거나 Visual Studio를 사용하거나 ()Blazor WebAssembly 명령에 옵션을 전달-ho|--hosted하여 프로젝트 템플릿에서 dotnet new 새 솔루션을 만듭니다.dotnet new blazorwasm -ho 자세한 내용은 ASP.NET Core용 도구를 참조하세요 Blazor.

  2. Client 프로젝트에서 실험적 Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle 패키지를 추가합니다.

    비고

    .NET 앱에 패키지를 추가하는 방법에 대한 지침은 패키지 사용 작업 흐름(NuGet 문서)패키지 설치 및 관리 섹션에서 확인할 수 있습니다. 올바른 패키지 버전을 NuGet.org에서 확인하세요.

  3. Server 프로젝트에서 번들 파일()app.bundle을 제공하기 위한 엔드포인트를 추가합니다. 예제 코드는 이 문서의 호스트 서버 앱에서 번들 제공 섹션에서 찾을 수 있습니다.

  4. 릴리스 구성에 앱을 게시합니다.

NuGet 패키지를 통해 로딩 프로세스 사용자 지정Customize the Blazor WebAssembly loading process via a NuGet package

경고

세 개의 하위 섹션이 있는 이 섹션의 지침은 고유한 전략 및 사용자 지정 로드 프로세스를 구현하기 위해 처음부터 NuGet 패키지를 빌드하는 것과 관련이 있습니다. .NET 6 및 7에 대한 NuGet.org(실험적Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle 패키지) 는 이 섹션의 지침을 기반으로 합니다. 멀티파트 번들 다운로드 방법의 로컬 데모 에서 제공된 패키지를 사용하는 경우 이 섹션의 지침을 따를 필요가 없습니다. 제공된 패키지를 사용하는 방법에 대한 지침은 실험적 NuGet 패키지 및 샘플 앱 섹션을 참조하세요.

Blazor 앱 리소스는 멀티파트 번들 파일로 압축되고 사용자 지정 JavaScript(JS) 이니셜라이저를 통해 브라우저에 의해 로드됩니다. 이니셜라이저와 함께 JS 패키지를 사용하는 앱의 경우 앱은 요청 시 번들 파일만 제공하면 됩니다. 이 방법의 다른 모든 측면은 투명하게 처리됩니다.

기본 게시된 Blazor 앱을 로드하는 방법에는 4가지 사용자 지정이 필요합니다.

  • 게시 파일을 변환하는 MSBuild 작업입니다.
  • 게시 프로세스에 연결 Blazor 하고, 출력을 변환하고, 하나 이상의 Blazor 게시 확장 파일(이 경우 단일 번들)을 정의하는 MSBuild 대상이 있는 NuGet 패키지입니다.
  • JS 리소스 로더 콜백을 Blazor WebAssembly 업데이트하여 번들을 로드하고 앱에 개별 파일을 제공하는 이니셜라이저입니다.
  • 요청 시 번들이 클라이언트에 제공되도록 하는 호스트 Server 앱의 도우미입니다.

MSBuild 작업을 만들어 게시된 파일 목록을 사용자 지정하고 새 확장명을 정의합니다

MSBuild 컴파일의 일부로 가져올 수 있고 빌드와 상호 작용할 수 있는 공용 C# 클래스로 MSBuild 작업을 만듭니다.

C# 클래스에는 다음이 필요합니다.

비고

이 문서의 예제에 대한 NuGet 패키지는 Microsoft Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle에서 제공하는 패키지의 이름을 따서 명명되었습니다. 사용자 고유의 NuGet 패키지 이름을 지정하고 생성하는 방법에 대한 지침은 다음 NuGet 문서를 참조하세요.

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Build.Framework" Version="{VERSION}" />
    <PackageReference Include="Microsoft.Build.Utilities.Core" Version="{VERSION}" />
  </ItemGroup>

</Project>

NuGet.org 에서 자리 표시자에 대한 {VERSION} 최신 패키지 버전을 확인합니다.

MSBuild 작업을 만들려면 확장(not Microsoft.Build.Utilities.Task)하는 공용 C# 클래스를 System.Threading.Tasks.Task 만들고 세 가지 속성을 선언합니다.

  • PublishBlazorBootStaticWebAsset: 앱용으로 Blazor 게시할 파일 목록입니다.
  • BundlePath: 번들이 작성되는 경로입니다.
  • Extension: 빌드에 포함할 새 게시 확장입니다.

다음 예제 BundleBlazorAssets 클래스는 추가 사용자 지정을 위한 시작점입니다.

  • Execute 메서드에서 번들은 다음 세 가지 파일 형식으로 만들어집니다.
    • 자바스크립트 파일(dotnet.js)
    • WASM 파일 ()dotnet.wasm
    • 앱 DLL(.dll)
  • 번들이 multipart/form-data 만들어집니다. 각 파일은 Content-Disposition 헤더Content-Type 헤더를 통해 해당 설명과 함께 번들에 추가됩니다.
  • 번들이 만들어지면 번들이 파일에 기록됩니다.
  • 빌드는 확장에 대해 구성됩니다. 다음 코드는 확장 항목을 만들어 속성에 추가합니다 Extension . 각 확장 항목에는 세 가지 데이터가 포함됩니다.
    • 확장 파일의 경로입니다.
    • 앱의 루트를 기준으로 하는 URL 경로입니다 Blazor WebAssembly .
    • 지정된 확장에서 생성된 파일을 그룹화하는 확장의 이름입니다.

앞의 목표를 달성한 후 게시 출력을 사용자 지정 Blazor 하기 위한 MSBuild 작업이 만들어집니다. Blazor 에서는 확장 프로그램을 수집하고 확장 프로그램이 게시 출력 폴더의 올바른 위치(예: bin\Release\net6.0\publish)에 복사되었는지 확인합니다. 다른 파일에 적용되는 것과 동일한 Blazor 최적화(예: 압축)가 JavaScript, WASM 및 DLL 파일에 적용됩니다.

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks/BundleBlazorAssets.cs:

using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks
{
    public class BundleBlazorAssets : Task
    {
        [Required]
        public ITaskItem[]? PublishBlazorBootStaticWebAsset { get; set; }

        [Required]
        public string? BundlePath { get; set; }

        [Output]
        public ITaskItem[]? Extension { get; set; }

        public override bool Execute()
        {
            var bundle = new MultipartFormDataContent(
                "--0a7e8441d64b4bf89086b85e59523b7d");

            foreach (var asset in PublishBlazorBootStaticWebAsset)
            {
                var name = Path.GetFileName(asset.GetMetadata("RelativePath"));
                var fileContents = File.OpenRead(asset.ItemSpec);
                var content = new StreamContent(fileContents);
                var disposition = new ContentDispositionHeaderValue("form-data");
                disposition.Name = name;
                disposition.FileName = name;
                content.Headers.ContentDisposition = disposition;
                var contentType = Path.GetExtension(name) switch
                {
                    ".js" => "text/javascript",
                    ".wasm" => "application/wasm",
                    _ => "application/octet-stream"
                };
                content.Headers.ContentType = 
                    MediaTypeHeaderValue.Parse(contentType);
                bundle.Add(content);
            }

            using (var output = File.Open(BundlePath, FileMode.OpenOrCreate))
            {
                output.SetLength(0);
                bundle.CopyToAsync(output).ConfigureAwait(false).GetAwaiter()
                    .GetResult();
                output.Flush(true);
            }

            var bundleItem = new TaskItem(BundlePath);
            bundleItem.SetMetadata("RelativePath", "app.bundle");
            bundleItem.SetMetadata("ExtensionName", "multipart");

            Extension = new ITaskItem[] { bundleItem };

            return true;
        }
    }
}

NuGet 패키지를 작성하여 게시 출력을 자동으로 변환합니다.

패키지가 참조될 때 자동으로 포함되는 MSBuild 대상을 사용하여 NuGet 패키지를 생성합니다.

  • 새Razor RCL(클래스 라이브러리) 프로젝트를 만듭니다.
  • NuGet 규칙에 따라 대상 파일을 만들어 사용 프로젝트에서 패키지를 자동으로 가져옵니다. 예를 들어, create build\net6.0\{PACKAGE ID}.targets{PACKAGE ID} 패키지의 패키지 식별자입니다.
  • MSBuild 작업이 포함된 클래스 라이브러리에서 출력을 수집하고 출력이 올바른 위치에 압축되어 있는지 확인합니다.
  • 파이프라인에 연결하는 Blazor 데 필요한 MSBuild 코드를 추가하고 MSBuild 작업을 호출하여 번들을 생성합니다.

이 섹션에서 설명하는 방법은 패키지를 사용하여 대상과 콘텐츠를 전달하는 데만 사용되며, 이는 패키지에 라이브러리 DLL이 포함된 대부분의 패키지와 다릅니다.

경고

이 섹션에 설명된 샘플 패키지는 게시 프로세스를 사용자 지정하는 Blazor 방법을 보여 줍니다. 샘플 NuGet 패키지는 로컬 데모로만 사용할 수 있습니다. 프로덕션에서 이 패키지를 사용하는 것은 지원되지 않습니다.

비고

이 문서의 예제에 대한 NuGet 패키지는 Microsoft Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle에서 제공하는 패키지의 이름을 따서 명명되었습니다. 사용자 고유의 NuGet 패키지 이름을 지정하고 생성하는 방법에 대한 지침은 다음 NuGet 문서를 참조하세요.

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.csproj:

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <NoWarn>NU5100</NoWarn>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <Description>
      Sample demonstration package showing how to customize the Blazor publish 
      process. Using this package in production is not supported!
    </Description>
    <IsPackable>true</IsPackable>
    <IsShipping>true</IsShipping>
    <IncludeBuildOutput>false</IncludeBuildOutput>
  </PropertyGroup>

  <ItemGroup>
    <None Update="build\**" 
          Pack="true" 
          PackagePath="%(Identity)" />
    <Content Include="_._" 
             Pack="true" 
             PackagePath="lib\net6.0\_._" />
  </ItemGroup>

  <Target Name="GetTasksOutputDlls" 
          BeforeTargets="CoreCompile">
    <MSBuild Projects="..\Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks\Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks.csproj" 
             Targets="Publish;PublishItemsOutputGroup" 
             Properties="Configuration=Release">
      <Output TaskParameter="TargetOutputs" 
              ItemName="_TasksProjectOutputs" />
    </MSBuild>
    <ItemGroup>
      <Content Include="@(_TasksProjectOutputs)" 
               Condition="'%(_TasksProjectOutputs.Extension)' == '.dll'" 
               Pack="true" 
               PackagePath="tasks\%(_TasksProjectOutputs.TargetPath)" 
               KeepMetadata="Pack;PackagePath" />
    </ItemGroup>
  </Target>

</Project>

비고

<NoWarn>NU5100</NoWarn> 이전 예제의 속성은 폴더에 배치된 tasks 어셈블리에 대한 경고를 표시하지 않습니다. 자세한 내용은 NuGet 경고 NU5100을 참조하세요.

.targets MSBuild 작업을 빌드 파이프라인에 연결하는 파일을 추가합니다. 이 파일에서는 다음과 같은 목표를 달성합니다.

  • 작업을 빌드 프로세스로 가져옵니다. DLL의 경로는 패키지에 있는 파일의 최종 위치를 기준으로 합니다.
  • ComputeBlazorExtensionsDependsOn 속성은 사용자 지정 대상을 파이프라인에 Blazor WebAssembly 연결합니다.
  • 작업 출력에서 Extension 속성을 캡처하고 확장에 대해 알리 BlazorPublishExtension 기 위해 추가합니다Blazor. 대상에서 작업을 호출하면 번들이 생성됩니다. 게시된 파일 목록은 항목 그룹의 파이프라인 Blazor WebAssembly 에서 PublishBlazorBootStaticWebAsset 제공됩니다. 번들 경로는 (일반적으로 폴더 내부)를 IntermediateOutputPath 사용하여 obj 정의됩니다. 궁극적으로 번들은 게시 출력 폴더의 올바른 위치(예: bin\Release\net6.0\publish)에 자동으로 복사됩니다.

패키지가 참조되면 게시하는 동안 파일 번들이 Blazor 생성됩니다.

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle/build/net6.0/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.targets:

<Project>
  <UsingTask 
    TaskName="Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks.BundleBlazorAssets" 
    AssemblyFile="$(MSBuildThisProjectFileDirectory)..\..\tasks\Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.Tasks.dll" />

  <PropertyGroup>
    <ComputeBlazorExtensionsDependsOn>
      $(ComputeBlazorExtensionsDependsOn);_BundleBlazorDlls
    </ComputeBlazorExtensionsDependsOn>
  </PropertyGroup>

  <Target Name="_BundleBlazorDlls">
    <BundleBlazorAssets
      PublishBlazorBootStaticWebAsset="@(PublishBlazorBootStaticWebAsset)"
      BundlePath="$(IntermediateOutputPath)bundle.multipart">
      <Output TaskParameter="Extension" 
              ItemName="BlazorPublishExtension"/>
    </BundleBlazorAssets>
  </Target>

</Project>

번들에서 자동으로 부트스트랩 Blazor

NuGet 패키지는 JavaScript(JS) 이니셜라이저 를 활용하여 개별 DLL 파일을 사용하는 대신 번들에서 앱을 자동으로 부트스트랩 Blazor WebAssembly 합니다. JS이니셜라이저는 Blazor를 변경하고 번들을 사용하는 데 사용됩니다.

이니셜라이저를 JS 만들려면 패키지 프로젝트의 폴더에 이름이 JS{NAME}.lib.module.js 있는 파일을 추가합니다wwwroot. {NAME} 여기서 자리 표시자는 패키지 식별자입니다. 예를 들어 Microsoft 패키지의 파일 이름은 Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. 내보낸 함수 beforeWebAssemblyStartafterWebAssemblyStarted 핸들로딩.

이니셜라이저는 다음과 같습니다 JS .

  • extensions.multipart 제공된 확장 이름()ExtensionName인 를 확인하여 게시 확장을 사용할 수 있는지 확인합니다.
  • 번들을 다운로드하고 생성된 개체 URL을 사용하여 내용을 리소스 맵으로 구문 분석합니다.
  • boot resource loader (options.loadBootResource)를 개체 URL을 사용하여 리소스를 해결하는 사용자 지정 함수로 업데이트합니다.
  • 앱이 시작된 후 개체 URL을 해지하여 함수의 메모리를 해제합니다 afterWebAssemblyStarted .

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle/wwwroot/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js:

const resources = new Map();

export async function beforeWebAssemblyStart(options, extensions) {
  if (!extensions || !extensions.multipart) {
    return;
  }

  try {
    const integrity = extensions.multipart['app.bundle'];
    const bundleResponse = 
      await fetch('app.bundle', { integrity: integrity, cache: 'no-cache' });
    const bundleFromData = await bundleResponse.formData();
    for (let value of bundleFromData.values()) {
      resources.set(value, URL.createObjectURL(value));
    }
    options.loadBootResource = function (type, name, defaultUri, integrity) {
      return resources.get(name) ?? null;
    }
  } catch (error) {
    console.log(error);
  }
}

export async function afterWebAssemblyStarted(blazor) {
  for (const [_, url] of resources) {
    URL.revokeObjectURL(url);
  }
}

이니셜라이저를 JS 만들려면 패키지 프로젝트의 폴더에 이름이 JS{NAME}.lib.module.js 있는 파일을 추가합니다wwwroot. {NAME} 여기서 자리 표시자는 패키지 식별자입니다. 예를 들어 Microsoft 패키지의 파일 이름은 Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. 내보낸 함수 beforeStartafterStarted 핸들로딩.

이니셜라이저는 다음과 같습니다 JS .

  • extensions.multipart 제공된 확장 이름()ExtensionName인 를 확인하여 게시 확장을 사용할 수 있는지 확인합니다.
  • 번들을 다운로드하고 생성된 개체 URL을 사용하여 내용을 리소스 맵으로 구문 분석합니다.
  • boot resource loader (options.loadBootResource)를 개체 URL을 사용하여 리소스를 해결하는 사용자 지정 함수로 업데이트합니다.
  • 앱이 시작된 후 개체 URL을 해지하여 함수의 메모리를 해제합니다 afterStarted .

Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle/wwwroot/Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js:

const resources = new Map();

export async function beforeStart(options, extensions) {
  if (!extensions || !extensions.multipart) {
    return;
  }

  try {
    const integrity = extensions.multipart['app.bundle'];
    const bundleResponse = 
      await fetch('app.bundle', { integrity: integrity, cache: 'no-cache' });
    const bundleFromData = await bundleResponse.formData();
    for (let value of bundleFromData.values()) {
      resources.set(value, URL.createObjectURL(value));
    }
    options.loadBootResource = function (type, name, defaultUri, integrity) {
      return resources.get(name) ?? null;
    }
  } catch (error) {
    console.log(error);
  }
}

export async function afterStarted(blazor) {
  for (const [_, url] of resources) {
    URL.revokeObjectURL(url);
  }
}

호스트 서버 앱에서 번들 제공

보안 제한으로 인해 ASP.NET Core는 app.bundle 파일을 제공하지 않습니다. 요청 처리 도우미는 클라이언트에서 요청할 때 파일을 제공하는 데 필요합니다.

비고

동일한 최적화가 앱의 파일에 app.bundle.gz 적용되는 Publish Extensions에 투명하게 적용되기 때문에 압축 app.bundle.br 된 에셋 파일은 게시 시 자동으로 생성됩니다.

프로젝트의 C# 코드를 Program.csServer 대체 파일을 (index.html)로 app.MapFallbackToFile("index.html"); 설정하는 줄 바로 앞에 배치하여 번들 파일에 대한 요청에 응답합니다(예: app.bundle).

app.MapGet("app.bundle", (HttpContext context) =>
{
    string? contentEncoding = null;
    var contentType = 
        "multipart/form-data; boundary=\"--0a7e8441d64b4bf89086b85e59523b7d\"";
    var fileName = "app.bundle";

    var acceptEncodings = context.Request.Headers.AcceptEncoding;

    if (Microsoft.Net.Http.Headers.StringWithQualityHeaderValue
        .StringWithQualityHeaderValue
        .TryParseList(acceptEncodings, out var encodings))
    {
        if (encodings.Any(e => e.Value == "br"))
        {
            contentEncoding = "br";
            fileName += ".br";
        }
        else if (encodings.Any(e => e.Value == "gzip"))
        {
            contentEncoding = "gzip";
            fileName += ".gz";
        }
    }

    if (contentEncoding != null)
    {
        context.Response.Headers.ContentEncoding = contentEncoding;
    }

    return Results.File(
        app.Environment.WebRootFileProvider.GetFileInfo(fileName)
            .CreateReadStream(), contentType);
});

콘텐츠 형식은 빌드 작업에서 이전에 정의한 형식과 일치합니다. 엔드포인트는 브라우저에서 허용하는 콘텐츠 인코딩을 확인하고 최적의 파일인 Brotli(.br) 또는 Gzip(.gz)을 제공합니다.