Новые возможности в ASP.NET Core 5.0

В этой статье описываются наиболее важные изменения в ASP.NET Core 5.0 со ссылками на соответствующую документацию.

Улучшения ASP.NET Core MVC и Razor

Привязка модели DateTime в формате UTC

Привязка модели теперь поддерживает привязку строк времени в формате UTC к DateTime. Если запрос содержит строку времени в формате UTC, привязка модели привязывает ее к DateTime в формате UTC. Например, следующая строка времени привязывается к DateTime в формате UTC: https://example.com/mycontroller/myaction?time=2019-06-14T02%3A30%3A04.0576719Z

Привязка модели и проверка с помощью типов записей C# 9

Типы записей C# 9 можно использовать с привязкой модели в контроллере MVC или на странице Razor. Типы записей — это хороший способ моделирования передаваемых по сети данных.

Например, в следующем контроллере PersonController используется тип записи Person с привязкой модели и проверкой формы:

public record Person([Required] string Name, [Range(0, 150)] int Age);

public class PersonController
{
   public IActionResult Index() => View();

   [HttpPost]
   public IActionResult Index(Person person)
   {
          // ...
   }
}

Файл Person/Index.cshtml:

@model Person

Name: <input asp-for="Model.Name" />
<span asp-validation-for="Model.Name" />

Age: <input asp-for="Model.Age" />
<span asp-validation-for="Model.Age" />

Усовершенствования DynamicRouteValueTransformer

В ASP.NET Core 3.1 появился DynamicRouteValueTransformer в качестве способа использования пользовательской конечной точки для динамического выбора действия контроллера MVC или страницы Razor. Приложения ASP.NET Core 5.0 могут передавать состояние в DynamicRouteValueTransformer и фильтровать выбранный набор конечных точек.

Разное

  • Этот атрибут [Compare] можно применить к свойствам в модели страницы Razor.
  • Параметры и свойства, привязанные из текста, считаются обязательными по умолчанию.

Веб-интерфейс API

Спецификация OpenAPI включена по умолчанию

Спецификация OpenAPI является отраслевым стандартом для описания API-интерфейсов HTTP и их интеграции в сложные бизнес-процессы или со сторонними производителями. OpenAPI широко поддерживается всеми поставщиками облачных служб и многими реестрами API. В приложениях, создающих документы OpenAPI из веб-API, представлено множество новых возможностей, в которых можно использовать эти API-интерфейсы. В условиях партнерства с издателями проекта Swashbuckle.AspNetCore с открытым кодом шаблон API для ASP.NET Core содержит зависимость NuGet от Swashbuckle. Swashbuckle — это популярный пакет NuGet с открытым кодом, который динамически создает документы OpenAPI. Он выполняет это путем самоанализа через контроллеры API и создания документа OpenAPI во время выполнения или во время сборки, используя интерфейс командной строки Swashbuckle.

В ASP.NET Core 5.0 шаблоны веб-API по умолчанию поддерживают OpenAPI. Чтобы отключить OpenAPI:

  • Из командной строки.

      dotnet new webapi --no-openapi true
    
  • Из Visual Studio: un проверка Enable OpenAPI support.

Все файлы, созданные .csproj для проектов веб-API, содержат справочник по пакету NuGet Swashbuckle.AspNetCore .

<ItemGroup>
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
</ItemGroup>

Код, созданный шаблоном, содержит код в Startup.ConfigureServices, который активирует создание документа OpenAPI:

public void ConfigureServices(IServiceCollection services)
{

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApp1", Version = "v1" });
    });
}

Метод Startup.Configure добавляет ПО промежуточного слоя Swashbuckle, которое активирует:

  • процесс создания документа;
  • страницу пользовательского интерфейса Swagger по умолчанию в режиме разработки.

Созданный шаблоном код не станет по случайности предоставлять описание API при публикации в рабочей среде.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();  // UseSwaggerUI Protected by if (env.IsDevelopment())
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json",
                         "WebApp1 v1"));
    }

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Импорт Управления API Azure

