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

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

ПО промежуточного слоя для ограничения скорости в ASP.NET Core

ПО промежуточного слоя Microsoft.AspNetCore.RateLimiting предоставляет ПО промежуточного слоя для ограничения скорости. Приложения настраивают политики ограничения скорости, а затем присоединяют политики к конечным точкам. Дополнительные сведения см. в статье ПО промежуточного слоя для ограничения скорости в ASP.NET Core.

Проверка подлинности использует одну схему в качестве DefaultScheme

В рамках работы по упрощению проверки подлинности при регистрации только одной схемы проверки подлинности она автоматически используется в качестве DefaultScheme и не нужно указывать. Дополнительные сведения см. в разделе DefaultScheme.

MVC и Razor Pages

Поддержка моделей, допускающих значение NULL, в представлениях MVC и Razor Pages

Модели страниц или представлений, допускающих значение NULL, поддерживаются для улучшения работы при проверке состояния NULL в приложениях ASP.NET Core:

@model Product?

Привязка с помощью IParsable<T>.TryParse в контроллерах API и MVC

API IParsable<TSelf>.TryParse поддерживает привязку значений параметров действий контроллера. Дополнительные сведения см. в разделе Привязка с помощью IParsable<T>.TryParse.

В версиях ASP.NET Core, предшествующих 7, при проверке согласия cookie используется значение yescookie, чтобы указать согласие. Теперь можно указать значение, представляющее согласие. Например, можно использовать true вместо yes:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
    options.ConsentCookieValue = "true";
});

var app = builder.Build();

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

Контроллеры API

Привязка параметров с помощью внедрения зависимостей в контроллерах API

Привязка параметров для действий контроллера API позволяет привязать параметры с помощью внедрения зависимостей при настройке типа в качестве службы. Это означает, что больше не требуется явно применять атрибут [FromServices] к параметру. В следующем коде оба действия возвращают время:

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    public ActionResult GetWithAttribute([FromServices] IDateTime dateTime) 
                                                        => Ok(dateTime.Now);

    [Route("noAttribute")]
    public ActionResult Get(IDateTime dateTime) => Ok(dateTime.Now);
}

В редких случаях автоматическое внедрение зависимостей может прервать работу приложения, если оно имеет тип, который также принимается в методах действий контроллеров API. Обычно тип во внедрении зависимостей и тип, используемый в качестве аргумента в действии контроллера API, не совпадают. Чтобы отключить автоматическую привязку параметров, задайте DisableImplicitFromServicesParameters:

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddSingleton<IDateTime, SystemDateTime>();

builder.Services.Configure<ApiBehaviorOptions>(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

var app = builder.Build();

app.MapControllers();

app.Run();

В ASP.NET Core 7.0 типы во внедрении зависимостей проверяются при запуске приложения с помощью IServiceProviderIsService, чтобы определить, поступает ли аргумент в действии контроллера API из внедрения зависимостей или из других источников.

Новый механизм вывода источника привязки параметров действия контроллера API использует следующие правила:

  1. Указанный ранее BindingInfo.BindingSource не перезаписывается.
  2. Назначается параметр сложного типа, зарегистрированный в контейнере внедрения зависимостей: BindingSource.Services.
  3. Назначается параметр сложного типа, не зарегистрированный в контейнере внедрения зависимостей: BindingSource.Body.
  4. Параметру с именем, которое появляется как значение маршрута в любом шаблоне маршрута, присваивается BindingSource.Path.
  5. В качестве остальных параметров используется BindingSource.Query.

Имена свойств JSON в ошибках проверки

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

using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider());
});

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

В следующем коде для проверки настраивается использование NewtonsoftJsonValidationMetadataProvider для использования имени свойства JSON при применении Json.NET:

using Microsoft.AspNetCore.Mvc.NewtonsoftJson;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new NewtonsoftJsonValidationMetadataProvider());
}).AddNewtonsoftJson();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Дополнительные сведения см. в разделе Использование имен свойств JSON в ошибках проверки.

Минимальные API

Фильтры в приложениях с минимальным API

Фильтры минимальных API позволяют разработчикам реализовать бизнес-логику, которая поддерживает следующее:

  • Выполнение кода до и после запуска обработчика маршрутов.
  • Проверка и изменение параметров, предоставленных при вызове обработчика маршрутов.
  • Перехват ответа обработчика маршрутов.

Фильтры могут быть полезны в следующих сценариях:

  • Проверка параметров и текста запросов, отправляемых в конечную точку.
  • Запись сведений о запросе и ответе в журнал.
  • Проверка того, что запрос предназначен для поддерживаемой версии API.

Дополнительные сведения см. в статьях "Фильтры" в приложениях API "Минимальный"

Привязка массивов и строковых значений из заголовков и строк запроса

В ASP.NET 7 поддерживается привязка строк запроса к массиву примитивных типов, массивам строк и StringValues.

// Bind query string values to a primitive type array.
// GET  /tags?q=1&q=2&q=3
app.MapGet("/tags", (int[] q) =>
                      $"tag1: {q[0]} , tag2: {q[1]}, tag3: {q[2]}");

