Udostępnij za pośrednictwem


Układ wdrożenia aplikacji ASP.NET Core hostowanych w Blazor WebAssembly

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualnym wydaniem, zobacz wersję tego artykułu dla platformy .NET 9.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z aktualnym wydaniem, zobacz wersję tego artykułu dla platformy .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, wyraźnych ani domniemanych, w odniesieniu do podanych tutaj informacji.

Aby zapoznać się z aktualnym wydaniem, zobacz wersję tego artykułu dla platformy .NET 9.

W tym artykule wyjaśniono, jak włączyć Blazor WebAssembly hostowane wdrożenia w środowiskach, które blokują pobieranie i wykonywanie plików biblioteki DLL.

Uwaga

Te wskazówki dotyczą środowisk, które blokują klientom pobieranie i wykonywanie bibliotek DLL. W programie .NET 8 lub nowszym Blazor format pliku Webcil jest używany do rozwiązania tego problemu. Aby uzyskać więcej informacji, zobacz Host and deploy ASP.NET Core Blazor WebAssembly. Tworzenie pakietów wielopartowych przy użyciu eksperymentalnego pakietu NuGet opisanego w tym artykule nie jest obsługiwane w przypadku Blazor aplikacji na platformie .NET 8 lub nowszej. Skorzystaj ze wskazówek w tym artykule, aby utworzyć własny wieloczęściowy pakiet NuGet dla platformy .NET 8 lub nowszej.

Blazor WebAssembly aplikacje wymagają, aby biblioteki linków dynamicznych (DLL) działały, ale niektóre środowiska blokują klientom pobieranie i wykonywanie bibliotek DLL. W podzestawie tych środowisk zmiana rozszerzenia nazwy pliku plików DLL (.dll) jest wystarczająca do obejścia ograniczeń zabezpieczeń, ale produkty zabezpieczeń są często w stanie skanować zawartość plików przechodzących przez sieć i zablokować lub poddać kwarantannie pliki DLL. W tym artykule opisano jedno podejście do włączania aplikacji Blazor WebAssembly w tych środowiskach, gdzie tworzony jest plik pakietu wieloczęściowego z bibliotek DLL aplikacji, aby można było je pobrać razem, omijając ograniczenia zabezpieczeń.

Blazor WebAssembly Hostowana aplikacja może dostosować opublikowane pliki i pakowanie bibliotek DLL aplikacji przy użyciu następujących funkcji:

  • Inicjatory języka JavaScript , które umożliwiają dostosowywanie procesu rozruchu Blazor .
  • Rozszerzalność programu MSBuild w celu przekształcenia listy opublikowanych plików i zdefiniowania Blazor rozszerzeń publikowania. Blazor Rozszerzenia publikowania to pliki zdefiniowane podczas procesu publikowania, które stanowią alternatywną reprezentację zestawu plików wymaganych do uruchomienia opublikowanej Blazor WebAssembly aplikacji. W tym artykule utworzone jest rozszerzenie publikowania Blazor, które generuje pakiet wieloczęściowy zawierający wszystkie biblioteki DLL aplikacji zapakowane w jeden plik, co pozwala na pobranie wszystkich bibliotek DLL razem.

Podejście przedstawione w tym artykule służy jako punkt wyjścia dla deweloperów do opracowania własnych strategii i niestandardowych procesów ładowania.

Ostrzeżenie

Każde podejście podjęte w celu obejścia ograniczenia bezpieczeństwa musi być starannie przemyślane pod kątem jego skutków dla bezpieczeństwa. Zalecamy dalsze zapoznanie się z tematem u specjalistów ds. zabezpieczeń sieci w organizacji przed przyjęciem podejścia w tym artykule. Alternatywy do rozważenia:

  • Włącz urządzenia zabezpieczające i oprogramowanie zabezpieczające, aby umożliwić klientom sieciowym pobieranie i używanie dokładnych plików wymaganych przez aplikację Blazor WebAssembly .
  • Przełącz się z modelu hostingu Blazor WebAssembly do modelu hostinguBlazor Server, który obsługuje cały kod języka C# aplikacji na serwerze i nie wymaga pobierania bibliotek DLL do klientów. Blazor Server Oferuje również możliwość zachowania prywatności kodu w języku C# bez konieczności używania aplikacji web API w aplikacjach Blazor WebAssembly.

Eksperymentalny pakiet NuGet i przykładowa aplikacja

