ASP.NET Core barındırılan uygulamalar için dağıtım Blazor WebAssembly düzeni

Bu makalede, dinamik bağlantı kitaplığı (DLL) dosyalarının indirilmesini ve yürütülmesini engelleyen ortamlarda barındırılan Blazor WebAssembly dağıtımların nasıl etkinleştirileceği açıklanır.

Not

Bu kılavuz, istemcilerin DLL'leri indirmesini ve yürütmesini engelleyen ortamları ele alır. .NET 8 veya sonraki sürümlerinde, Blazor bu sorunu gidermek için Webcil dosya biçimini kullanır. Daha fazla bilgi için bkz . ASP.NET Core'u Blazor WebAssemblybarındırma ve dağıtma. Bu makalede açıklanan deneysel NuGet paketinin kullanıldığı çok parçalı paketleme, .NET 8 veya sonraki sürümlerdeki uygulamalar için Blazor desteklenmez. .NET 8 veya üzeri için kendi çok parçalı paketleme NuGet paketinizi oluşturmak için bu makaledeki yönergeleri kullanabilirsiniz.

Blazor WebAssemblyuygulamaların çalışması için dinamik bağlantı kitaplıklarının (DLL' ler) çalışması gerekir, ancak bazı ortamlar istemcilerin DLL'leri indirmesini ve yürütmesini engeller. Bu ortamların bir alt kümesinde, DLL dosyalarının (.dll) dosya adı uzantısını değiştirmek güvenlik kısıtlamalarını atlamak için yeterlidir, ancak güvenlik ürünleri genellikle ağ üzerinden geçen dosyaların içeriğini tarar ve DLL dosyalarını engeller veya karantinaya alır. Bu makalede, bu ortamlardaki uygulamaları etkinleştirmeye Blazor WebAssembly yönelik bir yaklaşım açıklanır. Burada, dll'ler güvenlik kısıtlamaları atlayarak birlikte indirilebilmeleri için uygulamanın DLL'lerinden çok parçalı paket dosyası oluşturulur.

Barındırılan Blazor WebAssembly bir uygulama, yayımlanan dosyalarını ve uygulama DLL'lerini paketlemesini aşağıdaki özellikleri kullanarak özelleştirebilir:

  • Önyükleme işlemini özelleştirmeye Blazor izin veren JavaScript başlatıcıları.
  • Yayımlanan dosyaların listesini dönüştürmek ve Yayımlama Uzantıları tanımlamak Blazor için MSBuild genişletilebilirliği. Blazor Yayımlama Uzantıları, yayımlama işlemi sırasında tanımlanan ve yayımlanmış Blazor WebAssembly bir uygulamayı çalıştırmak için gereken dosya kümesi için alternatif bir gösterim sağlayan dosyalardır. Bu makalede, Blazor DLL'lerin birlikte indirilmesi için uygulamanın tüm DLL'lerinin tek bir dosyaya paketlendiği çok parçalı bir paket oluşturan bir Yayımlama Uzantısı oluşturulur.

Bu makalede gösterilen yaklaşım, geliştiricilerin kendi stratejilerini ve özel yükleme süreçlerini geliştirmeleri için bir başlangıç noktası görevi görür.

Uyarı

Bir güvenlik kısıtlamasını aşmak için uygulanan tüm yaklaşımlar, güvenlik üzerindeki etkileri açısından dikkatli bir şekilde değerlendirilmelidir. Bu makaledeki yaklaşımı benimsemeden önce kuruluşunuzun ağ güvenlik uzmanlarıyla konuyu daha ayrıntılı incelemenizi öneririz. Dikkate alınması gereken alternatifler şunlardır:

  • Ağ istemcilerinin bir Blazor WebAssembly uygulamanın tam olarak gerektirdiği dosyaları indirmesine ve kullanmasına izin vermek için güvenlik gereçlerini ve güvenlik yazılımını etkinleştirin.
  • Blazor WebAssembly Sunucuda uygulamanın tüm C# kodunu koruyan ve istemcilere Blazor Server DLL'lerin indirilmesini gerektirmeyen barındırma modelinden barındırma modeline geçin. Blazor Serverayrıca uygulamalarla Blazor WebAssembly C# kodu için web API uygulamalarının kullanılmasını gerektirmeden C# kodunu privacy özel tutma avantajı sunar.

Deneysel NuGet paketi ve örnek uygulama

Bu makalede açıklanan yaklaşım, .NET 6 veya üzerini hedefleyen uygulamalar için deneyselMicrosoft.AspNetCore.Components.WebAssembly.MultipartBundle paket (NuGet.org) tarafından kullanılır. Paket, yayımlama çıkışını özelleştirmek için MSBuild hedefleri ve her biri bu makalenin Blazor devamında ayrıntılı olarak açıklanan özel bir önyükleme kaynak yükleyicisi kullanmak için bir JavaScript başlatıcısı içerir.

Deneysel kod (NuGet paketi başvuru kaynağını ve CustomPackagedApp örnek uygulamayı içerir)

Uyarı

Deneysel ve önizleme özellikleri geri bildirim toplamak amacıyla sağlanır ve üretim kullanımı için desteklenmez.

Bu makalenin Blazor WebAssembly devamında, üç alt bölümüyle NuGet paketi aracılığıyla yükleme işlemini özelleştirme bölümü, paketteki yapılandırma ve kod Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle hakkında ayrıntılı açıklamalar sağlar. Ayrıntılı açıklamalar, uygulamalar için kendi stratejinizi ve özel yükleme işleminizi oluştururken anlamanız önemlidir Blazor WebAssembly . Yerel bir tanıtım olarak özelleştirme olmadan yayımlanan, deneysel, desteklenmeyen NuGet paketini kullanmak için aşağıdaki adımları gerçekleştirin:

  1. Visual Studio'yu kullanarak veya seçeneğini dotnet new komutuna Blazor WebAssembly geçirerek mevcut barındırılan-ho|--hostedBlazor WebAssembly çözümü kullanın veya proje şablonundan yeni bir çözüm oluşturun.dotnet new blazorwasm -ho Daha fazla bilgi için bkz . ASP.NET Core Blazoriçin Araçlar.

  2. Client Projeye deneysel Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle paketi ekleyin.

    Not

    .NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri) paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.

  3. Projede Server paket dosyasına (app.bundle ) hizmet veren bir uç nokta ekleyin. Örnek kod, bu makalenin Ana bilgisayar sunucusu uygulamasından paketi sunma bölümünde bulunabilir.

  4. Uygulamayı Yayın yapılandırması'nda yayımlayın.