Если проекты API для ASP.NET Core включают OpenAPI, Visual Studio 2019 версии 16.8 и более поздних публикаций автоматически предлагают дополнительный этап в потоке публикации. Разработчики, использующие Управление API Azure, имеют возможность автоматического импорта API-интерфейсов в Управление API Azure во время потока публикации:

Azure API Management Import VS publishing

Улучшенный интерфейс запуска для проектов веб-API

Если OpenAPI включен по умолчанию, интерфейс запуска приложений (F5) для разработчиков веб-API значительно улучшается. В ASP.NET Core 5.0 шаблон веб-API предварительно настроен для загрузки страницы пользовательского интерфейса Swagger. На странице пользовательского интерфейса Swagger содержится документация, добавленная для опубликованного API, и обеспечивается тестирование API-интерфейсов одним щелчком мыши.

swagger/index.html view

Blazor

Улучшения производительности

В .NET 5 мы внесли значительные улучшения в производительность среды выполнения Blazor WebAssembly, делая основной акцент на сложной отрисовке пользовательского интерфейса и сериализации JSON. По результатам наших тестов производительности в большинстве сценариев скорость Blazor WebAssembly в .NET 5 в два-три раза выше. Дополнительные сведения см. в блоге ASP.NET: ASP.NET обновления Core в .NET 5 версии 1.

Изоляция CSS

Теперь Blazor поддерживает определение стилей CSS, областью действия которых является данный компонент. Благодаря стилям CSS для отдельных компонентов проще ориентироваться в стилях в приложении и избежать непредвиденных побочных эффектов от применения глобальных стилей. Дополнительные сведения см. в статье Изоляция CSS в ASP.NET Core Blazor.

Новый компонент InputFile

Компонент InputFile позволяет считывать один или несколько файлов, выбранных пользователем для отправки. Дополнительные сведения см. в статье Отправка файлов в ASP.NET Core Blazor.

Новые компоненты InputRadio и InputRadioGroup

Blazor содержит встроенные компоненты InputRadio и InputRadioGroup, которые упрощают привязку данных к группам переключателей со встроенной проверкой. Дополнительные сведения см. в разделе ASP.NET Основные Blazor входные компоненты.

Виртуализация компонентов

Повысьте воспринимаемую производительность отрисовки компонентов с помощью встроенной поддержки виртуализации платформы Blazor. Дополнительные сведения см. в статье Виртуализация компонентов Razor ASP.NET Core.

Поддержка события ontoggle

События Blazor теперь поддерживают событие DOM ontoggle. Дополнительные сведения см. в статье Обработка событий Blazor в ASP.NET Core.

Установка фокуса пользовательского интерфейса в приложениях Blazor

Используйте удобный метод FocusAsync со ссылками на элемент, чтобы установить фокус пользовательского интерфейса на этот элемент. Дополнительные сведения см. в статье Обработка событий Blazor в ASP.NET Core.

Настраиваемые атрибуты класса проверки CSS

Настраиваемые атрибуты класса проверки CSS полезны при интеграции с платформами CSS, такими как Bootstrap. Дополнительные сведения см. в разделе ASP.NET Проверка основных Blazor форм.

Поддержка IAsyncDisposable

Теперь компоненты Razor поддерживают интерфейс IAsyncDisposable для асинхронного выпуска выделенных ресурсов.

Ссылки на изоляцию JavaScript и объекты

Blazor реализует изоляцию JavaScript в стандартных модулях JavaScript. Дополнительные сведения см. в статье Вызов функций JavaScript из методов .NET в ASP.NET Core Blazor.

Поддержка компонентами форм отображаемого имени

Следующие встроенные компоненты поддерживают отображаемые имена с помощью параметра DisplayName.

  • InputDate
  • InputNumber
  • InputSelect

Дополнительные сведения см. в разделе ASP.NET Общие сведения о формах CoreBlazor.

Параметры маршрута catch-all

В компонентах поддерживаются параметры маршрута catch-all, которые захватывают пути в нескольких папках. Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor и навигация.

Усовершенствования отладки

