Миграция из ASP.NET Core в .NET 7 в .NET 8

В этой статье объясняется, как обновить существующий ASP.NET Core в проекте .NET 7 до .NET 8.

Предпосылки

  • Visual Studio 2022 с рабочей нагрузкой ASP.NET и разработка веб-приложений.

    Рабочие нагрузки установщика VS22

Обновите версию .NET SDK в global.json

Если вы используете global.json файл, нацеленный на определённую версию .NET SDK, обновите version свойство до версии SDK для .NET 8, которая в данный момент установлена. Рассмотрим пример.

{
  "sdk": {
-    "version": "7.0.100"
+    "version": "8.0.100"
  }
}

Обновление целевой платформы

Обновите идентификатор целевой платформы (TFM) в файле проекта на:net8.0

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

  <PropertyGroup>
-    <TargetFramework>net7.0</TargetFramework>
+    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

</Project>

Обновление ссылок на пакеты

В файле проекта обновите атрибут Microsoft.AspNetCore.* каждой ссылки на пакеты Microsoft.EntityFrameworkCore.*, Microsoft.Extensions.*, System.Net.Http.Json и Version до версии 8.0.0 или более поздней. Рассмотрим пример.

<ItemGroup>
-   <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="7.0.12" />
-   <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.12" />
-   <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
-   <PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
+   <PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="8.0.0" />
+   <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
+   <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
+   <PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
</ItemGroup>

Blazor

Рассматриваются следующие сценарии миграции:

Рекомендации по добавлению Blazor поддержки в приложение ASP.NET Core см. в статье "Интеграция компонентов ASP.NET Core Razor с MVC или Razor Pages".

Blazor Server Обновление приложения

Рекомендуется использовать Blazor Web Apps в .NET 8, но Blazor Server поддерживается. Чтобы продолжить использование Blazor Server с .NET 8, следуйте инструкциям в первых трех разделах этой статьи:

Новые функции Blazor, добавленные для приложений Blazor Web App, недоступны для приложения Blazor Server, обновлённого для работы в .NET 8. Если вы хотите внедрить новые функции .NET 8 Blazor , следуйте инструкциям в любом из следующих разделов:

Принятие всех Blazor Web App соглашений

Чтобы при необходимости принять все новые Blazor Web App соглашения, рекомендуется выполнить следующий процесс:

  • Создайте приложение из Blazor Web App шаблона проекта. Дополнительные сведения см. в разделе "Инструменты для ASP.NET Core Blazor".
  • Перенесите компоненты и код вашего приложения в новый Blazor Web App, внеся изменения для поддержки новых функций.
  • Обновите макет и стили объекта Blazor Web App.

Новые функции .NET 8 рассматриваются в новых возможностях ASP.NET Core в .NET 8. При обновлении приложения с .NET 6 или более ранней версии, см. заметки о миграции и выпуске (статьи Что нового) для промежуточных выпусков.

Blazor Server Преобразование приложения в приложениеBlazor Web App

Blazor Server приложения поддерживаются в .NET 8 без каких-либо изменений кода. Используйте следующие рекомендации, чтобы преобразовать приложение Blazor Server в эквивалентное .NET 8 Blazor Web App, что делает доступными все новые возможности .NET 8.

Это важно