Blazor WebAssembly NuGet paketi aracılığıyla yükleme işlemini özelleştirme

Uyarı

Üç alt bölümüyle bu bölümdeki kılavuz, kendi stratejinizi ve özel yükleme işleminizi uygulamak için sıfırdan bir NuGet paketi oluşturmaya yöneliktir. .NET 6 ve 7 için deneyselMicrosoft.AspNetCore.Components.WebAssembly.MultipartBundle paket (NuGet.org) bu bölümdeki yönergelere dayanır. Sağlanan paketi çok parçalı paket indirme yaklaşımının yerel bir tanıtımında kullanırken, bu bölümdeki yönergeleri izlemeniz gerekmez. Sağlanan paketi kullanma hakkında yönergeler için Deneysel NuGet paketi ve örnek uygulama bölümüne bakın.

Blazor uygulama kaynakları çok parçalı paket dosyasına paketlenir ve tarayıcı tarafından özel bir JavaScript (JS) başlatıcısı aracılığıyla yüklenir. Paketi başlatıcıyla JS kullanan bir uygulama için, uygulama yalnızca istendiğinde paket dosyasının hizmet edilmesini gerektirir. Bu yaklaşımın diğer tüm yönleri saydam bir şekilde işlenir.

Varsayılan yayımlanan Blazor uygulamanın yüklenmesi için dört özelleştirme gerekir:

  • Yayımlama dosyalarını dönüştürmek için bir MSBuild görevi.
  • MSBuild içeren bir NuGet paketi yayımlama işlemine takılan Blazor , çıkışı dönüştüren ve bir veya daha fazla Blazor Yayımlama Uzantısı dosyası (bu örnekte tek bir paket) tanımlayan hedefler.
  • JS Paketi yükleyip uygulamaya tek tek dosyaları sağlaması için kaynak yükleyici geri çağırmasını güncelleştiren Blazor WebAssembly bir başlatıcı.
  • Paketin istek üzerine istemcilere sunulduğundan emin olmak için konak Server uygulamasında bir yardımcı.

