Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье рассматриваются наиболее значительные изменения в ASP.NET Core в .NET 6 со ссылками на соответствующую документацию.
Улучшения ASP.NET Core MVC и Razor
Минимальные API
Архитектура минимальных API позволяет создавать API для HTTP с минимальным числом зависимостей. Они идеально подходят для микрослужб и приложений, которым нужен небольшой набор файлов, компонентов и зависимостей на платформе ASP.NET Core. Дополнительные сведения см. в разделе:
- Руководство. Создание минимального API с помощью ASP.NET Core
- Различия между минимальными API и API с контроллерами
- Краткий справочник по минимальным API
- Примеры кода перенесены на новую минимальную модель размещения в 6.0
SignalR
Тег долгосрочной активности для подключений SignalR
SignalR использует новый объект Microsoft.AspNetCore.Http.Features.IHttpActivityFeature.Activity для добавления тега http.long_running к действию запроса.
IHttpActivityFeature.Activity используется службами APM, такими как Azure Monitor Application Insights, чтобы фильтровать запросы SignalR и предотвращать создание предупреждений о длительных запросах.
Улучшения производительности SignalR
- Распределить HubCallerClients один раз на соединение вместо каждого вызова метода концентратора.
- Избегайте выделения закрытия в SignalR
DefaultHubDispatcher.Invoke. Состояние передается в локальную статическую функцию через параметры, чтобы избежать выделения памяти для замыкания. Дополнительные сведения см. в этом пулл-реквесте на GitHub. - Выделение одного StreamItemMessage на поток, а не на каждый элемент потока в потоковой передаче с сервера клиенту. Дополнительные сведения см. в этом пулл-реквесте на GitHub.
Компилятор Razor
Компилятор Razor обновлен для использования генераторов исходного кода
Теперь компилятор Razor основан на генераторах исходного кода C#. Генераторы источников выполняются во время компиляции и проверяют, какие файлы компилируются для создания дополнительных файлов, скомпилированных вместе с остальной частью проекта. Использование генераторов исходного кода упрощает компилятор Razor и значительно сокращает время сборки.
Компилятор Razor больше не создает отдельную сборку Views
В компиляторе Razor ранее использовался двухэтапный процесс компиляции, при котором создавалась отдельная сборка Views, содержащая созданные представления и страницы (файлы .cshtml), определенные в приложении. Созданные типы были общедоступными и находились в пространстве имен AspNetCore.
Обновленный компилятор Razor создает представления и типы страниц в главной сборке проекта. Эти типы теперь по умолчанию создаются как внутренние запечатанные в пространстве имен AspNetCoreGeneratedDocument. Это изменение улучшает производительность сборки, позволяет развертывать один файл и позволяет этим типам участвовать в Горячей перезагрузке.
Дополнительные сведения об этом изменении см. в связанной теме объявления на GitHub.
улучшения производительности ASP.NET Core и API
Внесено множество изменений для уменьшения количества выделений и повышения производительности в стеке:
- Метод расширения app.Use без выделения. Новая перегрузка метода
app.Useтребует передачи контекста вnext, что позволяет избежать двух внутренних выделений памяти для каждого запроса, которые требуются при использовании другой перегрузки. - Уменьшение количества выделений памяти при доступе к HttpRequest.Cookies. Дополнительные сведения см. здесь на GitHub.
- Используйте LoggerMessage.Define только для веб-сервера HTTP.sys Windows. Вызовы методов расширения ILogger были заменены вызовами
LoggerMessage.Define. - Снизить накладные расходы на каждое соединение в SocketConnection на ~30 %. Дополнительные сведения см. в этом пулл-реквесте на GitHub.
- Сокращено количество выделений за счет удаления делегатов ведения журналов в универсальных типах. Дополнительные сведения см. в этом пулл-реквесте на GitHub.
- Более быстрый доступ GET (примерно на 50% быстрее) к часто используемым функциям, включая IHttpRequestFeature, IHttpResponseFeature, IHttpResponseBodyFeature, IRouteValuesFeature и IEndpointFeature. Дополнительные сведения см. в этом пулл-реквесте на GitHub.
- Используйте одиночные строки для известных имён заголовков, даже если они не в сохранённом блоке заголовков. Использование строки в одном экземпляре помогает предотвратить дублирование одной и той же строки в долговременных соединениях, например в Microsoft.AspNetCore.WebSockets. Дополнительные сведения см. здесь на GitHub.
- Повторно используйте HttpProtocol CancellationTokenSource в Kestrel. Используйте новый метод CancellationTokenSource.TryReset для
CancellationTokenSource, чтобы повторно использовать токены, если они не были отменены. Дополнительные сведения см. в описании этой ошибки на GitHub и в этом видео. - Реализуйте и используйте AdaptiveCapacityDictionary в Microsoft.AspNetCore.HttpRequestCookieCollection для более эффективного доступа к словарям. Дополнительные сведения см. в этом пулл-реквесте на GitHub.
Уменьшение объема занимаемой памяти для бездействующих подключений TLS
Для длительных подключений TLS с редко передаваемыми данными мы значительно уменьшили объем памяти, занимаемый приложениями ASP.NET Core в .NET 6. Это поможет улучшить масштабируемость таких сценариев, как серверы WebSocket. Это стало возможно благодаря многочисленным улучшениям в System.IO.Pipelines, SslStream и Kestrel. В следующих разделах подробно описаны некоторые улучшения, которые привели к уменьшению объема занимаемой памяти.
Уменьшение размера System.IO.Pipelines.Pipe
Для каждого установленного соединения в Kestrel выделяются два канала:
- транспортный уровень к приложению для обработки запроса.
- уровень приложения к транспортировке для ответа.
За счет уменьшения размера System.IO.Pipelines.Pipe с 368 байт до 264 байт (примерно на 28,2%) обеспечивается экономия 208 байт на подключение (104 байт на канал).
Пул SocketSender
Объекты SocketSender (подкласс SocketAsyncEventArgs) имеют размер около 350 байт во время выполнения. Вместо выделения нового объекта SocketSender для каждого соединения их можно поместить в пул. Объекты SocketSender можно поместить в пул, так как отправка обычно выполняется очень быстро. Использование пулов сокращает затраты на подключение. Вместо выделения 350 байт на одно соединение, выделяется только 350 байт на IOQueue. Выделение выполняется по очереди во избежание конкуренции. На нашем сервере WebSocket с 5000 неактивными подключениями мы перешли от выделения ~1,75 МБ (350 байт * 5000) к выделению ~2,8 КБ (350 байт * 8) для объектов SocketSender.
Чтение нулевых байтов с SslStream
Операции чтения без буферизации — это методика, применяемая в ASP.NET Core, чтобы избежать аренды памяти из пула памяти, если на сокете нет доступных данных. До этого изменения наш сервер WebSocket с 5000 неактивными подключениями требовал 200 МБ без TLS по сравнению с 800 МБ с TLS. Некоторые из этих выделений (4 КБ на подключение) были вызваны необходимостью Kestrel удерживать ArrayPool<T> в буфере во время ожидания завершения операций чтения SslStream. Учитывая, что эти соединения были неактивными, ни одна из операций чтения не завершилась и не вернула буфер в ArrayPool, из-за чего ArrayPool нужно было выделять больше памяти. Оставшиеся выделения памяти были в самом SslStream: 4 КБ для подтверждений TLS и буфер 32 КБ для обычных операций чтения. В .NET 6, когда пользователь выполняет чтение нуля байтов на SslStream и не имеет доступных данных, SslStream внутренне выполняет чтение нуля байтов в обёрнутом базовом потоке. В лучшем случае (неактивное подключение) эти изменения приводят к экономии 40 КБ на подключение, одновременно позволяя объекту-получателю (Kestrel) получать уведомления о доступности данных без удержания неиспользуемых буферов.
Чтение нулевого байта с PipeReader
Поскольку для SslStream теперь поддерживаются операции чтения без буферизации, была добавлена возможность выполнять чтение нулевого количества байтов в StreamPipeReader, который является внутренним типом и преобразует Stream в PipeReader. В Kestrel элемент StreamPipeReader используется для адаптации базового SslStream в PipeReader. Поэтому было необходимо открыть семантику чтения нулевого байта на PipeReader.
Теперь можно создать объект PipeReader, который поддерживает чтение нулевого числа байт для любого используемого потока Stream, поддерживающего соответствующую семантику (например, SslStream, NetworkStream и др.) с помощью следующего API.
var reader = PipeReader.Create(stream, new StreamPipeReaderOptions(useZeroByteReads: true));
Удалите плиты из SlabMemoryPool
Чтобы уменьшить фрагментацию кучи, в Kestrel применялась методика выделения слэбов памяти размером 128 КБ в составе пула памяти. Затем эти слэбы делились на блоки размером 4 КБ, которые использовались внутри Kestrel. Размер этих slab должен был быть больше 85 КБ, чтобы принудительно выделить их в куче больших объектов и предотвратить перемещение этого массива в ходе ГЦ. Однако с появлением нового поколения метода сборки мусора, кучи закрепленных объектов (POH), больше не имеет смысла распределять блоки по slab (плита). Kestrel теперь непосредственно выделяет блоки на куче POH, уменьшая сложность, связанную с управлением пулом памяти. Это изменение должно упростить выполнение будущих улучшений, например упростить уменьшение пула памяти, используемого Kestrel.
Поддержка IAsyncDisposable
Теперь контроллеры, IAsyncDisposable Pages и компоненты представления могут использовать Razor. К соответствующим интерфейсам в фабриках и активаторах были добавлены асинхронные версии:
- Новые методы предлагают реализацию интерфейса по умолчанию, которая передает выполнение синхронной версии и вызывает Dispose.
- Реализации переопределяют реализацию по умолчанию и управляют процессом освобождения
IAsyncDisposable. - Когда реализуются обе интерфейсы
IAsyncDisposableиIDisposable, предпочтение отдаетсяIAsyncDisposable. - Расширители должны переопределять новые методы, включаемые для поддержки экземпляров
IAsyncDisposable.
IAsyncDisposable полезно использовать при работе с:
- Асинхронные перечислители, например, в асинхронных потоках.
- неуправляемыми ресурсами, имеющими ресурсоемкие операции ввода-вывода, требующие освобождения ресурсов.
При реализации этого интерфейса используйте метод DisposeAsync для освобождения ресурсов.
Рассмотрим контроллер, создающий и использующий Utf8JsonWriter.
Utf8JsonWriter является ресурсом IAsyncDisposable:
public class HomeController : Controller, IAsyncDisposable
{
private Utf8JsonWriter? _jsonWriter;
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
_jsonWriter = new Utf8JsonWriter(new MemoryStream());
}
IAsyncDisposable должен реализовывать DisposeAsync:
public async ValueTask DisposeAsync()
{
if (_jsonWriter is not null)
{
await _jsonWriter.DisposeAsync();
}
_jsonWriter = null;
}
Порт Vcpkg для клиента C++ SignalR
Vcpkg — это кроссплатформенный диспетчер пакетов командной строки для библиотек C и C++. Мы недавно добавили порт в vcpkg, чтобы обеспечить нативную поддержку CMake для клиента C++ SignalR.
vcpkg также работает с MSBuild.
Клиент SignalR можно добавить в проект CMake с помощью следующего фрагмента кода, если vcpkg включен в файл цепочки инструментов:
find_package(microsoft-signalr CONFIG REQUIRED)
link_libraries(microsoft-signalr::microsoft-signalr)
С помощью предыдущего фрагмента SignalRклиент C++ готов к использованию #include и используется в проекте без дополнительной конфигурации. Полный пример приложения на C++, использующего SignalRклиент C++, можно найти в репозитории halter73/SignalR-Client-Cpp-Sample.
Blazor
Изменения шаблона проекта
Для приложений Blazor внесено несколько изменений в шаблон проекта, в частности, файл Pages/_Layout.cshtml использовался для компоновки содержимого, которое в более ранних приложениях _Host.cshtml отображалось в файле Blazor Server. Изучите изменения, создав приложение из шаблона проекта 6.0 или обратившись к справочному источнику ASP.NET Core по шаблонам проектов:
Blazor WebAssembly Поддержка встроенных зависимостей
Приложения Blazor WebAssembly могут использовать зависимости в машинном коде, созданные для выполнения в WebAssembly. Дополнительные сведения. см. в статье Собственные зависимости Blazor WebAssembly ASP.NET Core.
Компиляция Ahead-of-time (AOT) WebAssembly и повторная компоновка в среде выполнения
Blazor WebAssembly поддерживает упреждающую компиляцию (AOT), с помощью которой вы можете скомпилировать код .NET непосредственно в WebAssembly. Компиляция AOT позволяет повысить производительность среды выполнения за счет увеличения размера приложения. Перекомпоновка .NET WebAssembly исполняемой среды отсекает неиспользуемый код и улучшает скорость загрузки. Дополнительные сведения см. в разделах Компиляция Ahead-of-time (AOT) и Релинковка во время выполнения.
Продолжать сохранять предварительно визуализированное состояние
Blazor поддерживает сохранение состояния на предварительно отображенной странице, чтобы не нужно было повторно создавать состояние при полной загрузке приложения. Дополнительные сведения см. в разделе "Интеграция компонентов ASP.NET Core Razor с MVC или Razor Страницами".
Границы ошибок
Границы ошибок предоставляют удобный подход к обработке исключений на уровне пользовательского интерфейса. Дополнительные сведения см. в статье Обработка ошибок в приложениях Blazor ASP.NET Core.
Поддержка SVG
Элемент <foreignObject> поддерживается для отображения внутри SVG произвольного HTML-кода. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Поддержка Blazor Server передачи массива байтов в JS Interop
Blazor поддерживает оптимизированное взаимодействие с JS через массивы байтов, что позволяет избежать кодирования и декодирования массивов байтов в Base64. Дополнительные сведения см. на следующих ресурсах:
- Вызов функций JavaScript из методов .NET в ASP.NET Core Blazor
- Вызов методов .NET из функций JavaScript в Blazor ASP.NET Core
Усовершенствования строк запросов
Улучшена поддержка работы со строками запросов. Дополнительные сведения см. в разделе Навигация ASP.NET CoreBlazor.
Привязка для выбора нескольких элементов
Привязка поддерживает выбор нескольких вариантов с элементами <input>. Дополнительные сведения см. на следующих ресурсах:
Контроль содержимого <head> (head)
Компоненты Razor могут изменять содержимое элемента HTML <head> страницы, в том числе задавать заголовок страницы (элемент <title>) и изменять метаданные (элементы <meta>). Дополнительные сведения см. в разделе Управление содержимым <head> в приложениях Blazor ASP.NET Core.
Создание компонентов Angular и React
Создавать компоненты JavaScript, характерные для платформы, можно из компонентов Razor для веб-платформ, таких как Angular или React. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Отрисовка компонентов из JavaScript
Динамический рендеринг компонентов Razor из JavaScript для существующих приложений JavaScript. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Пользовательские элементы
Доступна экспериментальная поддержка для создания пользовательских элементов, использующих стандартные интерфейсы HTML. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Выведение универсальных типов компонентов из родительских компонентов
Компонент-предок может каскадировать параметр типа по имени к потомкам, используя новый атрибут [CascadingTypeParameter]. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Динамически отображаемые компоненты
Используйте новый встроенный компонент DynamicComponent для отображения компонентов по типу. Дополнительные сведения см. в разделе Динамически отображаемые компоненты Razor ASP.NET Core.
Улучшенная доступность Blazor
Используйте новый компонент FocusOnNavigate, чтобы установить фокус пользовательского интерфейса на элемент на основе селектора CSS после перехода с одной страницы на другую. Дополнительные сведения см. в разделе Маршрутизация ASP.NET CoreBlazor.
Поддержка аргументов пользовательских событий
Blazor поддерживает аргументы пользовательских событий, которые позволяют передавать произвольные данные в обработчики событий .NET с пользовательскими событиями. Дополнительные сведения см. в статье Обработка событий Blazor в ASP.NET Core.
Обязательные параметры
Примените новый атрибут [EditorRequired], чтобы указать обязательный параметр компонента. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Размещение файлов JavaScript рядом со страницами, представлениями и компонентами.
Размещайте совместно файлы JavaScript для страниц, представлений и компонентов Razor — это удобный способ организации скриптов в приложении. Дополнительные сведения см. в разделе Взаимодействие JavaScript Blazor ASP.NET Core (интероп JS).
Инициализаторы JavaScript
Инициализаторы JavaScript выполняют логику до и после загрузки приложения Blazor. Дополнительные сведения см. в разделе Взаимодействие JavaScript Blazor ASP.NET Core (интероп JS).
Потоковая передача при взаимодействии с JavaScript
Blazor теперь поддерживает потоковую передачу данных между .NET и JavaScript. Дополнительные сведения см. на следующих ресурсах:
Ограничения универсального типа
Теперь поддерживаются параметры универсального типа. Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.
Макет развертывания WebAssembly
Используйте макет развертывания, чтобы разрешить загрузку приложений Blazor WebAssembly в условиях ограниченной безопасности. Дополнительные сведения см. в разделе Макет развертывания для размещенных приложений ASP.NET CoreBlazor WebAssembly.
Новые Blazor статьи
В дополнение к функциям Blazor, описанным в предыдущих разделах, доступны новые статьи о Blazor по следующим темам:
-
Загрузки файлов Blazor ASP.NET Core: узнайте, как скачать файл, используя собственное взаимодействие
byte[]для потоковой передачи, чтобы обеспечить эффективную передачу данных клиенту. - Отображение изображений и документов в ASP.NET Core Blazor: узнайте, как работать с изображениями и документами в Blazor приложениях, включая потоковую передачу изображений и данных документа.
Создание приложений Blazor Hybrid с помощью .NET MAUI, WPF и Windows Forms
Используйте Blazor Hybrid для объединения настольных и мобильных собственных клиентских платформ с .NET и Blazor:
- .NET Multi-platform App UI (.NET MAUI) представляет собой кросс-платформенную платформу для создания собственных мобильных и настольных приложений с помощью C# и XAML.
- Приложения Blazor Hybrid можно создавать с помощью платформ Windows Presentation Foundation (WPF) и Windows Forms.
Внимание
Blazor Hybrid находится на этапе предварительной версии и не следует использовать в рабочих приложениях до финального выпуска.
Дополнительные сведения см. на следующих ресурсах:
- Ознакомьтесь с документацией по ASP.NET Core Blazor Hybrid
- Что такое .NET MAUI?
- Блог Microsoft .NET (категория: ".NET MAUI")
Kestrel
HTTP/3 в настоящее время находится в разработке, поэтому подлежит изменению. Поддержка HTTP/3 в ASP.NET Core не выпущена — это предварительная версия функции, включенная в .NET 6.
Kestrel теперь поддерживает HTTP/3. Дополнительные сведения см. в разделе Использование протокола HTTP/3 с веб-сервером Kestrel ASP.NET Core и запись в блоге Поддержка протокола HTTP/3 в .NET 6.
Новые категории логирования Kestrel для выбранного логирования
До этого изменения включение детализированного ведения журнала для Kestrel было чрезмерно дорогостоящим, так как всему Kestrel было присвоено общее имя категории журнала Microsoft.AspNetCore.Server.Kestrel.
Microsoft.AspNetCore.Server.Kestrel по-прежнему можно использовать, но следующие новые подкатегории обеспечивают более полный контроль ведения журнала:
-
Microsoft.AspNetCore.Server.Kestrel(текущая категория):ApplicationError,ConnectionHeadResponseBodyWrite,ApplicationNeverCompleted,RequestBodyStart,RequestBodyDone,RequestBodyNotEntirelyRead,RequestBodyDrainTimedOut,ResponseMinimumDataRateNotSatisfied,InvalidResponseHeaderRemoved,HeartbeatSlow. -
Microsoft.AspNetCore.Server.Kestrel.BadRequests:ConnectionBadRequest,RequestProcessingError,RequestBodyMinimumDataRateNotSatisfied. -
Microsoft.AspNetCore.Server.Kestrel.Connections:ConnectionAccepted,ConnectionStart,ConnectionStop,ConnectionPause,ConnectionResume,ConnectionKeepAlive,ConnectionRejected,ConnectionDisconnect,NotAllConnectionsClosedGracefully,NotAllConnectionsAborted.ApplicationAbortedConnection -
Microsoft.AspNetCore.Server.Kestrel.Http2:Http2ConnectionError,Http2ConnectionClosing;Http2ConnectionClosedHttp2StreamErrorHttp2StreamResetAbortHPackDecodingErrorHPackEncodingErrorHttp2FrameReceivedHttp2FrameSendingHttp2MaxConcurrentStreamsReached -
Microsoft.AspNetCore.Server.Kestrel.Http3:Http3ConnectionError,Http3ConnectionClosing,Http3ConnectionClosed,Http3StreamAbort,Http3FrameReceived,Http3FrameSending.
Существующие правила продолжают работать, но теперь можно более избирательно выбирать, какие правила включить. Например, можно значительно сократить издержки на наблюдения, если включить ведение журнала Debug только для недопустимых запросов. Для этого используется следующая конфигурация:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Kestrel.BadRequests": "Debug"
}
}
Фильтрация журналов применяет правила с наиболее длинным соответствующим префиксом категории. Дополнительные сведения см. в разделе Применение правил фильтрации.
Выдача KestrelServerOptions через событие EventSource
KestrelEventSource выдает новое событие, содержащее сериализованный в формате JSON KestrelServerOptions, при включении подробного режимаEventLevel.LogAlways. Это событие упрощает рассуждения о поведении сервера при анализе собранных трассировок. Ниже приведен пример полезной нагрузки события в формате JSON.
{
"AllowSynchronousIO": false,
"AddServerHeader": true,
"AllowAlternateSchemes": false,
"AllowResponseHeaderCompression": true,
"EnableAltSvc": false,
"IsDevCertLoaded": true,
"RequestHeaderEncodingSelector": "default",
"ResponseHeaderEncodingSelector": "default",
"Limits": {
"KeepAliveTimeout": "00:02:10",
"MaxConcurrentConnections": null,
"MaxConcurrentUpgradedConnections": null,
"MaxRequestBodySize": 30000000,
"MaxRequestBufferSize": 1048576,
"MaxRequestHeaderCount": 100,
"MaxRequestHeadersTotalSize": 32768,
"MaxRequestLineSize": 8192,
"MaxResponseBufferSize": 65536,
"MinRequestBodyDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
"MinResponseDataRate": "Bytes per second: 240, Grace Period: 00:00:05",
"RequestHeadersTimeout": "00:00:30",
"Http2": {
"MaxStreamsPerConnection": 100,
"HeaderTableSize": 4096,
"MaxFrameSize": 16384,
"MaxRequestHeaderFieldSize": 16384,
"InitialConnectionWindowSize": 131072,
"InitialStreamWindowSize": 98304,
"KeepAlivePingDelay": "10675199.02:48:05.4775807",
"KeepAlivePingTimeout": "00:00:20"
},
"Http3": {
"HeaderTableSize": 0,
"MaxRequestHeaderFieldSize": 16384
}
},
"ListenOptions": [
{
"Address": "https://127.0.0.1:7030",
"IsTls": true,
"Protocols": "Http1AndHttp2"
},
{
"Address": "https://[::1]:7030",
"IsTls": true,
"Protocols": "Http1AndHttp2"
},
{
"Address": "http://127.0.0.1:5030",
"IsTls": false,
"Protocols": "Http1AndHttp2"
},
{
"Address": "http://[::1]:5030",
"IsTls": false,
"Protocols": "Http1AndHttp2"
}
]
}
Новое событие DiagnosticSource для отклоненных HTTP-запросов
Kestrel теперь создает новое событие DiagnosticSource для HTTP-запросов, отклоненных на уровне сервера. До этого изменения возможности наблюдать за этими отклоненными запросами не было. Новое событие DiagnosticSourceMicrosoft.AspNetCore.Server.Kestrel.BadRequest содержит объект IBadRequestExceptionFeature, который можно использовать для анализа причины отклонения запроса.
using Microsoft.AspNetCore.Http.Features;
using System.Diagnostics;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var diagnosticSource = app.Services.GetRequiredService<DiagnosticListener>();
using var badRequestListener = new BadRequestEventListener(diagnosticSource,
(badRequestExceptionFeature) =>
{
app.Logger.LogError(badRequestExceptionFeature.Error, "Bad request received");
});
app.MapGet("/", () => "Hello world");
app.Run();
class BadRequestEventListener : IObserver<KeyValuePair<string, object>>, IDisposable
{
private readonly IDisposable _subscription;
private readonly Action<IBadRequestExceptionFeature> _callback;
public BadRequestEventListener(DiagnosticListener diagnosticListener,
Action<IBadRequestExceptionFeature> callback)
{
_subscription = diagnosticListener.Subscribe(this!, IsEnabled);
_callback = callback;
}
private static readonly Predicate<string> IsEnabled = (provider) => provider switch
{
"Microsoft.AspNetCore.Server.Kestrel.BadRequest" => true,
_ => false
};
public void OnNext(KeyValuePair<string, object> pair)
{
if (pair.Value is IFeatureCollection featureCollection)
{
var badRequestFeature = featureCollection.Get<IBadRequestExceptionFeature>();
if (badRequestFeature is not null)
{
_callback(badRequestFeature);
}
}
}
public void OnError(Exception error) { }
public void OnCompleted() { }
public virtual void Dispose() => _subscription.Dispose();
}
Дополнительные сведения см. в разделе Ведение журнала и диагностика в Kestrel.
Создайте контекст соединения (ConnectionContext) из принятого сокета (Accept Socket)
Новый SocketConnectionContextFactory предоставляет возможность создать ConnectionContext на основе принятого сокета. Это предоставляет возможность создавать пользовательские решения, основанные на сокетах IConnectionListenerFactory, не теряя при этом все преимущества производительности и организации пулов в SocketConnection.
См. пример пользовательского IConnectionListenerFactory, в котором показано, как использовать SocketConnectionContextFactory.
Kestrel является профилем запуска по умолчанию для Visual Studio
Профиль запуска по умолчанию для всех новых веб-проектов dotnet — Kestrel. Запуск Kestrel значительно ускоряется, что повышает удобство при разработке приложений.
IIS Express по-прежнему можно использовать в качестве профиля запуска для таких сценариев, как проверка подлинности Windows или общий доступ к портам.
Порты localhost для Kestrel являются случайными
Дополнительные сведения см. в разделе Шаблон генерируемых портов для Kestrel в этом документе.
Проверка подлинности и авторизация
Серверы проверки подлинности
.NET 3 и .NET 5 использовали IdentityServer4 в рамках нашего шаблона для поддержки выдачи токенов JWT для SPA и Blazor приложений. Шаблоны теперь используют сервер Duende Identity.
Если вы расширяете модели идентификации и обновляете текущие проекты, измените пространства имен в своем коде с IdentityServer4.IdentityServer на Duende.IdentityServer и следуйте предоставленным инструкциям по миграции.
Модель лицензирования для Duende Identity Server была изменена на перекрестную лицензию, из-за чего может потребоваться оплатить лицензию, если она используется в рабочей среде в коммерческих целях. Дополнительные сведения см. на странице лицензии Duende.
Отложенное согласование сертификата клиента
Теперь разработчики могут согласиться на использование отложенного согласования сертификата клиента, указав ClientCertificateMode.DelayCertificate в HttpsConnectionAdapterOptions. Это работает только с подключениями HTTP/1.1, так как HTTP/2 запрещает отложенное повторное согласование сертификата. Вызывающий объект этого API должен поместить в буфер текст запроса, прежде чем запрашивать сертификат клиента:
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.AspNetCore.WebUtilities;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(adapterOptions =>
{
adapterOptions.ClientCertificateMode = ClientCertificateMode.DelayCertificate;
});
});
var app = builder.Build();
app.Use(async (context, next) =>
{
bool desiredState = GetDesiredState();
// Check if your desired criteria is met
if (desiredState)
{
// Buffer the request body
context.Request.EnableBuffering();
var body = context.Request.Body;
await body.DrainAsync(context.RequestAborted);
body.Position = 0;
// Request client certificate
var cert = await context.Connection.GetClientCertificateAsync();
// Disable buffering on future requests if the client doesn't provide a cert
}
await next(context);
});
app.MapGet("/", () => "Hello World!");
app.Run();
OnCheckSlidingExpiration событие для управления продлением cookie
Скользящее истечение срока проверки подлинности Cookie теперь можно настроить или отключить, используя новый OnCheckSlidingExpiration. Например, это событие может использоваться одностраничным приложением, которое должно периодически выполнять проверку связи с сервером, не влияя на сеанс проверки подлинности.
Разное
Горячая перезагрузка
Горячая перезагрузка позволяет быстро вносить обновления в пользовательский интерфейс и код работающих приложений без потери состояния приложения, чтобы ускорить разработку и повысить ее продуктивность. Дополнительные сведения см. в статьях Поддержка Горячей перезагрузки .NET для ASP.NET Core и Обновление о ходе разработки Горячей перезагрузки .NET и основные моменты в Visual Studio 2022.
Улучшенные шаблоны одностраничных приложений (SPA)
Шаблоны проектов ASP.NET Core были обновлены для Angular и React. Теперь в них используется улучшенный шаблон для одностраничных приложений, которые обеспечивает большую гибкость и более точно соответствуют шаблонам для интерфейса современных веб-приложений.
Ранее в шаблоне ASP.NET Core для Angular и React во время разработки использовалось специализированное ПО промежуточного слоя для запуска сервера разработки для интерфейсной платформы, а затем запросы прокси от ASP.NET Core к серверу разработки. Логика запуска фронтенд-сервера разработки была предназначена для интерфейса командной строки соответствующего фронтенд-фреймворка. Для поддержки дополнительных интерфейсных платформ, использующих этот шаблон, нужно было добавлять дополнительную логику в ASP.NET Core.
Обновленные шаблоны ASP.NET Core для Angular и React в .NET 6 меняют используемую ранее схему и используют преимущества встроенной поддержки прокси-сервера на серверах разработки большинства современных интерфейсных платформ. При запуске приложения ASP.NET Core интерфейсный сервер разработки запускается так же, как и раньше, но сервер разработки настроен на передачу запросов через прокси-сервер к внутреннему процессу ASP.NET Core. Все настройки, связанные с настройкой прокси-сервера, являются частью приложения, а не ASP.NET Core. Настроить проекты ASP.NET Core для работы с другими фронтенд-фреймворками теперь просто: настройте сервер разработки для выбранного фреймворка так, чтобы он проксировал к ASP.NET Core бэкэнду по образцу, использованному в шаблонах Angular и React.
Для кода запуска приложения ASP.NET Core больше не нужна отдельная логика для одностраничного приложения. Логика для запуска интерфейсного сервера разработки во время разработки внедряется в приложение во время выполнения с помощью нового пакета Microsoft.AspNetCore.SpaProxy. Маршрутизация по умолчанию обрабатывается с помощью маршрутизации конечных точек вместо специализированного промежуточного ПО для одностраничных приложений.
Соответствующие шаблоны все еще можно запускать в виде отдельного проекта в Visual Studio или с помощью dotnet run из командной строки. При публикации приложения интерфейсный код в папке ClientApp строится и собирается, как и раньше, в корне узла приложения ASP.NET Core и предоставляется в виде статических файлов. Скрипты, содержащиеся в шаблоне, настраивают интерфейсный сервер разработки для использования протокола HTTPS с помощью сертификата разработки ASP.NET Core.
Предварительная поддержка HTTP/3 в .NET 6
HTTP/3 в настоящее время находится в разработке, поэтому подлежит изменению. Поддержка HTTP/3 в ASP.NET Core не выпущена — это предварительная версия функции, включенная в .NET 6.
См. запись блога Поддержка HTTP/3 в .NET 6.
Аннотации для ссылочных типов, допускающих значения NULL
Части ASP.NET Core в исходном коде .NET 6 имели применены заметки, допускавшие значение NULL .
Используя новую функцию допустимости значений NULL в C# 8, ASP.NET Core может обеспечить дополнительную безопасность во время компиляции при обработке ссылочных типов. Например, защита от исключений ссылок на null. В проектах, которые выбрали использование заметок о допустимости значений NULL, могут появиться новые предупреждения времени сборки от API ASP.NET Core.
Чтобы включить ссылочные типы, допускающие значения NULL, добавьте в файлы проекта следующее свойство:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Дополнительные сведения см. в статье Ссылочные типы, допускающие значение NULL.
Анализ исходного кода
Были добавлены несколько анализаторов платформы компилятора .NET, которые проверяют код приложения на наличие проблем, таких как неправильная конфигурация промежуточного программного обеспечения или его порядок, конфликты маршрутизации и т. д. Дополнительные сведения см. в разделе "Анализ диагностического кода" в приложениях ASP.NET Core.
Улучшения шаблонов веб-приложений
Шаблоны веб-приложений:
- Используют новую минимальную модель размещения.
- Значительно сокращают количество файлов и строк кода, необходимых для создания приложения. Например, пустое веб-приложение ASP.NET Core создает один файл C# с четырьмя строками кода и является полноценным приложением.
- Объединяют
Startup.csиProgram.csв один файлProgram.cs. - Используют инструкции верхнего уровня для минимизации кода, необходимого для приложения.
- Используют глобальные директивы
using, чтобы исключить или минимизировать числу требуемых строк инструкцийusing.
Порты, созданные на основе шаблона для Kestrel
Во время создания проекта назначаются случайные порты для использования веб-сервером Kestrel. Случайные порты помогают уменьшить конфликт портов, если на одном компьютере выполняется несколько проектов.
При создании проекта случайный HTTP-порт от 5000 до 5300 и случайный порт HTTPS от 7000 до 7300 указывается в созданном Properties/launchSettings.json файле. Порты можно изменить в Properties/launchSettings.json файле. Если порт не указан, Kestrel по умолчанию использует порт HTTP 5000 и HTTPS 5001. Дополнительные сведения см. в разделе "Настройка конечных точек для Kestrel веб-сервера".
Новые параметры ведения журнала по умолчанию
В appsettings.json и appsettings.Development.json были внесены следующие изменения:
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Microsoft.AspNetCore": "Warning"
Изменение от "Microsoft": "Warning" приводит к ведению журнала всех информационных сообщений из пространства имен "Microsoft.AspNetCore": "Warning", кроме Microsoft. Например, Microsoft.EntityFrameworkCore теперь заносится в журнал на уровне информации.
Автоматическое добавление промежуточного ПО для страницы обработки исключений разработчика
В среде разработки добавляется по умолчанию. Больше не нужно добавлять следующий код в приложения пользовательского веб-интерфейса:
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
Поддержка заголовков запросов в кодировке Latin1 в HttpSysServer
HttpSysServer теперь поддерживает декодирование заголовков запросов, Latin1 закодированных путем присвоения свойству UseLatin1RequestHeaders в HttpSysOptions значения true:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(o => o.UseLatin1RequestHeaders = true);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Журналы модуля ASP.NET Core включают метки времени и идентификатор процесса
Расширенные журналы диагностики модуля ASP.NET Core (ANCM) для IIS (ANCM) содержат метки времени и идентификатор процесса, создающего журналы. Запись меток времени и идентификатора процесса в журналы упрощает диагностику проблем с перекрывающимися перезапусками процессов в IIS при выполнении нескольких рабочих процессов IIS.
Полученные журналы теперь выглядят как пример, показанный ниже:
[2021-07-28T19:23:44.076Z, PID: 11020] [aspnetcorev2.dll] Initializing logs for 'C:\<path>\aspnetcorev2.dll'. Process Id: 11020. File Version: 16.0.21209.0. Description: IIS ASP.NET Core Module V2. Commit: 96475a2acdf50d7599ba8e96583fa73efbe27912.
[2021-07-28T19:23:44.079Z, PID: 11020] [aspnetcorev2.dll] Resolving hostfxr parameters for application: '.\InProcessWebSite.exe' arguments: '' path: 'C:\Temp\e86ac4e9ced24bb6bacf1a9415e70753\'
[2021-07-28T19:23:44.080Z, PID: 11020] [aspnetcorev2.dll] Known dotnet.exe location: ''
Настраиваемый размер буфера для неиспользованных входящих запросов для IIS
Сервер IIS ранее помещал в буфер только 64 КБ текстов неиспользованных запросов. Размер буфера 64 КБ привел к ограничению операций чтения этим максимальным размером, что влияло на производительность при больших входящих объектах, таких как отправка данных. В .NET 6 размер буфера по умолчанию измене с 64 КиБ на 1 МиБ, что повышает пропускную способность для отправок больших объемов данных. В наших тестах отправка 700 МиБ, которая занимала 9 секунд, теперь занимает всего 2,5 секунды.
Недостатком большего размера буфера является увеличение потребления памяти для каждого запроса, когда приложение не считывает текст запроса быстро. Поэтому, помимо изменения размера буфера по умолчанию, теперь появилась возможность настроить размер буфера для приложений в зависимости от рабочей нагрузки.
Вспомогательные теги для компонентов представлений
Рассмотрим компонент представления с необязательным параметром, как показано в следующем коде:
class MyViewComponent
{
IViewComponentResult Invoke(bool showSomething = false) { ... }
}
При использовании ASP.NET Core в .NET 6 вспомогательный компонент тега можно вызвать без необходимости указывать значение для showSomething параметра:
<vc:my />
Шаблон Angular обновлен до версии Angular 12
Шаблон ASP.NET Core в .NET 6 для Angular теперь использует Angular 12.
Шаблон React обновлен до React 17.
Настраиваемое пороговое значение буфера перед записью на диск в форматировщике выходных данных Json.NET
Примечание. Рекомендуется использовать форматировщик выходных данных System.Text.Json, за исключением случаев, когда сериализатор Newtonsoft.Json требуется для обеспечения совместимости. Сериализатор System.Text.Json является полностью async и эффективно работает с большими объемами данных.
Форматировщик выходных данных Newtonsoft.Json по умолчанию помещает в буфер в памяти ответы размером до 32 КБ перед буферизацией на диске. Это позволяет избежать выполнения синхронных операций ввода-вывода, которые могут привести к другим побочным эффектам, таким как нехватка потоков и взаимоблокировка приложений. Однако если размер ответа превышает 32 КБ, для операций дискового ввода-вывода требуется значительное время. Теперь пороговое использование памяти, прежде чем данные помещаются в буфер на диске, можно настроить с помощью свойства MvcNewtonsoftJsonOptions.OutputFormatterMemoryBufferThreshold:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages()
.AddNewtonsoftJson(options =>
{
options.OutputFormatterMemoryBufferThreshold = 48 * 1024;
});
var app = builder.Build();
Дополнительные сведения см. в этом pull-запросе на GitHub и в файле NewtonsoftJsonOutputFormatterTest.cs.
Ускорение получения и установки заголовков HTTP
Добавлены новые API для предоставления всех общих заголовков, доступных на Microsoft.Net.Http.Headers.HeaderNames, в виде свойств в IHeaderDictionary, что упрощает использование API. Например, встроенное ПО промежуточного слоя в следующем коде получает и устанавливает заголовки запросов и ответов с помощью новых API:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Use(async (context, next) =>
{
var hostHeader = context.Request.Headers.Host;
app.Logger.LogInformation("Host header: {host}", hostHeader);
context.Response.Headers.XPoweredBy = "ASP.NET Core 6.0";
await next.Invoke(context);
var dateHeader = context.Response.Headers.Date;
app.Logger.LogInformation("Response date: {date}", dateHeader);
});
app.Run();
Для заголовков, доступ к которым реализован, методы get и set осуществляются путем обращения непосредственно к полю, обходя механизм поиска. Для нереализованных заголовков методы доступа могут пропускать первоначальный поиск по реализованным заголовкам и напрямую выполнять поиск Dictionary<string, StringValues>. Пропуск поиска ускоряет доступ в обоих сценариях.
Асинхронная потоковая передача
ASP.NET Core теперь поддерживает асинхронную потоковую передачу от действий и ответов контроллера из форматировщика JSON. Возврат IAsyncEnumerable из действия больше не приводит к буферизации содержимого ответа в оперативной памяти перед его отправкой. Отсутствие буферизации помогает сократить использование памяти при возврате больших наборов данных, которые можно перечислить асинхронно.
Обратите внимание, что Entity Framework Core предоставляет реализации IAsyncEnumerable для выполнения запросов к базе данных. Улучшенная поддержка IAsyncEnumerable в ASP.NET Core в .NET 6 может сделать использование EF Core с ASP.NET Core более эффективным. Например, следующий код больше не помещает данные о продуктах в память перед отправкой ответа:
public IActionResult GetMovies()
{
return Ok(_context.Movie);
}
Однако при использовании отложенной загрузки EF Coreэто новое поведение может привести к ошибкам из-за параллельного выполнения запроса во время перечисления данных. Приложения могут вернуться к предыдущему поведению путем буферизации данных:
public async Task<IActionResult> GetMovies2()
{
return Ok(await _context.Movie.ToListAsync());
}
Дополнительные сведения об этом изменении в поведении см. в соответствующем объявлении.
Среда ведения журнала HTTP
Ведение журнала HTTP — это новое встроенное ПО промежуточного слоя, в котором регистрируются сведения об HTTP-запросах и HTTP-ответах, включая заголовки и весь текст:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
При переходе к / с помощью кода выше данные записываются в журнал примерно так, как показано ниже:
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Protocol: HTTP/2
Method: GET
Scheme: https
PathBase:
Path: /
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: max-age=0
Connection: close
Cookie: [Redacted]
Host: localhost:44372
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 Edg/95.0.1020.30
sec-ch-ua: [Redacted]
sec-ch-ua-mobile: [Redacted]
sec-ch-ua-platform: [Redacted]
upgrade-insecure-requests: [Redacted]
sec-fetch-site: [Redacted]
sec-fetch-mode: [Redacted]
sec-fetch-user: [Redacted]
sec-fetch-dest: [Redacted]
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
Предыдущие выходные данные активированы с помощью следующего файла appsettings.Development.json.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
}
}
}
Ведение журнала HTTP предоставляет журналы со следующими сведениями:
- информация HTTP-запроса;
- Общие свойства
- Заголовки
- Основной текст
- информация HTTP-ответа.
Чтобы настроить ПО промежуточного слоя для ведения журнала HTTP, укажите HttpLoggingOptions:
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
// Customize HTTP logging.
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("My-Request-Header");
logging.ResponseHeaders.Add("My-Response-Header");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
app.UseHttpLogging();
app.MapGet("/", () => "Hello World!");
app.Run();
Функция IConnectionSocketFeature
Функция запроса IConnectionSocketFeature предоставляет доступ к базовому принимающему сокету, связанному с текущим запросом. Использовать ее можно с помощью FeatureCollection в HttpContext.
Например, следующее приложение задает свойство LingerState для принимающего сокета:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions => listenOptions.Use((connection, next) =>
{
var socketFeature = connection.Features.Get<IConnectionSocketFeature>();
socketFeature.Socket.LingerState = new LingerOption(true, seconds: 10);
return next();
}));
});
var app = builder.Build();
app.MapGet("/", (Func<string>)(() => "Hello world"));
await app.RunAsync();
Ограничения универсального типа в Razor
При определении параметров универсального типа в Razor с помощью директивы @typeparam ограничения универсального типа теперь можно указать с помощью стандартного синтаксиса C#:
Уменьшение размера скриптов SignalR, Blazor Server и MessagePack
Скрипты SignalR, MessagePack и Blazor Server теперь значительно меньше, что обеспечивает меньший объем загрузки, меньшее время синтаксического анализа и компиляции кода JavaScript в браузере и ускоряет запуск. Уменьшение размера:
-
signalr.js: 70% -
blazor.server.js: 45%
Уменьшение размера скриптов стало возможным благодаря Бену Адамсу (Ben Adams). Дополнительные сведения об уменьшении размера см. в запросе на вытягивание Бена на GitHub.
Включение сеансов профилирования Redis
Вклад пользователя Габриэля Лукачи (Gabriel Lucaci) позволяет проводить сессии профилирования Redis с помощью Microsoft.Extensions.Caching.StackExchangeRedis:
using StackExchange.Redis.Profiling;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddStackExchangeRedisCache(options =>
{
options.ProfilingSession = () => new ProfilingSession();
});
Дополнительные сведения см. в статье Профилирование StackExchange.Redis.
Теневое копирование в IIS
В модуль ASP.NET Core (ANCM) для IIS добавлена экспериментальная функция, позволяющая обеспечить поддержку теневого копирования сборок приложений. В настоящее время .NET блокирует двоичные файлы приложения при запуске на Windows, что делает невозможным замену двоичных файлов во время работы приложения. Хотя мы по-прежнему рекомендуем использовать автономный файл приложения, мы понимаем, что существуют определенные сценарии (например, FTP-развертывания), где это невозможно.
В таких случаях включите теневое копирование, настроив параметры обработчика модуля ASP.NET Core. В большинстве случаев у приложений ASP.NET Core нет файла web.config в системе управления версиями, который можно изменить. В ASP.NET Core web.config обычно создается пакетом SDK. Чтобы приступить к работе, можно использовать следующий пример web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section.
For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
<handlers>
<remove name="aspNetCore"/>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
<handlerSettings>
<handlerSetting name="experimentalEnableShadowCopy" value="true" />
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
<!-- Only enable handler logging if you encounter issues-->
<!--<handlerSetting name="debugFile" value=".\logs\aspnetcore-debug.log" />-->
<!--<handlerSetting name="debugLevel" value="FILE,TRACE" />-->
</handlerSettings>
</aspNetCore>
</system.webServer>
</configuration>
Теневое копирование в IIS — это экспериментальная функция. Мы не гарантируем, что она станет частью ASP.NET Core. Оставьте отзыв о теневом копировании IIS в описании этой проблемы на GitHub.
Кардинальные изменения
Используйте статьи в статье Критические изменения в .NET, чтобы найти критические изменения , которые могут применяться при обновлении приложения до более новой версии .NET.
Дополнительные ресурсы
ASP.NET Core