В ASP.NET Core 5.0 улучшена отладка приложений Blazor WebAssembly. Кроме того, сейчас отладка поддерживается в Visual Studio для Mac. Дополнительные сведения см. в разделе Отладка приложений ASP.NET CoreBlazor.

Microsoft Identity версии 2.0 и MSAL версии 2.0

Теперь для безопасности Blazor используется Microsoft Identity версии 2.0 (Microsoft.Identity.Web и Microsoft.Identity.Web.UI) и MSAL версии 2.0. Дополнительные сведения см. в статье о безопасности Blazor и узле Identity.

Защищенное хранилище браузера для Blazor Server

Теперь приложения Blazor Server могут использовать встроенную поддержку для хранения сведений о состоянии приложения в браузере, который уже защищен от незаконного изменения благодаря защите данных в ASP.NET Core. Данные могут храниться либо в локальном хранилище браузера, либо в хранилище сеансов. Дополнительные сведения. см. в статье Управление состоянием ASP.NET Core Blazor.

Предварительная отрисовка Blazor WebAssembly

Благодаря улучшенной интеграции компонентов в моделях размещения приложения Blazor WebAssembly теперь могут предварительно отрисовывать выходные данные на сервере.

Улучшенная обрезка и компоновка

Blazor WebAssembly выполняет обрезку и компоновку промежуточного языка (IL) во время сборки, чтобы затем удалить ненужный IL из выходных сборок приложения. В выпуске ASP.NET Core 5.0 Blazor WebAssembly выполняет улучшенную обрезку с помощью дополнительных параметров конфигурации. Дополнительные сведения см. в статьях Настройка средства обрезки для ASP.NET Core Blazor и Параметры обрезки.

Анализатор совместимости с браузерами

Приложения Blazor WebAssembly предназначены для использования в полной контактной зоне API .NET, но из-за ограничений песочницы браузера поддерживаются не все API-интерфейсы .NET. При выполнении в WebAssembly неподдерживаемые API-интерфейсы вызывают PlatformNotSupportedException. Анализатор совместимости платформ предупреждает разработчика, когда приложение использует API-интерфейсы, которые не поддерживаются целевыми платформами приложения. Дополнительные сведения см. в статье Использование компонентов Razor в ASP.NET Core из библиотеки классов Razor (RCL).

Сборки с отложенной загрузкой

Производительность запуска приложения Blazor WebAssembly можно повысить, отложив загрузку некоторых сборок приложений, пока они не потребуются. Дополнительные сведения см. в статье Настройка средства обрезки для ASP.NET Core Blazor WebAssembly.

Обновленная поддержка глобализации

Поддержка глобализации доступна для Blazor WebAssembly на основе ICU (международных компонентов для Юникода). Дополнительные сведения см. в статье Глобализация и локализация в ASP.NET Core Blazor.

gRPC;

В gRPC внесено много усовершенствований производительности. Дополнительные сведения см. в статье Улучшения производительности gRPC в .NET 5.

Дополнительные сведения о gRPC см. в статье Общие сведения о gRPC на .NET.

SignalR

Фильтры концентраторов SignalR

Фильтры концентраторов SignalR, называемые конвейерами концентраторов в ASP.NET SignalR, — это возможность, которая позволяет выполнять код до и после вызова методов концентратора. Выполнение кода до и после вызова методов концентратора аналогично тому, как ПО промежуточного слоя может выполнять код до и после HTTP-запроса. Распространенные варианты использования включают ведение журнала, обработку ошибок и проверку аргументов.

Подробные сведения см. в статье Использование фильтров концентраторов в ASP.NET Core SignalR.

Параллельные вызовы концентраторов SignalR

ASP.NET Core SignalR теперь может обрабатывать параллельные вызовы концентраторов. Поведение по умолчанию можно изменить, чтобы разрешить клиентам одновременно вызывать несколько методов концентратора:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR(options =>
    {
        options.MaximumParallelInvocationsPerClient = 5;
    });
}

Добавлена поддержка MessagePack в клиент Java для SignalR