Yayımlanan dosyaların listesini özelleştirmek ve yeni uzantılar tanımlamak için MSBuild görevi oluşturma

MSBuild derlemesinin parçası olarak içeri aktarilebilen ve derlemeyle etkileşim kurabilen genel bir C# sınıfı olarak bir MSBuild görevi oluşturun.

C# sınıfı için aşağıdakiler gereklidir:

Not

Bu makaledeki örneklerin NuGet paketi, Microsoft Microsoft.AspNetCore.Components.WebAssembly.MultipartBundletarafından sağlanan paketin adını alır. Kendi NuGet paketinizi adlandırma ve üretme yönergeleri için aşağıdaki NuGet makalelerine bakın:

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 konumunda yer {VERSION} tutucular için en son paket sürümlerini belirleyin:

MSBuild görevini oluşturmak için genel C# sınıfını genişleten Microsoft.Build.Utilities.Task (değil System.Threading.Tasks.Task) oluşturun ve üç özellik bildirin:

  • PublishBlazorBootStaticWebAsset: Uygulama için Blazor yayımlayacak dosyaların listesi.
  • BundlePath: Paketin yazıldığı yol.
  • Extension: Derlemeye eklenecek yeni Yayımlama Uzantıları.

Aşağıdaki örnek BundleBlazorAssets sınıf, daha fazla özelleştirme için bir başlangıç noktasıdır:

  • yönteminde Execute paket aşağıdaki üç dosya türünden oluşturulur:
    • JavaScript dosyaları (dotnet.js)
    • WASM dosyaları (dotnet.wasm)
    • Uygulama DLL'leri (.dll)
  • Bir multipart/form-data paket oluşturulur. Her dosya, content-Disposition üst bilgisi ve content-type üst bilgisi aracılığıyla ilgili açıklamalarıyla birlikte pakete eklenir.
  • Paket oluşturulduktan sonra paket bir dosyaya yazılır.
  • Derleme, uzantı için yapılandırılır. Aşağıdaki kod bir uzantı öğesi oluşturur ve özelliğine Extension ekler. Her uzantı öğesi üç veri parçası içerir:
    • Uzantı dosyasının yolu.
    • Uygulamanın köküne Blazor WebAssembly göre URL yolu.
    • Belirli bir uzantı tarafından üretilen dosyaları gruplandıran uzantının adı.

Önceki hedefler tamamlandıktan sonra, yayımlama çıktısını özelleştirmek Blazor için MSBuild görevi oluşturulur. Blazor uzantılarını toplamayı ve uzantıların yayımlama çıktı klasöründeki doğru konuma kopyalandığından emin olun (örneğin, bin\Release\net6.0\publish). JavaScript, WASM ve DLL dosyalarına, diğer dosyalar için de geçerli olan Blazor iyileştirmeler (örneğin, sıkıştırma) uygulanır.

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

Yayımlama çıkışını otomatik olarak dönüştürmek için bir NuGet paketi yazma

Pakete başvurulduğunda otomatik olarak eklenen MSBuild hedefleri ile bir NuGet paketi oluşturun:

  • Yeni Razor bir sınıf kitaplığı (RCL) projesi oluşturun.
  • Proje tüketen paketi otomatik olarak içeri aktarmak için NuGet kurallarını izleyerek bir hedefler dosyası oluşturun. Örneğin, oluşturun build\net6.0\{PACKAGE ID}.targets; burada {PACKAGE ID} paketin paket tanımlayıcısıdır.
  • MSBuild görevini içeren sınıf kitaplığından çıktıyı toplayın ve çıkışın doğru konumda paketlendiğini onaylayın.
  • İşlem hattına eklemek Blazor için gerekli MSBuild kodunu ekleyin ve paketi oluşturmak için MSBuild görevini çağırın.

Bu bölümde açıklanan yaklaşım yalnızca, paketin kitaplık DLL'sini içerdiği çoğu paketten farklı olan hedefleri ve içeriği teslim etmek için paketini kullanır.

Uyarı

Bu bölümde açıklanan örnek pakette yayımlama işleminin nasıl özelleştirileceği Blazor gösterilmektedir. Örnek NuGet paketi yalnızca yerel gösterim olarak kullanılır. Bu paketin üretimde kullanılması desteklenmez.