// Bind to a string array.
// GET /tags2?names=john&names=jack&names=jane
app.MapGet("/tags2", (string[] names) =>
            $"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}");

// Bind to StringValues.
// GET /tags3?names=john&names=jack&names=jane
app.MapGet("/tags3", (StringValues names) =>
            $"tag1: {names[0]} , tag2: {names[1]}, tag3: {names[2]}");

Привязка строк запроса или значений заголовков к массиву сложных типов поддерживается, если для типа реализовать TryParse. Дополнительные сведения см. в разделе Привязка массивов и строковых значений из заголовков и строк запроса.

Дополнительные сведения см. в статье о добавлении сводок или описаний конечных точек.

Привязка текста запроса в виде Stream или PipeReader

Тело запроса может привязываться как Stream или PipeReader для эффективной поддержки сценариев, в которых пользователю необходимо обрабатывать данные и:

  • Хранить данные в хранилище BLOB-объектов или поставить их в очередь у поставщика очередей.
  • Обрабатывать хранимые данные с помощью рабочего процесса или облачной функции.

Например, данные могут быть помещены в очередь в Хранилище очередей Azure или храниться в Хранилище BLOB-объектов Azure.

Дополнительные сведения см. в статье Привязка текста запроса в качестве Stream или PipeReader.

Новые перегрузки Results.Stream

Мы ввели новые перегрузки Results.Stream для сценариев, которым необходим доступ к базовому потоку HTTP-ответов без буферизации. Эти перегрузки также улучшают случаи, когда API передает данные в поток ответа HTTP, например из Хранилища BLOB-объектов Azure. В следующем примере используется ImageSharp для возврата уменьшенного размера указанного изображения:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Processing;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/process-image/{strImage}", (string strImage, HttpContext http, CancellationToken token) =>
{
    http.Response.Headers.CacheControl = $"public,max-age={TimeSpan.FromHours(24).TotalSeconds}";
    return Results.Stream(stream => ResizeImageAsync(strImage, stream, token), "image/jpeg");
});

async Task ResizeImageAsync(string strImage, Stream stream, CancellationToken token)
{
    var strPath = $"wwwroot/img/{strImage}";
    using var image = await Image.LoadAsync(strPath, token);
    int width = image.Width / 2;
    int height = image.Height / 2;
    image.Mutate(x =>x.Resize(width, height));
    await image.SaveAsync(stream, JpegFormat.Instance, cancellationToken: token);
}

Дополнительные сведения см. в разделе Примеры потоковой передачи.

Типизированные результаты для минимальных API

В .NET 6 появился интерфейс IResult, который представляет значения, возвращаемые минимальными API, не использующими неявную поддержку JSON для сериализации возвращенного объекта для ответов HTTP. Статический класс Results используется для создания разных объектов IResult, которые представляют разные типы ответов. Например, установка кода статуса ответа или перенаправление на другой URL-адрес. Однако типы, реализующие IResult, возвращаемые этими методами, были внутренними, что затрудняло проверку конкретного типа IResult, возвращаемого методами в модульном тесте.

В .NET 7 типы, реализующие IResult, являются общедоступными, что позволяет использовать утверждения типов при тестировании. Например:

[TestClass()]
public class WeatherApiTests
{
    [TestMethod()]
    public void MapWeatherApiTest()
    {
        var result = WeatherApi.GetAllWeathers();
        Assert.IsInstanceOfType(result, typeof(Ok<WeatherForecast[]>));
    }      
}

Улучшенная модульная проверка для минимальных обработчиков маршрутов

IResult Типы реализации теперь общедоступны в Microsoft.AspNetCore.Http.HttpResults пространстве имен. IResult Типы реализации можно использовать для модульного тестирования минимальных обработчиков маршрутов при использовании именованных методов вместо лямбда-кодов.

Следующий код использует Ok<TValue> класс:

[Fact]
public async Task GetTodoReturnsTodoFromDatabase()
{
    // Arrange
    await using var context = new MockDb().CreateDbContext();

    context.Todos.Add(new Todo
    {
        Id = 1,
        Title = "Test title",
        Description = "Test description",
        IsDone = false
    });

    await context.SaveChangesAsync();

    // Act
    var result = await TodoEndpointsV1.GetTodo(1, context);

    //Assert
    Assert.IsType<Results<Ok<Todo>, NotFound>>(result);

    var okResult = (Ok<Todo>)result.Result;

    Assert.NotNull(okResult.Value);
    Assert.Equal(1, okResult.Value.Id);
}

Дополнительные сведения см. в разделе IResult "Типы реализации".

Новые интерфейсы HttpResult

Следующие интерфейсы в Microsoft.AspNetCore.Http пространстве имен предоставляют способ обнаружения IResult типа во время выполнения, который является общим шаблоном в реализации фильтров:

Дополнительные сведения см. в интерфейсах IHttpResult.

Улучшения OpenAPI для минимальных API

пакет NuGet Microsoft.AspNetCore.OpenApi;