Новый пакет com.microsoft.signalr.messagepack добавляет поддержку MessagePack в клиент Java для SignalR. Чтобы использовать протокол концентратора MessagePack, добавьте .withHubProtocol(new MessagePackHubProtocol()) в построитель подключений:

HubConnection hubConnection = HubConnectionBuilder.create(
                           "http://localhost:53353/MyHub")
               .withHubProtocol(new MessagePackHubProtocol())
               .build();

Kestrel

  • Перезагружаемые конечные точки с помощью конфигурации. Kestrel может обнаружить изменения в конфигурации, переданные KestrelServerOptions.Configure, отменить привязку к имеющимся конечным точкам и привязать к новым конечным точкам, не требуя перезапуска приложения, если для параметра reloadOnChange задано значение true. По умолчанию при использовании ConfigureWebHostDefaults или CreateDefaultBuilderKestrel привязывается к подразделу конфигурации "Kestrel" с включенным параметром reloadOnChange. Приложения должны передавать reloadOnChange: true при вызове KestrelServerOptions.Configure вручную для получения перезагружаемых конечных точек.

  • Улучшения заголовков ответов HTTP/2. Дополнительные сведения см. в следующем разделе Улучшения в области производительности.

  • Поддержка дополнительных типов конечных точек в транспорте сокетов: добавление в новый API, представленный в System.Net.SocketsKestrel , транспорт сокетов по умолчанию позволяет привязать как к существующим дескрипторам файлов, так и к сокетам домена Unix. Поддержка привязки к имеющимся дескрипторам файлов позволяет использовать имеющуюся интеграцию Systemd, не требуя транспортировки libuv.

  • Декодирование пользовательских заголовков в Kestrel: приложения могут указывать, какие Encoding следует использовать для интерпретации входящих заголовков на основе имени заголовка, а не по умолчанию для UTF-8. Задайте свойство Microsoft.AspNetCore.Server.Kestrel.KestrelServerOptions.RequestHeaderEncodingSelector, чтобы указать используемую кодировку:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
          .ConfigureWebHostDefaults(webBuilder =>
          {
              webBuilder.ConfigureKestrel(options =>
              {
                  options.RequestHeaderEncodingSelector = encoding =>
                  {
                        return encoding switch
                        {
                            "Host" => System.Text.Encoding.Latin1,
                            _ => System.Text.Encoding.UTF8,
                        };
                  };
              });
              webBuilder.UseStartup<Startup>();
          });
    

Параметры для конечной точки Kestrel с помощью конфигурации

Добавлена поддержка настройки параметров для каждой конечной точки Kestrel с помощью конфигурации. Конфигурации для каждой конечной точки включают:

  • используемые протоколы HTTP;
  • используемые протоколы TLS;
  • выбранный сертификат;
  • режим сертификата клиента.

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

В следующем примере показано, как задать для каждой конечной точки использование файла конфигурации:

{
  "Kestrel": {
    "Endpoints": {
      "EndpointName": {
        "Url": "https://*",
        "Sni": {
          "a.example.org": {
            "Protocols": "Http1AndHttp2",
            "SslProtocols": [ "Tls11", "Tls12"],
            "Certificate": {
              "Path": "testCert.pfx",
              "Password": "testPassword"
            },
            "ClientCertificateMode" : "NoCertificate"
          },
          "*.example.org": {
            "Certificate": {
              "Path": "testCert2.pfx",
              "Password": "testPassword"
            }
          },
          "*": {
            // At least one sub-property needs to exist per
            // SNI section or it cannot be discovered via
            // IConfiguration
            "Protocols": "Http1",
          }
        }
      }
    }
  }
}

Указание имени сервера — это расширение TLS для включения виртуального домена в состав согласования SSL. Это фактически означает, что виртуальное доменное имя или имя узла можно использовать для определения конечной точки сети.

Улучшения производительности