Not

Bu makaledeki örneklerin NuGet paketi, Microsoft Microsoft.AspNetCore.Components.WebAssembly.MultipartBundletarafından sağlanan paketin adını alır. Kendi NuGet paketinizi adlandırma ve üretme yönergeleri için aşağıdaki NuGet makalelerine bakın:

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>

Not

<NoWarn>NU5100</NoWarn> Yukarıdaki örnekteki özelliği, klasöre yerleştirilen derlemeler hakkındaki uyarıyı gizlertasks. Daha fazla bilgi için bkz . NuGet Uyarısı NU5100.

MSBuild görevini derleme işlem hattına göndermek için bir .targets dosya ekleyin. Bu dosyada aşağıdaki hedefler gerçekleştirilir:

  • Görevi derleme işlemine aktarın. DLL'nin yolunun dosyanın paketteki nihai konumuna göre olduğunu unutmayın.
  • özelliği özel ComputeBlazorExtensionsDependsOn hedefi işlem hattına Blazor WebAssembly ekler.
  • Görev çıkışındaki özelliğini yakalayın Extension ve uzantıyı anlatmak Blazor için öğesine ekleyinBlazorPublishExtension. Görevi hedefte çağırmak paketi oluşturur. Yayımlanan dosyaların listesi, öğe grubundaki Blazor WebAssembly PublishBlazorBootStaticWebAsset işlem hattı tarafından sağlanır. Paket yolu kullanılarak tanımlanır IntermediateOutputPath (genellikle klasörün içinde obj ). Sonuç olarak paket, yayımlama çıktı klasöründeki doğru konuma (örneğin, bin\Release\net6.0\publish) otomatik olarak kopyalanır.

Pakete başvurulduğunda, yayımlama sırasında dosyaların bir paketini Blazor oluşturur.

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>

Paketten otomatik olarak önyükleme Blazor

NuGet paketi, tek tek DLL dosyalarını kullanmak yerine bir uygulamayı paketten otomatik olarak önyüklemek Blazor WebAssembly için JavaScript (JS) başlatıcılarından yararlanır. JSbaşlatıcılar önyükleme kaynağı yükleyicisini Blazor değiştirmek ve paketi kullanmak için kullanılır.

Başlatıcı oluşturmak JS için paket projesinin klasörüne wwwroot adıyla {NAME}.lib.module.js bir JS dosya ekleyin; burada {NAME} yer tutucu paket tanımlayıcısıdır. Örneğin, Microsoft paketinin dosyası olarak adlandırılır Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Dışarı aktarılan işlevler beforeWebAssemblyStart ve afterWebAssemblyStarted yükleme işlemi.

Başlatıcılar 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);
  }
}

Başlatıcı oluşturmak JS için paket projesinin klasörüne wwwroot adıyla {NAME}.lib.module.js bir JS dosya ekleyin; burada {NAME} yer tutucu paket tanımlayıcısıdır. Örneğin, Microsoft paketinin dosyası olarak adlandırılır Microsoft.AspNetCore.Components.WebAssembly.MultipartBundle.lib.module.js. Dışarı aktarılan işlevler beforeStart ve afterStarted yükleme işlemi.

Başlatıcılar 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);
  }
}

Paketi konak sunucu uygulamasından sunma

Güvenlik kısıtlamaları nedeniyle ASP.NET Core dosyaya app.bundle hizmet vermez. İstemciler tarafından istendiğinde dosyaya hizmet vermek için bir istek işleme yardımcısı gereklidir.

Not

Aynı iyileştirmeler, uygulamanın dosyalarına uygulanan Yayımlama Uzantılarına saydam olarak uygulandığından, app.bundle.gz ve app.bundle.br sıkıştırılmış varlık dosyaları yayımlama işleminde otomatik olarak oluşturulur.

C# kodunu Program.cs Server , paket dosyası isteğine yanıt vermek için geri dönüş dosyasını index.html (app.MapFallbackToFile("index.html");) olarak ayarlayan satırın hemen önüne yerleştirin (örneğin, 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);
});

İçerik türü, derleme görevinde daha önce tanımlanan türle eşleşir. Uç nokta, tarayıcı tarafından kabul edilen içerik kodlamalarını denetler ve en uygun dosya olan Brotli (.br) veya Gzip (.gz) sunar.