Пакет Microsoft.AspNetCore.OpenApi позволяет взаимодействовать со спецификациями OpenAPI для конечных точек. Этот пакет создает связь между моделями OpenAPI, определенными в пакете Microsoft.AspNetCore.OpenApi, и конечными точками, определенными в минимальных API. Этот пакет предоставляет API, который проверяет параметры, ответы и метаданные конечной точки и создает тип заметки OpenAPI, подходящий для описания этой конечной точки.

app.MapPost("/todoitems/{id}", async (int id, Todo todo, TodoDb db) =>
{
    todo.Id = id;
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi();

Вызов WithOpenApi с параметрами

Метод WithOpenApi принимает функцию, которую можно использовать для изменения заметки OpenAPI. Например, следующий код добавляет описание в первый параметр конечной точки:

app.MapPost("/todo2/{id}", async (int id, Todo todo, TodoDb db) =>
{
    todo.Id = id;
    db.Todos.Add(todo);
    await db.SaveChangesAsync();

    return Results.Created($"/todoitems/{todo.Id}", todo);
})
.WithOpenApi(generatedOperation =>
{
    var parameter = generatedOperation.Parameters[0];
    parameter.Description = "The ID associated with the created Todo";
    return generatedOperation;
});

Предоставление описаний и сводок конечных точек

Минимальные API-интерфейсы теперь поддерживают операции аннотирования с описаниями и сводками для создания спецификаций OpenAPI. Можно вызывать методы расширения WithDescription и WithSummary или использовать атрибуты [EndpointDescription] и [EndpointSummary]).

Дополнительные сведения см. в разделе OpenAPI в минимальных приложениях API

Отправка файлов с помощью IFormFile и IFormFileCollection

Минимальные API теперь поддерживают отправку файлов с применением IFormFile и IFormFileCollection. Следующий код использует IFormFile и IFormFileCollection, чтобы отправить файл:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.MapPost("/upload", async (IFormFile file) =>
{
    var tempFile = Path.GetTempFileName();
    app.Logger.LogInformation(tempFile);
    using var stream = File.OpenWrite(tempFile);
    await file.CopyToAsync(stream);
});

app.MapPost("/upload_many", async (IFormFileCollection myFiles) =>
{
    foreach (var file in myFiles)
    {
        var tempFile = Path.GetTempFileName();
        app.Logger.LogInformation(tempFile);
        using var stream = File.OpenWrite(tempFile);
        await file.CopyToAsync(stream);
    }
});

app.Run();

Поддерживаются запросы на отправку файлов с проверкой подлинности посредством заголовка авторизации, сертификата клиента или заголовка cookie.

Встроенная поддержка защиты от подделки отсутствует. Однако ее можно реализовать с помощью службы IAntiforgery.

Атрибут [AsParameters] обеспечивает привязку параметров для списков аргументов.

Атрибут [AsParameters] обеспечивает привязку параметров для списков аргументов. Дополнительные сведения: Привязка параметров для списков аргументов с помощью [AsParameters].

Минимальные API и контроллеры API

Новая служба сведений о проблеме

Служба сведений о проблеме IProblemDetailsService реализует интерфейс, который поддерживает создание сведений о проблеме для API HTTP.

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

Группы маршрутов

Метод MapGroup расширения помогает упорядочивать группы конечных точек с общим префиксом. Это уменьшает повторяющийся код и позволяет настраивать целые группы конечных точек с одним вызовом методов, таких как RequireAuthorization и WithMetadata которые добавляют метаданные конечной точки.

Например, следующий код создает две аналогичные группы конечных точек:

app.MapGroup("/public/todos")
    .MapTodosApi()
    .WithTags("Public");

app.MapGroup("/private/todos")
    .MapTodosApi()
    .WithTags("Private")
    .AddEndpointFilterFactory(QueryPrivateTodos)
    .RequireAuthorization();


EndpointFilterDelegate QueryPrivateTodos(EndpointFilterFactoryContext factoryContext, EndpointFilterDelegate next)
{
    var dbContextIndex = -1;

    foreach (var argument in factoryContext.MethodInfo.GetParameters())
    {
        if (argument.ParameterType == typeof(TodoDb))
        {
            dbContextIndex = argument.Position;
            break;
        }
    }

    // Skip filter if the method doesn't have a TodoDb parameter.
    if (dbContextIndex < 0)
    {
        return next;
    }

    return async invocationContext =>
    {
        var dbContext = invocationContext.GetArgument<TodoDb>(dbContextIndex);
        dbContext.IsPrivate = true;

        try
        {
            return await next(invocationContext);
        }
        finally
        {
            // This should only be relevant if you're pooling or otherwise reusing the DbContext instance.
            dbContext.IsPrivate = false;
        }
    };
}
public static RouteGroupBuilder MapTodosApi(this RouteGroupBuilder group)
{
    group.MapGet("/", GetAllTodos);
    group.MapGet("/{id}", GetTodo);
    group.MapPost("/", CreateTodo);
    group.MapPut("/{id}", UpdateTodo);
    group.MapDelete("/{id}", DeleteTodo);

    return group;
}

В этом сценарии можно использовать относительный адрес заголовка Location201 Created в результате:

public static async Task<Created<Todo>> CreateTodo(Todo todo, TodoDb database)
{
    await database.AddAsync(todo);
    await database.SaveChangesAsync();

    return TypedResults.Created($"{todo.Id}", todo);
}

Первая группа конечных точек будет соответствовать только запросам, префиксным и /public/todos доступным без какой-либо проверки подлинности. Вторая группа конечных точек будет соответствовать только запросам, префиксным и /private/todos требующим проверки подлинности.

Фабрика QueryPrivateTodos фильтров конечных точек — это локальная функция, которая изменяет параметры обработчика TodoDb маршрутов, чтобы разрешить доступ к частным данным и хранить данные о частных объектах.

Группы маршрутов также поддерживают вложенные группы и сложные шаблоны префикса с параметрами маршрута и ограничениями. В следующем примере обработчик маршрутов, сопоставленный с user группой, может записывать {org} параметры маршрута, {group} определенные в префиксах внешней группы.

Префикс также может быть пустым. Это может быть полезно для добавления метаданных конечной точки или фильтров в группу конечных точек без изменения шаблона маршрута.

var all = app.MapGroup("").WithOpenApi();
var org = all.MapGroup("{org}");
var user = org.MapGroup("{user}");
user.MapGet("", (string org, string user) => $"{org}/{user}");

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

var outer = app.MapGroup("/outer");
var inner = outer.MapGroup("/inner");

inner.AddEndpointFilter((context, next) =>
{
    app.Logger.LogInformation("/inner group filter");
    return next(context);
});

outer.AddEndpointFilter((context, next) =>
{
    app.Logger.LogInformation("/outer group filter");
    return next(context);
});

inner.MapGet("/", () => "Hi!").AddEndpointFilter((context, next) =>
{
    app.Logger.LogInformation("MapGet filter");
    return next(context);
});

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

Запрос, который /outer/inner/ будет регистрировать следующее:

/outer group filter
/inner group filter
MapGet filter

gRPC;

Перекодирование JSON

Перекодирование gRPC JSON — это расширение для ASP.NET Core, которое создает REST API JSON для служб gRPC. Перекодирование gRPC JSON позволяет:

  • Приложениям вызывать службы gRPC, используя следующие привычные понятия HTTP.
  • Приложениям gRPC ASP.NET Core поддерживать gRPC и API-интерфейсы RESTful JSON без репликации функций.
  • Экспериментальная поддержка создания OpenAPI из транскодированных RESTAPI-интерфейсов с ful путем интеграции с Swashbuckle.

Дополнительные сведения см. в статье о транскодирование gRPC JSON в приложениях ASP.NET Core gRPC и использовании OpenAPI с транскодированием ASP.NET приложениями Core gRPC JSON.

Проверки работоспособности gRPC в ASP.NET Core

Протокол проверки работоспособности gRPC является стандартом для передачи сведений о работоспособности серверных приложений gRPC. Приложение предоставляет проверка работоспособности как службу gRPC. Они обычно используются с внешней службой мониторинга для проверки состояния приложения.

gRPC ASP.NET Core добавил встроенную поддержку проверка работоспособности gRPC с пакетомGrpc.AspNetCore.HealthChecks. Результаты проверок работоспособности .NET передаются вызывающим объектам.

Дополнительные сведения см. в разделе проверка работоспособности gRPC в ASP.NET Core.

Улучшена поддержка учетных данных для звонков

Учетные данные вызова — это рекомендуемый способ настроить клиент gRPC для отправки маркера проверки подлинности на сервер. Клиенты gRPC поддерживают две новые функции, которые упрощают использование учетных данных вызова:

  • Поддержка учетных данных вызова с помощью соединений с открытым текстом. Ранее вызов gRPC отправлял только учетные данные вызова, если подключение было защищенно с помощью TLS. Новый параметр GrpcChannelOptions, вызываемый UnsafeUseInsecureChannelCallCredentials, позволяет настроить это поведение. Существуют последствия для защиты подключения с помощью TLS.
  • Вызывается новый метод AddCallCredentials с помощью клиентской фабрики gRPC. AddCallCredentials — это быстрый способ настройки учетных данных вызова для клиента gRPC и хорошо интегрируется с внедрением зависимостей (DI).

Следующий код настраивает клиентную фабрику gRPC для отправки Authorization метаданных:

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
       o.Address = new Uri("https://localhost:5001");
    })
    .AddCallCredentials((context, metadata) =>
    {
       if (!string.IsNullOrEmpty(_token))
       {
          metadata.Add("Authorization", $"Bearer {_token}");
       }
       return Task.CompletedTask;
    });