HTTP/2

  • Значительное сокращение распределений в пути к коду HTTP/2.

  • Поддержка динамического сжатия HPack заголовков ответов HTTP/2 в Kestrel. Дополнительные сведения см. в разделе Размер таблицы заголовка и записи блога HPACK: возможность Silent Killer в HTTP/2.

  • Отправка кадров PING HTTP/2: HTTP/2 имеет механизм отправки кадров PING, чтобы убедиться, что неактивное подключение по-прежнему работает. Обеспечение работоспособного соединения особенно полезно при работе с долгосрочными потоками, которые часто находятся в неактивном состоянии, но только периодически видят действия, например потоки gRPC. Приложения могут отправить периодические кадры проверки связи в Kestrel, установив ограничения на KestrelServerOptions:

    public static IHostBuilder CreateHostBuilder(string[] args) =>
      Host.CreateDefaultBuilder(args)
          .ConfigureWebHostDefaults(webBuilder =>
          {
              webBuilder.ConfigureKestrel(options =>
              {
                  options.Limits.Http2.KeepAlivePingInterval =
                                                 TimeSpan.FromSeconds(10);
                  options.Limits.Http2.KeepAlivePingTimeout =
                                                 TimeSpan.FromSeconds(1);
              });
              webBuilder.UseStartup<Startup>();
          });
    

Контейнеры

До выпуска .NET 5.0 создание и публикация документа Dockerfile для приложения ASP.NET Core, необходимого для получения всего пакета SDK для .NET Core и образа ASP.NET Core. В этом выпуске количество извлекаемых байтов образов пакета SDK сокращено, а байты, полученные для образа ASP.NET Core, как правило, устраняются. Дополнительные сведения об этом см. в комментарии к проблеме на GitHub.

Проверка подлинности и авторизация

Проверка подлинности идентификатора Microsoft Entra с помощью Microsoft.Identity. Веб

Теперь шаблоны проектов ASP.NET Core интегрируются с Microsoft.Identity.Web обработкой проверки подлинности с помощью идентификатора Microsoft Entra. Пакет Microsoft.Identity.Web предоставляет:

  • Лучший способ проверки подлинности с помощью идентификатора Microsoft Entra.
  • Более простой способ доступа к ресурсам Azure от имени пользователей, включая Microsoft Graph. См. пример Microsoft.Identity.Web, который начинается с базового входа и продолжается через мультитенантность с использованием API-интерфейсов Azure, Microsoft Graph и защиту собственных API-интерфейсов. Пакет Microsoft.Identity.Web доступен вместе с .NET 5.

Разрешение анонимного доступа к конечной точке

Метод расширения AllowAnonymous предоставляет анонимный доступ к конечной точке:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        })
        .AllowAnonymous();
    });
}

Пользовательская обработка сбоев авторизации

Пользовательская обработка сбоев авторизации стала еще проще благодаря новому интерфейсу IAuthorizationMiddlewareResultHandler, который вызывается ПО промежуточного слояавторизации. Реализация по умолчанию остается неизменной, но пользовательский обработчик можно зарегистрировать во внедрении зависимостей, что позволяет использовать пользовательские HTTP-ответы в зависимости от причины сбоя авторизации. См. этот пример, в котором демонстрируется использование IAuthorizationMiddlewareResultHandler.

Авторизация при использовании маршрутизации конечных точек

Авторизация при использовании маршрутизации конечных точек теперь получает HttpContext, а не экземпляр конечной точки. Это позволяет ПО промежуточного слоя авторизации получить доступ к RouteData и другим свойствам HttpContext, которые были недоступны через класс Endpoint. Конечную точку можно получить из контекста, используя context.GetEndpoint.

Управление доступом на основе ролей с помощью проверки подлинности Kerberos и протокола LDAP в Linux

См. раздел Проверка подлинности Kerberos и управление доступом на основе ролей (RBAC).

Усовершенствования API

Методы расширения JSON для HttpRequest и HttpResponse

Данные JSON можно считывать и записывать из HttpRequest и HttpResponse с помощью новых методов расширения ReadFromJsonAsync и WriteAsJsonAsync. Эти методы расширения используют сериализатор System.Text.Json для обработки данных JSON. Новый метод расширения HasJsonContentType также может проверять, имеет ли запрос тип содержимого JSON.