В этом разделе рассматриваются минимальные изменения, необходимые для преобразования приложения .NET 7 Blazor Server в .NET 8 Blazor Web App. Чтобы принять все новые Blazor Web App соглашения, следуйте указаниям в разделе "Принятие всех Blazor Web App соглашений ".

  1. Следуйте инструкциям в первых трех разделах этой статьи:

  2. Переместите содержимое компонента App (App.razor) в новый файл компонента Routes (Routes.razor), добавленный в корневую папку проекта. Оставьте пустой App.razor файл в приложении в корневой папке проекта.

  3. Добавьте запись в файл _Imports.razor, чтобы приложению были доступны сокращённые режимы отрисовки:

    @using static Microsoft.AspNetCore.Components.Web.RenderMode
    
  4. Переместите содержимое _Host страницы (Pages/_Host.cshtml) в пустой App.razor файл. Перейдите к следующим изменениям компонента App .

    Замечание

    В следующем примере пространство имен проекта — BlazorServerApp. Настройте пространство имен, чтобы соответствовать проекту.

    Удалите следующие строки из верхней части файла:

    - @page "/"
    - @using Microsoft.AspNetCore.Components.Web
    - @namespace BlazorServerApp.Pages
    - @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    

    Замените предыдущие строки строкой, которая вставляет экземпляр IHostEnvironment:

    @inject IHostEnvironment Env
    

    Удалите тильду (~) из href тега <base> и замените её базовым путём для вашего приложения:

    - <base href="~/" />
    + <base href="/" />
    

    Удалите вспомогательный компонент HeadOutlet тега компонента и замените его компонентом HeadOutlet .

    Удалите следующую строку:

    - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
    

    Замените предыдущую строку следующим образом:

    <HeadOutlet @rendermode="InteractiveServer" />
    

    Удалите вспомогательный компонент App тега компонента и замените его компонентом Routes .

    Удалите следующую строку:

    - <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    Замените предыдущую строку следующим образом:

    <Routes @rendermode="InteractiveServer" />
    

    Замечание

    Предыдущая конфигурация предполагает, что компоненты приложения используют интерактивный рендеринг на сервере. Дополнительные сведения, в том числе о том, как использовать статическую отрисовку на стороне сервера (SSR), см. в статье режимы отрисовки в ASP.NET CoreBlazor.

    Удалите вспомогательные классы тегов Environment для пользовательского интерфейса отображения ошибок и замените их следующей разметкой Razor.

    Удалите следующие строки.

    - <environment include="Staging,Production">
    -     An error has occurred. This application may no longer respond until reloaded.
    - </environment>
    - <environment include="Development">
    -     An unhandled exception has occurred. See browser dev tools for details.
    - </environment>
    

    Замените предыдущие строки следующими:

    @if (Env.IsDevelopment())
    {
        <text>
            An unhandled exception has occurred. See browser dev tools for details.
        </text>
    }
    else
    {
        <text>
            An error has occurred. This app may no longer respond until reloaded.
        </text>
    }
    

    Изменить скрипт Blazor с blazor.server.js на blazor.web.js:

    - <script src="_framework/blazor.server.js"></script>
    + <script src="_framework/blazor.web.js"></script>
    
  5. Удалите файл Pages/_Host.cshtml.

  6. Обновление Program.cs:

    Замечание

    В следующем примере пространство имен проекта — BlazorServerApp. Настройте пространство имен, чтобы соответствовать проекту.

    Добавьте инструкцию using в начало файла для пространства имен проекта:

    using BlazorServerApp;
    

    Замените AddServerSideBlazor на AddRazorComponents и цепочку вызовов к AddInteractiveServerComponents.

    Удалите следующую строку:

    - builder.Services.AddServerSideBlazor();
    

    Замените предыдущую строку службами Razor компонентов и интерактивных компонентов сервера. Вызов AddRazorComponents добавляет службы антифоргерии (AddAntiforgery) по умолчанию.

    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents();
    

    Удалите следующую строку:

    - app.MapBlazorHub();
    

    Замените предыдущую строку вызовом MapRazorComponents, указав App как тип корневого компонента, и добавьте также вызов AddInteractiveServerRenderMode в цепочку:

    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode();
    

    Удалите следующую строку:

    - app.MapFallbackToPage("/_Host");
    

    Удалить промежуточное ПО маршрутизации:

    - app.UseRouting();
    

    Добавьте промежуточный компонент защиты от подделки запросов в конвейер обработки запросов после строки, добавляющей промежуточный компонент перенаправления HTTPS (app.UseHttpsRedirection):

    app.UseAntiforgery();
    

    Предшествующий вызов app.UseAntiforgery должен располагаться после вызовов, если таковые имеются, к app.UseAuthentication и app.UseAuthorization. Нет необходимости явно добавлять службы защиты от подделки запросов (builder.Services.AddAntiforgery), так как они добавляются автоматически с помощью AddRazorComponents, о котором говорилось ранее.

  7. Если для приложения Blazor Server было настроено отключение предварительной отрисовки, его можно сохранить и для обновлённого приложения. В компоненте App измените значение атрибутов директивы @rendermodeRazor для компонентов HeadOutlet и Routes.

    Измените значение атрибута директивы @rendermode для обоих компонентов HeadOutlet и Routes, чтобы отключить предварительный рендеринг:

    - @rendermode="InteractiveServer"
    + @rendermode="new InteractiveServerRenderMode(prerender: false)"
    

    Дополнительные сведения см. в ASP.NET CoreBlazor режимах рендеринга.