Дополнительные сведения см. в разделе "Настройка маркера носителя с помощью клиентской фабрики gRPC".

SignalR

Получение результатов от клиента

Теперь сервер поддерживает запрос результатов от клиента. Для этого требуется, чтобы сервер использовал ISingleClientProxy.InvokeAsync, а клиент возвращал результат от своего обработчика .On. Строго типизированные концентраторы также могут возвращать значения из методов интерфейса.

Дополнительные сведения см. в разделе Получение результатов от клиента.

Внедрение зависимостей для методов концентратора SignalR

Методы концентратора SignalR теперь поддерживают внедрение служб посредством внедрения зависимостей.

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

Blazor

Обработка событий изменения расположения и состояния навигации

В .NET 7 Blazor поддерживает изменение расположения событий и поддержание состояния навигации. Это позволяет предупреждать пользователей о несохраненных работах или выполнять связанные действия при выполнении пользователем навигации по страницам.

Дополнительные сведения см. в следующих разделах статьи "Маршрутизация и навигация ".

Пустые Blazor шаблоны проектов

Blazor имеет два новых шаблона проекта для запуска с пустого листа. Новые Blazor Server шаблоны проектов App Empty иBlazor WebAssemblyApp Empty похожи на их непустые аналоги, но без примера кода. Эти пустые шаблоны включают только базовую домашнюю страницу, и мы удалили начальную загрузку, чтобы начать с другой платформы CSS.

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