Методы расширения JSON можно объединять с маршрутизацией конечных точек для создания API-интерфейсов JSON в стиле программирования, который мы называем маршрут к коду. Это новый вариант для разработчиков, которые хотят создавать базовые API-интерфейсы JSON простым способом. Например, веб-приложение, имеющее только несколько конечных точек, может использовать маршрут к коду, а не все функции MVC ASP.NET Core:

endpoints.MapGet("/weather/{city:alpha}", async context =>
{
    var city = (string)context.Request.RouteValues["city"];
    var weather = GetFromDatabase(city);

    await context.Response.WriteAsJsonAsync(weather);
});

System.Diagnostics.Activity

System.Diagnostics.Activity теперь по умолчанию имеет формат W3C. Благодаря этому распределенная трассировка в ASP.NET Core поддерживает взаимодействие с другими платформами по умолчанию.

FromBodyAttribute

FromBodyAttribute теперь поддерживает настройку параметра, который позволяет считать такие параметры или свойства необязательными:

public IActionResult Post([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]
                          MyModel model)
{
    ...
}

Прочие улучшения

Мы начали применять заметки, допускающие значение NULL, к сборкам ASP.NET Core. Мы планируем добавить заметки к большей части контактной зоны общедоступного API на платформе .NET 5.

Управление активацией класса Startup

Добавлена дополнительная перегрузка UseStartup, которая разрешает приложению предоставлять фабричный метод для управления активацией класса Startup. Управление активацией класса Startup полезно для передачи дополнительных параметров в Startup, которые инициализируются вместе с узлом:

public class Program
{
    public static async Task Main(string[] args)
    {
        var logger = CreateLogger();
        var host = Host.CreateDefaultBuilder()
            .ConfigureWebHost(builder =>
            {
                builder.UseStartup(context => new Startup(logger));
            })
            .Build();

        await host.RunAsync();
    }
}

Автоматическое обновление с помощью dotnet watch

В .NET 5 при запуске dotnet watch в проекте ASP.NET Core запускается браузер по умолчанию и выполняется автоматическое обновление браузера по мере внесения изменений в код. Это означает, что вы можете:

  • Открыть проект ASP.NET Core в текстовом редакторе.
  • Запустите dotnet watch.
  • Сосредоточиться на изменениях кода, пока инструментарий обрабатывает перестроение, перезапуск и перезагрузку приложения.

Форматировщик средства ведения журнала консоли

В библиотеке Microsoft.Extensions.Logging для поставщика журнала консоли внесено несколько усовершенствований. Теперь разработчики могут реализовать пользовательский ConsoleFormatter, чтобы полностью контролировать форматирование и цветовое выделение выходных данных консоли. API-интерфейсы форматировщика позволяют выполнять обширное форматирование путем реализации подмножества escape-последовательностей VT-100. VT-100 поддерживается в большинстве современных терминалов. Средство ведения журнала консоли может анализировать escape-последовательности неподдерживаемых терминалов, позволяя разработчикам создавать единый форматировщик для всех терминалов.

Средство ведения журнала консолиJSON

Помимо поддержки пользовательских форматировщиков, мы также добавили встроенный форматировщик JSON, который выводит структурированные журналы JSON на консоль. В следующем примере кода показано, как переключиться со средства ведения журнала по умолчанию на JSON:

public static IHostBuilder CreateHostBuilder(string[] args) =>
           Host.CreateDefaultBuilder(args)
  .ConfigureLogging(logging =>
  {
     logging.AddJsonConsole(options =>
     {
         options.JsonWriterOptions = new JsonWriterOptions()
         { Indented = true };
     });
  })
  .ConfigureWebHostDefaults(webBuilder =>
  {
    webBuilder.UseStartup<Startup>();
  });

Сообщения журнала, выводимые на консоль, имеют формат JSON:

{
  "EventId": 0,
  "LogLevel": "Information",
  "Category": "Microsoft.Hosting.Lifetime",
  "Message": "Now listening on: https://localhost:5001",
  "State": {
    "Message": "Now listening on: https://localhost:5001",
    "address": "https://localhost:5001",
    "{OriginalFormat}": "Now listening on: {address}"
  }
}