Blazor WebAssembly Обновление приложения

Следуйте инструкциям в первых трех разделах этой статьи:

Для приложений, которые используют отложенную загрузку сборок, измените расширение файла с .dll на .wasm в реализации приложения, чтобы отразить внедрение Blazor WebAssembly.

До выпуска .NET 8 руководство по макету развертывания для приложений, размещенных на ASP.NET Core Blazor WebAssembly направлено на среды, которые блокируют клиентов от загрузки и выполнения DLL с помощью подхода многокомпонентной упаковки. В .NET 8 или более поздней версии Blazor используется формат файла Webcil для решения этой проблемы. Многопартийное объединение с помощью экспериментального пакета NuGet, описанного в статье макета развертывания WebAssembly, не поддерживается для Blazor приложений в .NET 8 или более поздней версии. Если вы хотите продолжить использование пакета с несколькими частями в приложениях .NET 8 или более поздних версий, вы можете использовать инструкции в статье для создания собственного пакета NuGet с несколькими частями, но он не будет поддерживаться корпорацией Майкрософт.

Преобразование размещенного Blazor WebAssembly приложения в Blazor Web App

Blazor WebAssembly приложения поддерживаются в .NET 8 без каких-либо изменений кода. Используйте следующее руководство, чтобы преобразовать размещенное Blazor WebAssembly приложение ASP.NET Core в эквивалентное .NET 8 Blazor Web App, что делает все новые функции .NET 8 доступными.

Это важно