Пользовательские элементы Blazor

Пакет Microsoft.AspNetCore.Components.CustomElements позволяет создавать пользовательские элементыBlazorDOM на основе стандартов.

Дополнительные сведения см. в статье Компоненты Razor ASP.NET Core.

Модификаторы привязки (@bind:after, @bind:get, @bind:set)

Внимание

В @bind:after//@bind:get@bind:set настоящее время функции получают дополнительные обновления. Чтобы воспользоваться преимуществами последних обновлений, убедитесь, что вы установили последний пакет SDK.

Использование параметра обратного вызова события ([Parameter] public EventCallback<string> ValueChanged { get; set; }) не поддерживается. Вместо этого передайте Actionметод @bind:set/@bind:after-returning или Task-returning.

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

В .NET 7 можно запустить асинхронную логику после завершения события привязки с помощью нового @bind:after модификатора. В следующем примере PerformSearch асинхронный метод выполняется автоматически после обнаружения любых изменений в тексте поиска:

<input @bind="searchText" @bind:after="PerformSearch" />

@code {
    private string searchText;

    private async Task PerformSearch()
    {
        ...
    }
}

В .NET 7 также проще настроить привязку для параметров компонента. Компоненты могут поддерживать двусторонняя привязка данных, определяя пару параметров:

  • @bind:get: указывает значение для привязки.
  • @bind:set: указывает обратный вызов при изменении значения.

@bind:get Модификаторы и @bind:set модификаторы всегда используются вместе.

Примеры:

@* Elements *@

<input type="text" @bind="text" @bind:after="() => { }" />

<input type="text" @bind:get="text" @bind:set="(value) => { }" />

<input type="text" @bind="text" @bind:after="AfterAsync" />

<input type="text" @bind:get="text" @bind:set="SetAsync" />

<input type="text" @bind="text" @bind:after="() => { }" />

<input type="text" @bind:get="text" @bind:set="(value) => { }" />

<input type="text" @bind="text" @bind:after="AfterAsync" />

<input type="text" @bind:get="text" @bind:set="SetAsync" />

@* Components *@

<InputText @bind-Value="text" @bind-Value:after="() => { }" />

<InputText @bind-Value:get="text" @bind-Value:set="(value) => { }" />

<InputText @bind-Value="text" @bind-Value:after="AfterAsync" />

<InputText @bind-Value:get="text" @bind-Value:set="SetAsync" />

<InputText @bind-Value="text" @bind-Value:after="() => { }" />

<InputText @bind-Value:get="text" @bind-Value:set="(value) => { }" />

<InputText @bind-Value="text" @bind-Value:after="AfterAsync" />

<InputText @bind-Value:get="text" @bind-Value:set="SetAsync" />

@code {
    private string text = "";

    private void After(){}
    private void Set() {}
    private Task AfterAsync() { return Task.CompletedTask; }
    private Task SetAsync(string value) { return Task.CompletedTask; }
}

Дополнительные сведения о компоненте InputText см. в разделе ASP.NET Основные Blazor входные компоненты.

улучшения Горячая перезагрузка

В .NET 7 поддержка Горячая перезагрузка включает следующее:

  • Компоненты сбрасывают параметры в значения по умолчанию при удалении значения.
  • Blazor WebAssembly:
    • Добавьте новые типы.
    • Добавьте вложенные классы.
    • Добавьте статические и экземплярные методы в существующие типы.
    • Добавьте статические поля и методы в существующие типы.
    • Добавьте статические лямбда-выражения в существующие методы.
    • Добавьте лямбда-выражения, которые записываются this в существующие методы, которые уже записаны this ранее.

Динамические запросы проверки подлинности с помощью MSAL в Blazor WebAssembly

Новые возможности .NET 7 Blazor WebAssembly поддерживают создание динамических запросов проверки подлинности во время выполнения с настраиваемыми параметрами для обработки расширенных сценариев проверки подлинности.

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

