Bereitstellungslayout für in ASP.NET Core gehostete Blazor WebAssembly-Apps

In diesem Artikel wird erläutert, wie Sie gehostete Blazor WebAssembly-Bereitstellungen in Umgebungen aktivieren, die das Herunterladen und Ausführen von DLL-Dateien (Dynamic Link Library) blockieren.

Hinweis

In diesem Leitfaden werden Umgebungen behandelt, in denen Clients das Herunterladen und Ausführen von DLLs blockieren. In .NET 8 oder höher verwendet Blazor das Webcil-Dateiformat, um dieses Problem zu beheben. Weitere Informationen finden Sie unter Hosten und Bereitstellen von Blazor WebAssembly in ASP.NET Core. Multipart-Bündelung mithilfe des experimentellen NuGet-Pakets, das in diesem Artikel beschrieben wird, wird für Blazor-Apps in .NET 8 oder höher nicht unterstützt. Weitere Informationen finden Sie unter Erweiterung des Pakets Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle zur Festlegung eines eigenen Bündelformats (dotnet/aspnetcore #36978). Sie können die Anleitungen in diesem Artikel verwenden, um ein eigenes mehrteiliges Bündelungspaket für .NET 8 oder höher zu erstellen.

Blazor WebAssembly-Apps erfordern DLLs (Dynamic Link Libraries), um funktionieren zu können, aber einige Umgebungen blockieren das Herunterladen und Ausführen von DLLs durch Clients. In einem Teil dieser Umgebungen reicht das Ändern der Dateinamenerweiterung von DLL-Dateien (.dll) aus, um Sicherheitseinschränkungen zu umgehen. Sicherheitsprodukte können jedoch häufig den Inhalt von Dateien überprüfen, die das Netzwerk durchlaufen, und DLL-Dateien blockieren oder unter Quarantäne stellen. In diesem Artikel wird ein Ansatz zum Aktivieren von Blazor WebAssembly-Apps in diesen Umgebungen beschrieben, bei dem eine mehrteilige Paketdatei aus den DLLs der App erstellt wird, sodass die DLLs unter Umgehung von Sicherheitseinschränkungen zusammen heruntergeladen werden können.

Eine gehostete Blazor WebAssembly-App kann ihre veröffentlichten Dateien und die Paketierung von App-DLLs mithilfe der folgenden Features anpassen:

  • JavaScript-Initialisierer, die das Anpassen des Blazor-Startprozesses ermöglichen.
  • MSBuild-Erweiterbarkeit, um die Liste der veröffentlichten Dateien zu transformieren und Blazor-Veröffentlichungserweiterungen zu definieren. Blazor-Veröffentlichungserweiterungen sind Dateien, die während des Veröffentlichungsprozesses definiert werden und eine alternative Darstellung für die Gruppe von Dateien bereitstellen, die zum Ausführen einer veröffentlichten Blazor WebAssembly-App erforderlich sind. In diesem Artikel wird eine Blazor-Veröffentlichungserweiterung erstellt, die ein mehrteiliges Paket mit allen DLLs der App erstellt, die in eine einzelne Datei gepackt sind, sodass die DLLs zusammen heruntergeladen werden können.

Der in diesem Artikel gezeigte Ansatz dient Entwicklern als Startpunkt für die Entwicklung eigener Strategien und benutzerdefinierter Ladeprozesse.

Warnung

Jeder Ansatz, mit dem eine Sicherheitseinschränkung umgangen wird, muss sorgfältig hinsichtlich seiner Auswirkungen auf die Sicherheit geprüft werden. Es wird empfohlen, das Thema mit den Netzwerksicherheitsexperten Ihrer Organisation weiter zu untersuchen, bevor Sie den in diesem Artikel erläuterten Ansatz übernehmen. Zu berücksichtigende Alternativen:

  • Aktivieren Sie Sicherheitsappliances und Sicherheitssoftware, damit Netzwerkclients die richtigen Dateien herunterladen und verwenden können, die für eine Blazor WebAssembly-App erforderlich sind.
  • Wechseln Sie vom Blazor WebAssembly-Hostingmodell zum Blazor Server-Hostingmodell, das den gesamten C#-Code der App auf dem Server verwaltet und kein Herunterladen von DLLs auf Clients erfordert. Blazor Server bietet auch den Vorteil, dass C#-Code privat bleibt, ohne dass Web-API-Apps für den Datenschutz von C#-Code mit Blazor WebAssembly-Apps verwendet werden müssen.

Experimentelle NuGet-Pakete und Beispiel-Apps

Der in diesem Artikel beschriebene Ansatz wird von dem experimentellenMicrosoft.AspNetCore.Components.WebAssembly.MultipartBundle Paket (NuGet.org) für Anwendungen verwendet, die auf .NET 6 oder höher abzielen. Das Paket enthält MSBuild-Ziele zum Anpassen der Blazor-Veröffentlichungsausgabe und einen JavaScript-Initialisierer, um ein benutzerdefiniertes Startressourcenladeprogramm zu verwenden. Diese werden jeweils weiter unten in diesem Artikel ausführlich beschrieben.

Experimenteller Code (enthält die NuGet-Paketverweisquelle und die CustomPackagedApp- Beispiel-App)

Warnung

Experimentelle Features und Previewfunktionen werden zum Sammeln von Feedback bereitgestellt und für die Verwendung in der Produktion nicht unterstützt.

Weiter unten in diesem Artikel enthält der Abschnitt Anpassen des Blazor WebAssembly-Ladeprozesses über ein NuGet-Paket mit seinen drei Unterabschnitten ausführliche Erläuterungen zur Konfiguration und zum Code im Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle-Paket. Es ist wichtig, die ausführlichen Erläuterungen zu verstehen, wenn Sie Ihre eigene Strategie und einen benutzerdefinierten Ladeprozess für Blazor WebAssembly-Apps entwickeln. Führen Sie die folgenden Schritte aus, um das veröffentlichte, experimentelle, nicht unterstützte NuGet-Paket ohne Anpassung zur lokalen Demonstration zu verwenden:

  1. Verwenden Sie eine vorhandene gehostete Blazor WebAssemblyProjektmappe, oder erstellen Sie eine neue Projektmappe aus der Blazor WebAssembly-Projektvorlage, indem Sie Visual Studio verwenden oder die -ho|--hosted-Option an den dotnet new Befehl (dotnet new blazorwasm -ho) übergeben. Weitere Informationen finden Sie unter Tools für ASP.NET Core Blazor.

  2. Fügen Sie im Client-Projekt das experimentelle Paket Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle hinzu.

    Hinweis

    Einen Leitfaden zum Hinzufügen von Paketen zu .NET-Apps finden Sie in Installieren und Verwalten von Paketen unter Workflow der Nutzung von Paketen (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.

  3. Fügen Sie im Server -Projekt einen Endpunkt für die Bereitstellung der Paketdatei (app.bundle) hinzu. Beispielcode finden Sie im Abschnitt Bereitstellen des Pakets über die Hostserver-App dieses Artikels.

  4. Veröffentlichen Sie die App in der Releasekonfiguration.

Anpassen des Blazor WebAssembly-Ladevorgangs über ein NuGet-Paket

Warnung

Die Anleitung in diesem Abschnitt mit den drei Unterabschnitten bezieht sich auf das Erstellen eines NuGet-Pakets von Grund auf, um Ihre eigene Strategie und Ihren benutzerdefinierten Ladevorgang zu implementieren. Das experimentelle Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle-Paket (NuGet.org) für .NET 6- und 7-Apps basiert auf den Anweisungen in diesem Abschnitt. Wenn Sie das bereitgestellte Paket in einer lokalen Demonstration des Ansatzes für den Download eines mehrteiligen Pakets verwenden, müssen Sie die Anleitung in diesem Abschnitt nicht befolgen. Eine Anleitung zur Verwendung des bereitgestellten Pakets finden Sie im Abschnitt Experimentelles NuGet-Paket und Beispiel-App.

Blazor-App-Ressourcen werden in eine mehrteilige Paketdatei gepackt und vom Browser über einen benutzerdefinierten JavaScript-Initialisierer (JS) geladen. Für eine App, die das Paket mit dem JS-Initialisierer verwendet, erfordert die App nur, dass die Paketdatei auf Anforderung zur Verfügung gestellt wird. Alle anderen Aspekte dieses Ansatzes werden transparent behandelt.

Für das Laden einer veröffentlichten Blazor-Standard-App sind vier Anpassungen erforderlich:

  • Ein MSBuild-Task zum Transformieren der Veröffentlichungsdateien.
  • Ein NuGet-Paket mit MSBuild-Zielen, das in den Blazor-Veröffentlichungsprozess eingebunden wird, die Ausgabe transformiert und mindestens eine Blazor-Veröffentlichungserweiterungsdatei definiert (in diesem Fall ein einzelnes Paket).
  • Ein JS-Initialisierer zum Aktualisieren des Blazor WebAssembly-Ressourcenladeprogrammrückrufs, sodass er das Paket lädt und die einzelnen Dateien für die App bereitstellt.
  • Ein Hilfsprogramm für die Server -Host-App, um sicherzustellen, dass das Paket auf Anforderung für Clients bereitgestellt wird.

Erstellen eines MSBuild-Tasks zum Anpassen der Liste veröffentlichter Dateien und zum Definieren neuer Erweiterungen

Erstellen Sie einen MSBuild-Task als öffentliche C#-Klasse, die als Teil einer MSBuild-Kompilierung importiert werden und mit dem Build interagieren kann.

Folgendes ist für die C#-Klasse erforderlich:

Hinweis

Das NuGet-Paket für die Beispiele in diesem Artikel wird nach dem von Microsoft bereitgestellten Paket Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle benannt. Anleitungen zum Benennen und Erstellen eines eigenen NuGet-Pakets finden Sie in den folgenden NuGet-Artikeln:

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>

Ermitteln Sie die neuesten Paketversionen für die {VERSION}-Platzhalter auf NuGet.org:

Um den MSBuild-Task zu erstellen, erstellen Sie eine öffentliche C#-Klasse zum Erweitern von Microsoft.Build.Utilities.Task (nicht System.Threading.Tasks.Task), und deklarieren Sie drei Eigenschaften:

  • PublishBlazorBootStaticWebAsset: Die Liste der Dateien, die für die Blazor-App veröffentlicht werden sollen.
  • BundlePath: Der Pfad, in den das Paket geschrieben wird.
  • Extension: Die neuen Veröffentlichungserweiterungen, die in den Build eingeschlossen werden sollen.

Die folgende BundleBlazorAssets-Beispielklasse ist ein Startpunkt für die weitere Anpassung:

  • In der Execute-Methode wird das Paket aus den folgenden drei Dateitypen erstellt:
    • JavaScript-Dateien (dotnet.js)
    • WASM-Dateien (dotnet.wasm)
    • App-DLLs (.dll)
  • Ein multipart/form-data-Paket wird erstellt. Jede Datei wird dem Paket mit den entsprechenden Beschreibungen über den Content-Disposition-Header und den Content-Type-Header hinzugefügt.
  • Nachdem das Paket erstellt wurde, wird es in eine Datei geschrieben.
  • Der Build wird für die Erweiterung konfiguriert. Mit dem folgenden Code wird ein Erweiterungselement erstellt, das der Extension-Eigenschaft hinzugefügt wird. Jedes Erweiterungselement enthält drei Dateninformationen:
    • Den Pfad zur Erweiterungsdatei
    • Den URL-Pfad relativ zum Stamm der Blazor WebAssembly-App
    • Den Namen der Erweiterung, die die von einer bestimmten Erweiterung erstellten Dateien gruppiert

Nachdem die oben genannten Ziele erreicht wurden, wird der MSBuild-Task zum Anpassen der Blazor-Veröffentlichungsausgabe erstellt. Blazor übernimmt das Sammeln der Erweiterungen und stellt sicher, dass die Erweiterungen an den richtigen Speicherort im Veröffentlichungsausgabeordner (z. B. bin\Release\net6.0\publish) kopiert werden. Die gleichen Optimierungen (z. B. Komprimierung) werden auf die JavaScript-, WASM- und DLL-Dateien angewendet, wie Blazor sie auch auf andere Dateien anwendet.

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

Erstellen eines NuGet-Pakets zum automatischen Transformieren der Veröffentlichungsausgabe

Generieren Sie ein NuGet-Paket mit MSBuild-Zielen, die automatisch eingeschlossen werden, wenn auf das Paket verwiesen wird:

  • Erstellen Sie ein neues Razor-Klassenbibliotheksprojekt (Razor Class Library, RCL).
  • Erstellen Sie eine Zieldatei, die NuGet-Konventionen befolgt, um das Paket bei der Nutzung von Projekten automatisch zu importieren. Erstellen Sie beispielsweise build\net6.0\{PACKAGE ID}.targets, wobei {PACKAGE ID} der Paketbezeichner des Pakets ist.
  • Erfassen Sie die Ausgabe aus der Klassenbibliothek, die den MSBuild-Task enthält, und vergewissern Sie sich, dass die Ausgabe am richtigen Speicherort gepackt ist.
  • Fügen Sie den erforderlichen MSBuild-Code hinzu, der an die Blazor-Pipeline angefügt werden soll, und rufen Sie den MSBuild-Task auf, um das Paket zu generieren.

Der in diesem Abschnitt beschriebene Ansatz verwendet nur das Paket zum Übermitteln von Zielen und Inhalten. Dies ist ein Unterschied zu den meisten Paketen, bei denen das Paket eine Bibliotheks-DLL enthält.

Warnung

Das in diesem Abschnitt beschriebene Beispielpaket veranschaulicht das Anpassen des Blazor-Veröffentlichungsprozesses. Das NuGet-Beispielpaket ist nur für die Verwendung als lokale Demonstration konzipiert. Die Verwendung dieses Pakets in der Produktion wird nicht unterstützt.

Hinweis

Das NuGet-Paket für die Beispiele in diesem Artikel wird nach dem von Microsoft bereitgestellten Paket Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle benannt. Anleitungen zum Benennen und Erstellen eines eigenen NuGet-Pakets finden Sie in den folgenden NuGet-Artikeln:

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>

Hinweis

Die <NoWarn>NU5100</NoWarn>-Eigenschaft im vorherigen Beispiel unterdrückt die Warnung zu den Assemblys, die im tasks-Ordner platziert werden. Weitere Informationen finden Sie unter NuGet-Warnung NU5100.

Fügen Sie eine .targets-Datei hinzu, um den MSBuild-Task mit der Buildpipeline zu verknüpfen. In dieser Datei werden die folgenden Ziele erreicht:

  • Importieren Sie den Task in den Buildprozess. Beachten Sie, dass der Pfad zur DLL relativ zum endgültigen Speicherort der Datei im Paket ist.
  • Die ComputeBlazorExtensionsDependsOn-Eigenschaft fügt das benutzerdefinierte Ziel an die Blazor WebAssembly-Pipeline an.
  • Erfassen Sie die Extension-Eigenschaft in der Ausgabe des Tasks, und fügen Sie sie zu BlazorPublishExtension hinzu, um Blazor Informationen zur Erweiterung zu übermitteln. Wenn Sie den Task im Ziel aufrufen, wird das Paket erstellt. Die Liste der veröffentlichten Dateien wird von der Blazor WebAssembly-Pipeline in der PublishBlazorBootStaticWebAsset-Elementgruppe bereitgestellt. Der Paketpfad wird mithilfe von IntermediateOutputPath definiert (in der Regel innerhalb des obj-Ordners). Letztendlich wird das Paket automatisch an den richtigen Speicherort im Veröffentlichungsausgabeordner kopiert (z. B. bin\Release\net6.0\publish).

Wenn auf das Paket verwiesen wird, generiert es während der Veröffentlichung ein Paket der Blazor-Dateien.

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>

Automatisches Bootstrapping von Blazor aus dem Paket

Das NuGet-Paket nutzt JavaScript-Initialisierer (JS), um automatisch einen Bootstrap für eine Blazor WebAssembly-App aus dem Paket durchzuführen, anstatt einzelne DLL-Dateien zu verwenden. JS-Initialisierer werden verwendet, um das BlazorStartressourcen-Ladeprogramm zu ändern und das Bundle zu nutzen.

Um einen JS-Initialisierer zu erstellen, fügen Sie dem wwwroot-Ordner des Paketprojekts eine JS-Datei mit dem Namen {NAME}.lib.module.js hinzu, wobei der Platzhalter {NAME} der Paketbezeichner ist. Die Datei für das Microsoft-Paket heißt beispielsweise Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Die exportierten Funktionen beforeWebAssemblyStart und afterWebAssemblyStarted sind für das Laden zuständig.

Die JS-Initialisierer:

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

Um einen JS-Initialisierer zu erstellen, fügen Sie dem wwwroot-Ordner des Paketprojekts eine JS-Datei mit dem Namen {NAME}.lib.module.js hinzu, wobei der Platzhalter {NAME} der Paketbezeichner ist. Die Datei für das Microsoft-Paket heißt beispielsweise Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Die exportierten Funktionen beforeStart und afterStarted sind für das Laden zuständig.

Die JS-Initialisierer:

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

Bereitstellen des Pakets aus der Host-Server-App

Aufgrund von Sicherheitseinschränkungen stellt ASP.NET Core die app.bundle-Datei nicht standardmäßig bereit. Ein Hilfsprogramm für die Anforderungsverarbeitung ist erforderlich, um die Datei bereitzustellen, wenn sie von Clients angefordert wird.

Hinweis

Da die gleichen Optimierungen transparent auf die Veröffentlichungserweiterungen angewendet werden, die auf die Dateien der App angewendet werden, werden die komprimierten Ressourcendateien app.bundle.gz und app.bundle.br bei der Veröffentlichung automatisch erstellt.

Platzieren Sie C#-Code in Program.cs des Server-Projekts unmittelbar vor der Zeile, die die Fallbackdatei auf index.html (app.MapFallbackToFile("index.html");) festlegt, um auf eine Anforderung für die Paketdatei (z. B. app.bundle) zu reagieren:

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

Der Inhaltstyp entspricht dem zuvor im Buildtask definierten Typ. Der Endpunkt führt eine Überprüfung auf die vom Browser akzeptierten Inhaltscodierungen durch und stellt die optimale Datei bereit: Brotli (.br) oder Gzip (.gz).