В этом разделе рассматриваются минимальные изменения, необходимые для преобразования размещенного Blazor WebAssembly приложения .NET 7 ASP.NET Core в .NET 8 Blazor Web App. Чтобы принять все новые Blazor Web App соглашения, следуйте указаниям в разделе "Принятие всех Blazor Web App соглашений ".

  1. Следуйте инструкциям в первых трех разделах этой статьи:

    Это важно

    Используя предыдущее руководство, обновите .Client.Serverи .Shared проекты решения.

  2. .Client В файле проекта (.csproj) добавьте следующие свойства MSBuild:

    <NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
    <StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
    

    Кроме того, в .Client файле проекта удалите ссылку Microsoft.AspNetCore.Components.WebAssembly.DevServer на пакет:

    - <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer"... />
    
  3. Переместите содержимое файла из .Client/wwwroot/index.html файла в новый App файл компонента (App.razor), созданный в корне .Server проекта. После перемещения содержимого файла удалите index.html файл.

    Переименуйте App.razor в проекте .Client в Routes.razor.

    В Routes.razor, обновите значение атрибута AppAssembly на typeof(Program).Assembly.

  4. В проекте .Client добавьте запись в файл _Imports.razor, чтобы сделать сокращённые режимы отрисовки доступными в приложении:

    @using static Microsoft.AspNetCore.Components.Web.RenderMode
    

    Создайте копию .Client файла проекта _Imports.razor и добавьте его в .Server проект.

  5. Внесите указанные ниже изменения в файл App.razor.

    Замените название веб-сайта по умолчанию (<title>...</title>) компонентом HeadOutlet . Запишите название веб-сайта, чтобы использовать его позже, и удалите теги title и сам заголовок:

    - <title>...</title>
    

    В том месте, где вы удалили заголовок, поместите компонент HeadOutlet, задав интерактивный режим отрисовки WebAssembly без предварительного рендеринга:

    <HeadOutlet @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
    

    Измените пакет стилей CSS:

    - <link href="{CLIENT PROJECT ASSEMBLY NAME}.styles.css" rel="stylesheet">
    + <link href="{SERVER PROJECT ASSEMBLY NAME}.styles.css" rel="stylesheet">
    

    Заполнители в предыдущем коде:

    • {CLIENT PROJECT ASSEMBLY NAME}: имя сборки клиентского проекта. Пример: BlazorSample.Client
    • {SERVER PROJECT ASSEMBLY NAME}: имя сборки проекта сервера. Пример: BlazorSample.Server

    Найдите следующую <div>...</div> разметку HTML:

    - <div id="app">
    -     ...
    - </div>
    

    Замените предыдущую HTML-разметку на компонент <div>...</div> с использованием интерактивного режима рендеринга WebAssembly (с отключённой предварительной отрисовкой):

    <Routes @rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)" />
    

    Обновите скрипт blazor.webassembly.js до blazor.web.js:

    - <script src="_framework/blazor.webassembly.js"></script>
    + <script src="_framework/blazor.web.js"></script>
    
  6. Откройте файл макета проекта .Client (.Client/Shared/MainLayout.razor) и добавьте компонент PageTitle с заголовком веб-сайта по умолчанию (заполнитель {TITLE}):

    <PageTitle>{TITLE}</PageTitle>
    

    Замечание

    Другие файлы макета также должны получить компонент PageTitle с заголовком веб-сайта по умолчанию.

    Дополнительные сведения см. в статье Управление содержимым head в приложениях ASP.NET Core Blazor.

  7. Удалите следующие строки из .Client/Program.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  8. Обновление .Server/Program.cs:

    Добавьте в проект компонент Razor и интерактивные службы компонентов WebAssembly. Вызовите AddRazorComponents с помощью цепочки вызовов к AddInteractiveWebAssemblyComponents. Вызов AddRazorComponents добавляет службы антифоргерии (AddAntiforgery) по умолчанию.

    builder.Services.AddRazorComponents()
        .AddInteractiveWebAssemblyComponents();
    

    Добавьте антифоргерское ПО промежуточного слоя в конвейер обработки запросов.

    Поместите следующую строку после вызова app.UseHttpsRedirection. Вызов app.UseAntiforgery должен располагаться после вызовов app.UseAuthentication и app.UseAuthorization, если они присутствуют. Нет необходимости явно добавлять службы защиты от подделки запросов (builder.Services.AddAntiforgery), так как они добавляются автоматически с помощью AddRazorComponents, о котором говорилось ранее.

    app.UseAntiforgery();
    

    Удалите следующую строку:

    - app.UseBlazorFrameworkFiles();
    

    Удалите следующую строку:

    - app.MapFallbackToFile("index.html");
    

    Замените предыдущую строку вызовом MapRazorComponents, указав компонент App в качестве типа корневого компонента, и добавьте цепочки вызовов AddInteractiveWebAssemblyRenderMode и AddAdditionalAssemblies:

    app.MapRazorComponents<App>()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof({CLIENT APP NAMESPACE}._Imports).Assembly);
    

    В предыдущем примере заполнитель {CLIENT APP NAMESPACE} — это пространство имён проекта .Client (например, HostedBlazorApp.Client).

  9. Запустите решение из .Server проекта:

    Для Visual Studio убедитесь, что .Server проект выбран в обозревателе решений при запуске приложения.

    При использовании .NET CLI запустите проект из .Server папки проекта.