Blazor WebAssembly улучшения отладки

Blazor WebAssembly Отладка имеет следующие улучшения:

  • Поддержка параметра Just My Code для отображения или скрытия элементов типа, не входящих в пользовательский код.
  • Поддержка проверки многомерных массивов.
  • Теперь стек вызовов отображает правильное имя асинхронных методов.
  • Улучшенная оценка выражений.
  • Правильная new обработка ключевое слово производных элементов.
  • Поддержка атрибутов, связанных с отладчиком, в System.Diagnostics.

System.Security.Cryptography поддержка в WebAssembly

.NET 6 поддерживает семейство хэширования алгоритмов SHA при выполнении в WebAssembly. .NET 7 позволяет использовать более криптографические алгоритмы, используя преимущества SubtleCrypto, когда это возможно, и вернуться к реализации .NET, когда SubtleCrypto не удается использовать. Следующие алгоритмы поддерживаются в WebAssembly в .NET 7:

  • SHA1
  • SHA256
  • SHA384
  • SHA512
  • HMACSHA1
  • HMACSHA256
  • HMACSHA384
  • HMACSHA512
  • AES-CBC
  • PBKDF2
  • HKDF

Дополнительные сведения см. в статье Разработчики, предназначенные для браузера, могут использовать API веб-шифрования (dotnet/runtime #40074).

Внедрение служб в настраиваемые атрибуты проверки

Теперь можно внедрить службы в настраиваемые атрибуты проверки. Blazor настраивает его ValidationContext таким образом, чтобы его можно было использовать в качестве поставщика услуг.

Дополнительные сведения см. в разделе ASP.NET Проверка основных Blazor форм.

Input* компоненты за пределами EditContext/EditForm

Встроенные входные компоненты теперь поддерживаются за пределами формы в Razor разметке компонента.

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

Изменения шаблона проекта

Когда .NET 6 был выпущен в прошлом году, разметка _Host HTML страницы (Pages/_Host.chstml) была разделена между _Host страницей и новой _Layout страницей (Pages/_Layout.chstml) в шаблоне проекта .NET 6 Blazor Server .

В .NET 7 разметка HTML была перекомбинирована со страницей _Host в шаблонах проектов.

В шаблоны проектов были внесены Blazor несколько дополнительных изменений. Невозможно перечислить каждое изменение шаблонов в документации. Сведения о переносе приложения в .NET 7 для принятия всех изменений см. в статье "Миграция с ASP.NET Core 6.0 на 7.0".

Экспериментальный QuickGrid компонент

Новый QuickGrid компонент предоставляет удобный компонент сетки данных для наиболее распространенных требований, а также в качестве эталонной архитектуры и базовых показателей производительности для всех, кто создает Blazor компоненты сетки данных.

Дополнительные сведения см. в разделе ASP.NET Компонент QuickGrid CoreBlazor.

Демонстрация в реальном времени: QuickGrid для Blazor примера приложения

Усовершенствования виртуализации

Усовершенствования виртуализации в .NET 7:

  • Компонент Virtualize поддерживает использование самого документа в качестве корня прокрутки в качестве альтернативы применению другого элемента overflow-y: scroll .
  • Если компонент Virtualize помещается в элемент, которому требуется определенное имя дочернего тега, SpacerElement разрешает получить или задать имя тега разделителя в виртуализации.

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

MouseEventArgs Обновления

MovementX и MovementY были добавлены MouseEventArgsв .

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

Новая Blazor страница загрузки

Шаблон Blazor WebAssembly проекта имеет новый пользовательский интерфейс загрузки, показывающий ход загрузки приложения.

Дополнительные сведения см. в статье Запуск ASP.NET Core Blazor.

Улучшена диагностика для проверки подлинности вBlazor WebAssembly

Чтобы диагностировать проблемы с проверкой подлинности в Blazor WebAssembly приложениях, доступна подробная регистрация.

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

Взаимодействие JavaScript в WebAssembly

API взаимодействия JavaScript — это новый низкоуровневый механизм использования .NET в приложениях на основе JavaScript[JSImport][JSExport]/.Blazor WebAssembly Благодаря этой новой возможности взаимодействия JavaScript можно вызывать код .NET из JavaScript с помощью среды выполнения .NET WebAssembly и вызывать функции JavaScript из .NET без каких-либо зависимостей от модели компонента пользовательского Blazor интерфейса.

Дополнительные сведения см. по ссылке .

Условная регистрация поставщика состояния проверки подлинности

До выпуска .NET 7 AuthenticationStateProvider был зарегистрирован в контейнере AddScopedслужбы. Это усложняло отладку приложений, так как при предоставлении пользовательской реализации было принудительно выполнено определенное порядок регистрации служб. Из-за внутренних изменений платформы со временем больше не требуется зарегистрировать AuthenticationStateProvider в AddScoped.

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

- builder.Services.AddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();
+ builder.Services.TryAddScoped<AuthenticationStateProvider, ExternalAuthStateProvider>();

В предыдущем примере ExternalAuthStateProvider — это реализация службы разработчика.

Улучшения средств сборки .NET WebAssembly

Новые функции рабочей нагрузки wasm-tools для .NET 7, которые помогают повысить производительность и обрабатывать исключения:

Дополнительные сведения см. в статье ASP.NET Средства сборки Core Blazor WebAssembly и компиляция с заранеей компиляцией (AOT).

Blazor Hybrid

Внешние URL-адреса

Добавлен параметр, позволяющий открывать внешние веб-страницы в браузере.

Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor Hybrid и навигация.

Безопасность

Новые рекомендации доступны для Blazor Hybrid сценариев безопасности. Дополнительные сведения см. в следующих статьях:

Производительность

По промежуточному слоям кэширования выходных данных

Кэширование выходных данных — это новое ПО промежуточного слоя, которое хранит ответы из веб-приложения и обслуживает их из кэша, а не вычисляет их каждый раз. Кэширование выходных данных отличается от кэширования ответов следующими способами:

  • Поведение кэширования настраивается на сервере.
  • Записи кэша могут быть программным образом недействительными.
  • Блокировка ресурсов снижает риск метки кэша и гром стада.
  • Повторная проверка кэша означает, что сервер может возвращать 304 Not Modified код состояния HTTP вместо кэшированного текста ответа.
  • Среда хранилища кэша расширяема.

Дополнительные сведения см. в разделе "Обзор кэширования и кэширования выходных данных" по промежуточному слоям.

Улучшения HTTP/3

Этот выпуск:

  • Делает HTTP/3 полностью поддерживаемым ASP.NET Core, он больше не экспериментальн.
  • Улучшает Kestrelподдержку HTTP/3. Двумя основными областями улучшения являются четность функций с HTTP/1.1 и HTTP/2, а также производительность.
  • Обеспечивает полную поддержку UseHttps(ListenOptions, X509Certificate2) http/3. Kestrelпредоставляет дополнительные параметры настройки сертификатов подключения, например перехват в указание имени сервера (SNI).
  • Добавляет поддержку HTTP/3 в HTTP.sys и IIS.

В следующем примере показано, как использовать обратный вызов SNI для разрешения параметров TLS:

using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenAnyIP(8080, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
        listenOptions.UseHttps(new TlsHandshakeCallbackOptions
        {
            OnConnection = context =>
            {
                var options = new SslServerAuthenticationOptions
                {
                    ServerCertificate = 
                         MyResolveCertForHost(context.ClientHelloInfo.ServerName)
                };
                return new ValueTask<SslServerAuthenticationOptions>(options);
            },
        });
    });
});