Podejście opisane w tym artykule jest używane przez pakiet eksperymentalnyMicrosoft.AspNetCore.Components.WebAssembly.MultipartBundle (NuGet.org) dla aplikacji przeznaczonych dla platformy .NET 6 lub nowszej. Pakiet zawiera elementy docelowe programu MSBuild, aby dostosować Blazor wyniki publikacji i inicjator języka JavaScript do używania niestandardowego modułu ładującego zasoby rozruchowe, z których każdy został szczegółowo opisany w dalszej części artykułu.

Kod eksperymentalny (zawiera źródło referencyjne pakietu NuGet i CustomPackagedApp przykładową aplikację)

Ostrzeżenie

Funkcje eksperymentalne i w wersji zapoznawczej są udostępniane na potrzeby zbierania opinii i nie są obsługiwane w środowisku produkcyjnym.

W dalszej części tego artykułu sekcja Dostosowywanie Blazor WebAssembly procesu ładowania za pośrednictwem pakietu NuGet wraz z trzema podsekcjami zawiera szczegółowe wyjaśnienia dotyczące konfiguracji i kodu w Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle pakiecie. Szczegółowe wyjaśnienia są ważne, aby zrozumieć, kiedy tworzysz własną strategię i niestandardowy proces ładowania aplikacji Blazor WebAssembly . Aby użyć opublikowanego, eksperymentalnego, nieobsługiwanego pakietu NuGet bez dostosowywania jako pokazu lokalnego, wykonaj następujące kroki:

  1. Użyj istniejącego hostowanego Blazor WebAssemblyrozwiązania lub utwórz nowe rozwiązanie na podstawie szablonu projektu Blazor WebAssembly przy użyciu programu Visual Studio lub przez przekazanie opcji -ho|--hosted do polecenia dotnet new (dotnet new blazorwasm -ho). Aby uzyskać więcej informacji, zobacz Tooling for ASP.NET Core Blazor.

  2. W projekcie Client dodaj pakiet eksperymentalny Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle .

    Uwaga

    Aby uzyskać wskazówki dotyczące dodawania pakietów do aplikacji .NET, zobacz artykuły w Instalowanie i zarządzanie pakietami oraz w proces korzystania z pakietów (dokumentacja NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

  3. W projekcie Server dodaj punkt końcowy służący do obsługi pliku pakietu (app.bundle). Przykładowy kod można znaleźć w sekcji Obsługa pakietu w sekcji aplikacji serwera hosta w tym artykule.

  4. Opublikuj aplikację w konfiguracji wydania.

Blazor WebAssembly Dostosowywanie procesu ładowania za pomocą pakietu NuGet

Ostrzeżenie

Wskazówki zawarte w tej sekcji z trzema podsekcjami dotyczą tworzenia pakietu NuGet od podstaw w celu zaimplementowania własnej strategii i niestandardowego procesu ładowania. Pakiet eksperymentalnyMicrosoft.AspNetCore.Components.WebAssembly.MultipartBundle (NuGet.org) dla platformy .NET 6 i 7 jest oparty na wskazówkach w tej sekcji. W przypadku korzystania z podanego pakietu w lokalnym pokazie podejścia do pobierania pakietów wieloczęściowych nie trzeba postępować zgodnie ze wskazówkami w tej sekcji. Aby uzyskać wskazówki dotyczące korzystania z podanego pakietu, zobacz sekcję Eksperymentalny pakiet NuGet i przykładową aplikację .

Blazorzasoby aplikacji są pakowane do pliku pakietu wieloczęściowego i ładowane przez przeglądarkę za pośrednictwem niestandardowego inicjatora języka JavaScript (JS). W przypadku aplikacji korzystającej z pakietu za pomocą inicjatora JS, aplikacja wymaga jedynie, aby plik pakietu był udostępniany na żądanie. Wszystkie inne aspekty tego podejścia są obsługiwane w sposób przejrzysty.

Do sposobu ładowania domyślnej opublikowanej Blazor aplikacji są wymagane cztery dostosowania:

  • Zadanie MSBuild do przekształcania plików do publikacji.
  • Pakiet NuGet z elementami docelowymi programu MSBuild, który łączy się w Blazor proces publikowania, przekształca dane wyjściowe i definiuje co najmniej jeden Blazor plik rozszerzenia publikowania (w tym przypadku pojedynczy pakiet).
  • Inicjalizator JS do zaktualizowania wywołania zwrotnego Blazor WebAssembly ładującego zasoby, aby załadować pakiet i zapewnić aplikacji dostęp do poszczególnych plików.
  • Pomocnik w aplikacji hosta Server, które zapewnia, że pakiet jest dostarczany klientom na żądanie.

Tworzenie zadania MSBuild w celu dostosowania listy opublikowanych plików i zdefiniowania nowych rozszerzeń

Utwórz zadanie MSBuild jako publiczną klasę języka C#, którą można zaimportować w ramach kompilacji MSBuild i która może współdziałać z kompilacją.

Dla klasy C# wymagane są następujące elementy:

Uwaga

Pakiet NuGet dla przykładów w tym artykule nosi nazwę po pakiecie dostarczonym przez firmę Microsoft, Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle. Aby uzyskać wskazówki dotyczące nazewnictwa i tworzenia własnego pakietu NuGet, zobacz następujące artykuły 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>

Określ najnowsze wersje pakietów dla {VERSION} symboli zastępczych w NuGet.org:

Aby utworzyć zadanie MSBuild, utwórz publiczną klasę języka C# rozszerzającą Microsoft.Build.Utilities.Task (a nie System.Threading.Tasks.Task) i zadeklaruj trzy właściwości:

  • PublishBlazorBootStaticWebAsset: lista plików do opublikowania dla aplikacji Blazor.
  • BundlePath: ścieżka, w której jest zapisywany pakiet.
  • Extension: nowe rozszerzenia publikowania do uwzględnienia w kompilacji.

Poniższa przykładowa BundleBlazorAssets klasa to punkt wyjścia do dalszego dostosowywania:

  • W metodzie Execute pakiet jest tworzony na podstawie następujących trzech typów plików:
    • Pliki JavaScript (dotnet.js)
    • Pliki WASM (dotnet.wasm)
    • Biblioteki DLL aplikacji (.dll)
  • Tworzony jest multipart/form-data pakiet. Każdy plik jest dodawany do pakietu z odpowiednimi opisami za pośrednictwem nagłówka Content-Disposition i nagłówka Content-Type.
  • Po utworzeniu pakietu pakiet jest zapisywany w pliku.
  • Kompilacja jest skonfigurowana dla rozszerzenia. Poniższy kod tworzy element rozszerzenia i dodaje go do Extension właściwości . Każdy element rozszerzenia zawiera trzy fragmenty danych:
    • Ścieżka do pliku rozszerzenia.
    • Ścieżka adresu URL względem katalogu głównego Blazor WebAssembly aplikacji.
    • Nazwa rozszerzenia, które grupuje pliki utworzone przez określone rozszerzenie.

Po osiągnięciu wcześniejszych celów zadanie MSBuild jest tworzone do customizacji danych wyjściowych publikacji Blazor. Blazor dba o gromadzenie rozszerzeń i zapewnia, że są one kopiowane do właściwej lokalizacji w folderze danych wyjściowych publikacji (na przykład bin\Release\net6.0\publish). Te same optymalizacje (na przykład kompresja) są stosowane do plików JavaScript, WASM i DLL w taki sam sposób, w jaki Blazor są stosowane do innych plików.

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

Twórz pakiet NuGet, aby automatycznie przekształcać wyniki publikowania

Wygeneruj pakiet NuGet z miejscami docelowymi programu MSBuild, które są automatycznie dołączane po odwołaniu do pakietu:

  • Utwórz nowy Razor projekt biblioteki klas (RCL).
  • Utwórz plik targets zgodnie z konwencjami NuGet, aby automatycznie importować pakiet w projektach, które go używają. Na przykład utwórz build\net6.0\{PACKAGE ID}.targets, gdzie {PACKAGE ID} jest identyfikatorem pakietu.
  • Zbierz dane wyjściowe z biblioteki klas zawierającej zadanie MSBuild i upewnij się, że dane wyjściowe są pakowane we właściwej lokalizacji.
  • Dodaj niezbędny kod MSBuild do połączenia z potokiem Blazor i wywołaj zadanie MSBuild w celu wygenerowania pakietu.

Podejście opisane w tej sekcji używa tylko pakietu do dostarczania elementów docelowych i zawartości, która różni się od większości pakietów, w których pakiet zawiera bibliotekę DLL.

Ostrzeżenie

Przykładowy pakiet opisany w tej sekcji przedstawia sposób dostosowywania procesu publikowania Blazor . Przykładowy pakiet NuGet jest używany tylko jako lokalny pokaz. Używanie tego pakietu w środowisku produkcyjnym nie jest obsługiwane.

Uwaga

Pakiet NuGet dla przykładów w tym artykule nosi nazwę po pakiecie dostarczonym przez firmę Microsoft, Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle. Aby uzyskać wskazówki dotyczące nazewnictwa i tworzenia własnego pakietu NuGet, zobacz następujące artykuły 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>

Uwaga

Właściwość <NoWarn>NU5100</NoWarn> w poprzednim przykładzie pomija ostrzeżenie dotyczące zestawów umieszczonych w folderze tasks . Aby uzyskać więcej informacji, zobacz Ostrzeżenie narzędzia NuGet NU5100.

Dodaj plik .targets aby połączyć zadanie MSBuild z potokiem kompilacji. W tym pliku są realizowane następujące cele:

  • Zaimportuj zadanie do procesu kompilacji. Należy pamiętać, że ścieżka do biblioteki DLL jest względna względem ostatecznej lokalizacji pliku w pakiecie.
  • Właściwość ComputeBlazorExtensionsDependsOn dołącza niestandardowy element docelowy do potoku Blazor WebAssembly.
  • Extension Przechwyć właściwość w danych wyjściowych zadania i dodaj ją, aby poinformować BlazorPublishExtensionBlazor o rozszerzeniu. Wywołanie zadania w obiekcie docelowym powoduje wygenerowanie pakietu. Lista opublikowanych plików jest dostarczana przez Blazor WebAssembly pipeline w PublishBlazorBootStaticWebAsset grupie elementu. Ścieżka pakietu jest definiowana przy użyciu IntermediateOutputPath (zazwyczaj wewnątrz folderu obj). Ostatecznie pakiet jest kopiowany automatycznie do docelowej lokalizacji w folderze wynikowym publikacji (na przykład bin\Release\net6.0\publish).

Po odwołaniu się do pakietu, podczas publikowania generuje zestaw plików 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>

Automatyczne uruchamianie Blazor z pakietu

Pakiet NuGet wykorzystuje inicjatory języka JavaScript (JS), aby automatycznie uruchamiać aplikację Blazor WebAssembly z pakietu zamiast używać pojedynczych plików DLL. JSInicjalizatory są używane do zmiany Blazormodułu ładującego zasób rozruchowy oraz używania zbioru.

Aby utworzyć JS inicjator, dodaj JS plik o nazwie {NAME}.lib.module.js do wwwroot folderu projektu pakietu, gdzie {NAME} symbol zastępczy jest identyfikatorem pakietu. Na przykład plik pakietu firmy Microsoft ma nazwę Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Wyeksportowane funkcje beforeWebAssemblyStart i afterWebAssemblyStarted obsługują ładowanie.

Inicjatory JS :

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

Aby utworzyć JS inicjator, dodaj JS plik o nazwie {NAME}.lib.module.js do wwwroot folderu projektu pakietu, gdzie {NAME} symbol zastępczy jest identyfikatorem pakietu. Na przykład plik pakietu firmy Microsoft ma nazwę Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Wyeksportowane funkcje beforeStart i afterStarted obsługa ładowania.

Inicjatory JS :

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

Obsługa pakietu z aplikacji serwera hosta

Ze względu na ograniczenia zabezpieczeń ASP.NET Core nie obsługuje app.bundle pliku. Pomocnik przetwarzania żądań jest wymagany do obsługi pliku, gdy jest on żądany przez klientów.

Uwaga

Ponieważ te same optymalizacje są przezroczysto stosowane do rozszerzeń publikowania, co do plików aplikacji, skompresowane pliki zasobów app.bundle.gz i app.bundle.br są generowane automatycznie podczas publikowania.

Umieść kod C# w projekcie Server bezpośrednio przed wierszem, który ustawia plik zapasowy na index.html (app.MapFallbackToFile("index.html");), aby odpowiedzieć na żądanie dla pliku pakietu (na przykład 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);
});

Typ zawartości jest zgodny z typem zdefiniowanym wcześniej w zadaniu kompilacji. Punkt końcowy sprawdza kodowanie zawartości akceptowane przez przeglądarkę i obsługuje optymalny plik, Brotli (.br) lub Gzip (.gz).