Обновить конфигурацию параметров службы и конечной точки

С выходом Blazor Web Apps в .NET 8 была обновлена конфигурация параметров службы и конечной точки для Blazor с введением нового API для служб интерактивных компонентов и настройки конечных точек компонентов.

Обновленные рекомендации по настройке отображаются в следующих расположениях:

Удалить Blazor Server с обходным решением маршрутизации Yarp

Если вы ранее следовали инструкциям в статье Blazor Server для миграции приложения с Yarp на .NET 6 или .NET 7, вы можете отменить шаги, которых вы придерживались, выполняя рекомендации статьи. Маршрутизация и глубокая привязка для Blazor Server с Yarp работают правильно в .NET 8.

Перенесите компоненты CascadingValue в компоненты макета

Каскадные параметры не передают данные между границами режима отрисовки, а макеты статически отрисовываются в других интерактивных приложениях. Таким образом, приложения, которые стремятся использовать каскадные параметры в интерактивных отрисованных компонентах, не смогут каскадировать значения из макета.

Ниже приведены два подхода к миграции.

Дополнительные сведения см. в разделе Каскадные значения и параметры и границы режима отрисовки.

BlazorEnableCompression Перенос свойства MSBuild

Для Blazor WebAssembly приложений, которые отключают сжатие и ориентированы на .NET 7 или более ранние версии, но собираются с помощью SDK .NET 8, свойство MSBuild BlazorEnableCompression было изменено на CompressionEnabled:

<PropertyGroup>
-   <BlazorEnableCompression>false</BlazorEnableCompression>
+   <CompressionEnabled>false</CompressionEnabled>
</PropertyGroup>

При использовании команды публикации .NET CLI используйте новое свойство:

dotnet publish -p:CompressionEnabled=false

Дополнительные сведения см. в следующих ресурсах:

Перенос компонента <CascadingAuthenticationState> на каскадные службы состояния аутентификации

В .NET 7 или более ранней CascadingAuthenticationState версии компонент упаковывается вокруг части дерева пользовательского интерфейса, например вокруг Blazor маршрутизатора, чтобы обеспечить каскадное состояние проверки подлинности:

<CascadingAuthenticationState>
    <Router ...>
        ...
    </Router>
</CascadingAuthenticationState>

В .NET 8 не используйте CascadingAuthenticationState компонент:

- <CascadingAuthenticationState>
      <Router ...>
          ...
      </Router>
- </CascadingAuthenticationState>

Вместо этого добавьте каскадные службы проверки подлинности в коллекцию служб, вызвав AddCascadingAuthenticationState в Program файле:

builder.Services.AddCascadingAuthenticationState();

Дополнительные сведения см. в следующих ресурсах:

Новая статья о проблемах кэширования HTTP

Мы добавили новую статью, в которой рассматриваются некоторые распространенные проблемы с кэшированием HTTP, которые могут возникнуть при обновлении Blazor приложений в основных версиях и устранении проблем с кэшированием HTTP.

Дополнительные сведения см. в разделе Blazor.

Новая статья о классовых библиотеках со статическим рендерингом на стороне сервера (SSR)

Мы добавили новую статью, которая обсуждает создание библиотек компонентов в Razor библиотеках классов (RCL) с использованием статического рендеринга на стороне сервера (static SSR).

Дополнительные сведения см. в разделе Библиотеки классов ASP.NET Core Razor (RCLs) со статическим серверным рендерингом (статический SSR).

Обнаружение компонентов из дополнительных сборок

При миграции с приложения Blazor Server на приложение Blazor Web App смотрите руководство по маршрутизации ASP.NET CoreBlazor, если приложение использует маршрутизируемые компоненты из дополнительных сборок, например, библиотек классов компонентов.

Удаление [Parameter] атрибута при указании параметра из строки запроса