В .NET 7 была проведена важная работа по сокращению выделения HTTP/3. Некоторые из этих улучшений можно увидеть в следующих GitHub PR:

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

.NET 7 представляет значительную переработанную архитектуру того, как Kestrel обрабатывает запросы HTTP/2. В приложениях ASP.NET Core с загруженными подключениями HTTP/2 будет наблюдаться снижение использования ЦП и повышение пропускной способности.

Ранее реализация мультиплексирования HTTP/2 зависела от блокировки, контролирующей то, какой запрос может выполнять запись в базовое подключение TCP. Потокобезопасная очередь заменяет блокировку записи. Теперь вместо того, чтобы потоки конкурировали за использование блокировки записи, запросы ставятся в очередь, и их обрабатывает выделенный потребитель. Ранее потраченные ресурсы ЦП были доступными для остальной части приложения.

Одним из мест, где можно заметить эти улучшения, является gRPC, популярная платформа RPC, использующая HTTP/2. Показатели Kestrel + gRPC показывают существенное улучшение:

Производительность потоковой передачи сервера gRPC

Изменения были внесены в код написания кода HTTP/2, что повышает производительность при наличии нескольких потоков, пытающихся записывать данные в одном подключении HTTP/2. Теперь мы отправим TLS в пул потоков и более быстро выпускаем блокировку записи, которую другие потоки могут получить для записи своих данных. Сокращение времени ожидания может повысить производительность в случаях, когда для этой блокировки записи возникает конфликт. Тест gRPC с 70 потоками в одном соединении (с TLS) показал улучшение запросов в секунду (RPS) на ~15 % с этим изменением.

Поддержка WebSockets по HTTP/2

.NET 7 содержит веб-ockets через поддержку HTTP/2 для Kestrelклиента SignalR JavaScript и SignalR с Blazor WebAssembly.

При использовании соединений WebSocket по HTTP/2 доступны новые возможности, в том числе следующие:

  • сжатие заголовка;
  • мультиплексирование, которое сокращает время и ресурсы, необходимые для выполнения нескольких запросов к серверу.

Эти функции доступны в Kestrel на всех платформах с поддержкой HTTP/2. Согласование версии выполняется в браузерах и Kestrel автоматически, поэтому новые интерфейсы API не требуются.

Дополнительные сведения см. в разделе поддержки Http/2 WebSockets.

Улучшенная производительность Kestrel на компьютерах с большим количеством ядер