Атрибут [Parameter] больше не требуется при предоставлении параметра из строки запроса:

- [Parameter]
  [SupplyParameterFromQuery]

Blazor Server Авторизация резервной политики скрипта

В .NET 7 Blazor Server скрипт (blazor.server.js) обслуживается статическим ПО промежуточного слоя файлов. Размещение вызова ПО промежуточного слоя для статических файлов (UseStaticFiles) в конвейере обработки запросов перед вызовом ПО промежуточного слоя авторизации (UseAuthorization) достаточно в приложениях .NET 7, чтобы отдавать скрипт Blazor анонимным пользователям.

В .NET 8 Blazor Server скрипт обслуживается собственной конечной точкой, используя маршрутизацию конечных точек. Это изменение внесено с исправлением ошибки - передача параметров в UseStaticFiles приводит к сбою (Blazor Server #45897).

Рассмотрим сценарий с несколькими клиентами, где:

  • Политики по умолчанию и резервные политики задаются одинаково.
  • Арендатор определяется по первому сегменту пути запроса (например, tld.com/tenant-name/...).
  • Запросы к конечным точкам арендатора проходят проверку подлинности с помощью дополнительной схемы проверки подлинности, которая добавляет дополнительное удостоверение к субъекту запроса.
  • Политика резервной авторизации имеет требования, которые проверяют утверждения с помощью дополнительного удостоверения.

Запросы к файлу скрипта Blazor (blazor.server.js) обрабатываются по адресу /_framework/blazor.server.js, который жестко задан во фреймворке. Запросы к файлу не проходят проверку подлинности по дополнительной схеме проверки подлинности для клиентов, но по-прежнему оспариваются резервной политикой, что приводит к возврату несанкционированного результата.

Эта проблема рассматривается для новой функции платформы в MapRazorComponents, нарушенной с помощью FallbackPolicy RequireAuthenticatedUser (dotnet/aspnetcore 51836), которая в настоящее время запланирована на выпуск .NET 9 в ноябре 2024 года. До тех пор вы можете обойти эту проблему с помощью любого из следующих трех подходов:

  • Не используйте резервную политику. [Authorize] Примените атрибут в _Imports.razor файле, чтобы применить его ко всем компонентам приложения. Для конечных точек, отличных от blazor, явно используйте [Authorize] или RequireAuthorization.

  • Добавьте [AllowAnonymous] в конечную точку /_framework/blazor.server.js в Program файле:

    app.MapBlazorHub().Add(endpointBuilder =>
    {
        if (endpointBuilder is 
            RouteEndpointBuilder
            { 
                RoutePattern: { RawText: "/_framework/blazor.server.js" }
            })
        {
            endpointBuilder.Metadata.Add(new AllowAnonymousAttribute());
        }
    });
    
  • Зарегистрируйте пользовательский AuthorizationHandler, который проверяет HttpContext, чтобы разрешить файл /_framework/blazor.server.js.

Докер

Обновление образов Docker

Для приложений с помощью Docker обновите инструкции и скрипты DockerfileFROM . Используйте базовый образ, включающий среду выполнения .NET 8. Рассмотрим следующее docker pull различие между ASP.NET Core в .NET 7 и .NET 8:

- docker pull mcr.microsoft.com/dotnet/aspnet:7.0
+ docker pull mcr.microsoft.com/dotnet/aspnet:8.0

Обновление порта Docker

Порт по умолчанию ASP.NET Core, настроенный в образах контейнеров .NET, обновлен с порта 80 до 8080.

Новая ASPNETCORE_HTTP_PORTS переменная среды была добавлена в качестве более простой альтернативы ASPNETCORE_URLS.

Дополнительные сведения можно найти здесь

Кардинальные изменения

Используйте статьи в статье Критические изменения в .NET, чтобы найти критические изменения , которые могут применяться при обновлении приложения до более новой версии .NET.