Kestrel использует ConcurrentQueue<T> для многих целей. Одна из них — планирование операций ввода-вывода при транспортировке Kestrel на основе сокетов по умолчанию. Секционирование ConcurrentQueue на основе связанного сокета сокращает состязание и увеличивает пропускную способность на компьютерах с большим количеством ядер ЦП.

Профилирование на компьютерах с большим количеством ядер на .NET 6 продемонстрировало значительный показатель состязания в одном из других экземпляров ConcurrentQueueKestrel, в пуле PinnedMemoryPool, который Kestrel использует для кэширования буферов байтов.

В .NET 7 пул памяти Kestrel секционируется так же, как и его очередь ввода-вывода, что значительно сокращает состязание и увеличивает пропускную способность на компьютерах с большим количеством ядер. На виртуальных машинах ARM64 с 80 ядрами наблюдается повышение числа ответов в секунду (RPS) более чем на 500 % по результатам теста производительности TechEmpower с открытым текстом. На виртуальных машинах AMD с 48 ядрами повышение составляет почти 100 % по результатам теста производительности JSON для HTTPS.

Событие ServerReady для измерения времени запуска

Приложения, использующие EventSource, могут измерять время запуска, чтобы определить и оптимизировать его производительность. Новое событие ServerReady в Microsoft.AspNetCore.Hosting представляет точку, в которой сервер готов отвечать на запросы.

Сервер

Событие New ServerReady для измерения времени запуска

Событие ServerReady было добавлено для измерения времени запуска приложений ASP.NET Core.

IIS

Теневое копирование в IIS

Теневое копирование сборок приложений в модуль ASP.NET Core (ANCM) для IIS может быть удобнее для пользователя, чем остановка приложения путем развертывания автономного файла приложения.

Дополнительные сведения см. в разделе "Теневое копирование" в службах IIS.

Разное

Kestrel улучшения полной цепочки сертификатов

Https Подключение ionAdapterOptions имеет новое свойство ServerCertificateChain типа X509Certificate2Collection, что упрощает проверку цепочек сертификатов, позволяя выполнять полную цепочку, включая промежуточные сертификаты. Дополнительные сведения см. в dotnet/aspnetcore#21513 .

dotnet watch

Улучшенные выходные данные консоли для dotnet watch

Выходные данные консоли из dotnet watch были улучшены, чтобы соответствовать ведению журнала в ASP.NET Core, и дополнены 😮эмодзи😍.

Вот пример того, как выглядят новые выходные данные:

выходные данные для dotnet watch

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

Настройка dotnet watch для перезапуска при грубых изменениях

Грубые изменения — это изменения, которые не подлежат горячей перезагрузке. Чтобы настроить dotnet watch для перезапуска без запроса в случае грубых изменений, задайте для переменной среды DOTNET_WATCH_RESTART_ON_RUDE_EDIT значение true.

Темный режим страницы исключений для разработчиков

Поддержка темного режима была добавлена на страницу исключений для разработчиков благодаря участию Патрика Вестерхоффа (Patrick Westerhoff). Чтобы протестировать темный режим в браузере, на странице инструментов разработчика установите темный режим. Например, в Firefox:

Средства F12 FF темный режим

В Chrome:

Средства F12 Chrome — темный режим

Параметр шаблона проекта для использования метода Program.Main вместо инструкций верхнего уровня

В шаблонах .NET 7 можно не использовать инструкции верхнего уровня и не создавать namespace и метод Main, объявенный в классе Program.

С помощью .NET CLI задайте параметр --use-program-main:

dotnet new web --use-program-main

В Visual Studio установите флажок Не использовать инструкции верхнего уровня при создании проекта:

флажок

Обновленные шаблоны Angular и React

Шаблон проекта Angular обновлен до Angular 14. Шаблон проекта React обновлен до React 18.2.

Управление токенами JSON Web Token при разработке с использованием dotnet user-jwts

Новое средство командной строки dotnet user-jwts позволяет создавать локальные токены JSON Web Token (JWT) и управлять ими. Дополнительные сведения см. в статье Управление токенами JSON Web Token при разработке с использованием dotnet user-jwts.

Поддержка дополнительных заголовков запросов в W3CLogger

Теперь вы можете указывать дополнительные заголовки запросов для регистрации при использовании средства ведения журнала W3C. Для этого вызовите AdditionalRequestHeaders() для класса W3CLoggerOptions:

services.AddW3CLogging(logging =>
{
    logging.AdditionalRequestHeaders.Add("x-forwarded-for");
    logging.AdditionalRequestHeaders.Add("x-client-ssl-protocol");
});

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

Распаковка запросов

Новое ПО промежуточного слоя для распаковки запросов предоставляет такие преимущества:

  • позволяет конечным точкам API принимать запросы со сжатым содержимым;
  • использует заголовок HTTP Content-Encoding, чтобы автоматически обнаруживать и распаковывать запросы, содержащие сжатое содержимое;
  • устраняет необходимость писать код для обработки сжатых запросов.

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