Partilhar via


O que há de novo no ASP.NET Core 7.0

Este artigo destaca as alterações mais significativas no ASP.NET Core 7.0 com links para documentação relevante.

Middleware de limitação de requisições no ASP.NET Core

O middleware Microsoft.AspNetCore.RateLimiting fornece middleware de limitação de taxa. Os aplicativos configuram políticas de limitação de taxa e, em seguida, anexam as políticas aos pontos de extremidade. Para obter mais informações, consulte Rate limitando middleware no ASP.NET Core.

A autenticação usa um único esquema como DefaultScheme

Como parte do trabalho para simplificar a autenticação, quando há apenas um único esquema de autenticação registrado, ele é usado automaticamente como o DefaultScheme e não precisa ser especificado. Para obter mais informações, consulte DefaultScheme.

Páginas MVC e Razor

Suporte para modelos anuláveis em visualizações MVC e páginas Razor

Há suporte para modelos de página ou de vista anuláveis para melhorar a experiência ao usar a verificação de estados nulos com aplicações ASP.NET Core.

@model Product?

Vincular com IParsable<T>.TryParse em MVC e controladores de API

A API IParsable<TSelf>.TryParse suporta valores de parâmetros de ação do controlador de vinculação. Para obter mais informações, consulte Vincular com IParsable<T>.TryParse.

Nas versões ASP.NET Core anteriores a 7, a validação de consentimento cookie usa o valor cookieyes para indicar o consentimento. Agora você pode especificar o valor que representa o consentimento. Por exemplo, você pode usar true em vez de 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();

Para obter mais informações, consulte Personalizar o valor de consentimento cookie.

Controladores de API

Ligação de parâmetros com DI em controladores de API

A vinculação de parâmetros para ações de controladores de API vincula parâmetros por meio da injeção de dependência quando o tipo é configurado como serviço. Isso significa que não é mais necessário aplicar explicitamente o atributo [FromServices] a um parâmetro. No código a seguir, ambas as ações retornam o tempo:

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

Em casos raros, a DI automática pode quebrar aplicativos que têm um tipo de DI que também é aceito em um método de ação de controladores de API. Não é comum ter um tipo no DI e também como argumento numa ação de um controlador da API. Para desativar a vinculação automática de parâmetros, defina 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();

No ASP.NET Core 7.0, os tipos de DI são verificados na inicialização do aplicativo com IServiceProviderIsService para determinar se um argumento em uma ação do controlador de API vem da DI ou de outras fontes.

O novo mecanismo para inferir a origem vinculante dos parâmetros de ação do controlador de API usa as seguintes regras:

  1. Um BindingInfo.BindingSource especificado anteriormente nunca é substituído.
  2. Um parâmetro de tipo complexo, registrado no contêiner DI, é atribuído BindingSource.Services.
  3. Um parâmetro de tipo complexo, não registrado no contêiner DI, é atribuído BindingSource.Body.
  4. Um parâmetro com um nome que aparece como um valor de rota em qualquer modelo de rota em tem a atribuição de .
  5. Todos os outros parâmetros são BindingSource.Query.

Nomes de propriedades JSON em erros de validação

Por padrão, quando ocorre um erro de validação, a validação do modelo produz um ModelStateDictionary com o nome da propriedade como chave de erro. Alguns aplicativos, como aplicativos de página única, se beneficiam do uso de nomes de propriedade JSON para erros de validação gerados a partir de APIs da Web. O código a seguir configura a validação para que o SystemTextJsonValidationMetadataProvider use os nomes de propriedade 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();

O código a seguir configura a validação para que NewtonsoftJsonValidationMetadataProvider use o nome da propriedade JSON ao utilizar 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();

Para obter mais informações, consulte Use nomes de propriedade JSON em erros de validação

APIs mínimas

Filtros em aplicativos de API mínima

Filtros de API mínimos permitem que os desenvolvedores implementem uma lógica de negócios que suporte:

  • Executando código antes e depois do manipulador de rota.
  • Inspecionar e modificar parâmetros fornecidos durante uma chamada do manipulador de rotas.
  • Intercetando o comportamento de resposta de um manipulador de rota.

Os filtros podem ser úteis nos seguintes cenários:

  • Validação dos parâmetros de requisição e do seu corpo que são enviados para um endpoint.
  • Registro de informações sobre a solicitação e a resposta.
  • Validação de que uma solicitação está direcionada a uma versão de API suportada.

Para obter mais informações, consulte Filtros de em aplicativos de API mínima

Vincular matrizes e valores de texto de cabeçalhos e strings de consulta

No ASP.NET 7, há suporte para a vinculação de cadeias de caracteres a uma matriz de tipos primitivos, matrizes de cadeia de caracteres e 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]}");

A vinculação de cadeias de consulta ou valores de cabeçalho a uma matriz de tipos complexos é suportada quando o tipo tem a interface TryParse implementada. Para obter mais informações, consulte Vincular matrizes e valores de cadeia de caracteres de cabeçalhos e cadeias de caracteres de consulta.

Para obter mais informações, consulte Adicionar resumo ou descrição do ponto de extremidade.

Vincular o corpo da solicitação como um Stream ou PipeReader

O corpo da solicitação pode ser vinculado como um Stream ou PipeReader para suportar eficientemente cenários em que o usuário precisa processar dados e:

  • Armazene os dados no armazenamento de blob ou enfileire os dados num provedor de filas.
  • Processe os dados armazenados com um processo de trabalho ou função de nuvem.

Por exemplo, os dados podem ser enfileirados no armazenamento de filas do Azure ou armazenados no armazenamento de blobs do Azure .

Para obter mais informações, consulte Vincule o corpo do pedido como Stream ou PipeReader

Novas sobrecargas de Results.Stream

Introduzimos novas sobrecargas de Results.Stream para acomodar cenários que precisam de acesso ao fluxo de resposta HTTP subjacente sem buffering. Essas sobrecargas também melhoram os casos em que uma API transmite dados para o fluxo de resposta HTTP, como do Armazenamento de Blobs do Azure. O exemplo a seguir usa ImageSharp para retornar um tamanho reduzido da imagem especificada:

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

Para obter mais informações, consulte Exemplos de fluxo

Resultados digitados para APIs mínimas

No .NET 6, a interface IResult foi introduzida para representar valores retornados de APIs mínimas que não utilizam o suporte implícito para JSON serializar o objeto retornado para a resposta HTTP. A classe estática Results é usada para criar objetos de IResult variáveis que representam diferentes tipos de respostas. Por exemplo, definir o código de status da resposta ou redirecionar para outra URL. No entanto, os IResult tipos de estrutura de implementação retornados desses métodos eram internos, dificultando a verificação do tipo de IResult específico que estava sendo retornado dos métodos em um teste de unidade.

No .NET 7, os tipos que implementam IResult são públicos, permitindo asserções de tipo durante o teste. Por exemplo:

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

Testabilidade de unidades melhorada para manipuladores de rotas mínimas

Os tipos de implementação IResult estão agora disponíveis publicamente no namespace Microsoft.AspNetCore.Http.HttpResults. Os tipos de implementação IResult podem ser usados para testar em unidade manipuladores de rota mínimos ao usar métodos nomeados em vez de lambdas.

O código a seguir usa a classe 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);
}

Para obter mais informações, consulte IResult tipos de implementação.

Novas interfaces HttpResult

As interfaces a seguir no namespace Microsoft.AspNetCore.Http fornecem uma maneira de detetar o tipo de IResult em tempo de execução, que é um padrão comum em implementações de filtro:

Para obter mais informações, consulte interfaces IHttpResult.

Melhorias na OpenAPI para APIs mínimas

Microsoft.AspNetCore.OpenApi pacote do NuGet

O pacote Microsoft.AspNetCore.OpenApi permite interações com especificações OpenAPI para endpoints. O pacote atua como um link entre os modelos OpenAPI definidos no pacote Microsoft.AspNetCore.OpenApi e os pontos de extremidade definidos em APIs mínimas. O pacote fornece uma API que examina os parâmetros, respostas e metadados de um endpoint para construir um tipo de anotação OpenAPI que é usado para descrever um endpoint.

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();

Chamar WithOpenApi com parâmetros

O método WithOpenApi aceita uma função que pode ser usada para modificar a anotação OpenAPI. Por exemplo, no código a seguir, uma descrição é adicionada ao primeiro parâmetro do ponto de extremidade:

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

Fornecer descrições e resumos de pontos finais

APIs mínimas agora suportam operações de anotação com descrições e resumos para geração de especificações OpenAPI. Você pode chamar métodos de extensão WithDescription e WithSummary ou usar atributos [EndpointDescription] e [EndpointSummary]).

Para obter mais informações, consulte OpenAPI em aplicativos de API mínimos

Carregamentos de arquivos usando IFormFile e IFormFileCollection

APIs mínimas agora suportam o carregamento de ficheiros com IFormFile e IFormFileCollection. O código a seguir usa IFormFile e IFormFileCollection para carregar o arquivo:

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();

As solicitações autenticadas de carregamento de ficheiro são suportadas usando um cabeçalho Authorization, um certificado de cliente , ou um cabeçalho cookie.

Não há suporte integrado antifalsificação para . No entanto, ele pode ser implementado usando o serviço IAntiforgery.

[AsParameters] atributo permite a vinculação de parâmetros para listas de argumentos

O atributo [AsParameters] habilita a vinculação de parâmetros para listas de argumentos. Para mais informações, consulte a vinculação de parâmetro para listas de argumentos com [AsParameters].

APIs e controladores de API mínimos

Novo serviço de detalhes do problema

O serviço de detalhes do problema implementa a interface IProblemDetailsService, que suporta a criação de detalhes do problema para APIs HTTP.

Para mais informações, consulte o serviço de detalhes do problema .

Grupos de rotas

O método de extensão MapGroup ajuda a organizar grupos de pontos de extremidade com um prefixo comum. Ele reduz o código repetitivo e permite personalizar grupos inteiros de endpoints com uma única chamada para métodos como RequireAuthorization e WithMetadata que adicionam metadados de endpoint.

Por exemplo, o código a seguir cria dois grupos semelhantes de pontos de extremidade:

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

Nesse cenário, você pode usar um endereço relativo para o cabeçalho Location no resultado 201 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);
}

O primeiro grupo de endpoints só corresponderá a solicitações prefixadas com /public/todos e será acessível sem quaisquer autenticações. O segundo grupo de pontos de extremidade só corresponderá a solicitações prefixadas com /private/todos e exigirá autenticação.

O de fábrica do filtro de ponto de extremidade é uma função local que modifica os parâmetros de do manipulador de rotas para permitir acessar e armazenar dados inteiros privados.

Os grupos de rotas também suportam grupos aninhados e padrões de prefixo complexos com parâmetros e restrições de rota. No exemplo a seguir, o manipulador de rotas mapeado para o grupo user pode capturar os parâmetros de rota {org} e {group} definidos nos prefixos do grupo externo.

O prefixo também pode estar vazio. Isso pode ser útil para adicionar metadados ou filtros de ponto de extremidade a um grupo de pontos de extremidade sem alterar o padrão de rota.

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

Adicionar filtros ou metadados a um grupo comporta-se da mesma forma que adicioná-los individualmente a cada ponto de extremidade antes de adicionar quaisquer filtros ou metadados adicionais que possam ter sido adicionados a um grupo interno ou ponto de extremidade específico.

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

No exemplo acima, o filtro externo registrará a solicitação de entrada antes do filtro interno, mesmo que ele tenha sido adicionado em segundo lugar. Como os filtros foram aplicados a grupos diferentes, a ordem em que foram adicionados em relação uns aos outros não importa. Os filtros de ordem adicionados são importantes se aplicados ao mesmo grupo ou ponto de extremidade específico.

Uma solicitação para /outer/inner/ registrará o seguinte:

/outer group filter
/inner group filter
MapGet filter

gRPC

Transcodificação JSON

A extensão de transcodificação JSON gRPC para ASP.NET Core permite a criação de APIs JSON RESTful para serviços gRPC. A transcodificação JSON gRPC permite:

  • Aplicativos para chamar serviços gRPC com conceitos HTTP familiares.
  • Aplicações ASP.NET Core gRPC para suportar APIs gRPC e RESTful JSON sem replicar funcionalidades.
  • Suporte experimental para gerar OpenAPI a partir de APIs RESTful transcodificadas integrando-se com Swashbuckle.

Para obter mais informações, consulte transcodificação JSON gRPC em aplicações gRPC ASP.NET Core e Usar OpenAPI com transcodificação JSON em aplicações gRPC ASP.NET Core.

Verificações de integridade do gRPC no ASP.NET Core

O protocolo de verificação de integridade gRPC é um padrão para relatar a saúde de aplicativos de servidor gRPC. Uma aplicação expõe verificações de estado de saúde como um serviço gRPC. Eles geralmente são usados com um serviço de monitoramento externo para verificar o status de um aplicativo.

O gRPC ASP.NET Core adicionou suporte interno para verificações de integridade do gRPC com o pacote Grpc.AspNetCore.HealthChecks. Os resultados de verificações de integridade do .NET são relatados aos chamadores.

Para obter mais informações, consulte verificações de integridade do gRPC no ASP.NET Core.

Suporte melhorado a credenciais de chamada

As credenciais de chamada são a maneira recomendada de configurar um cliente gRPC para enviar um token de autenticação para o servidor. Os clientes gRPC suportam dois novos recursos para tornar as credenciais de chamada mais fáceis de usar:

  • Suporte para credenciais de chamada com conexões de texto simples. Anteriormente, uma chamada gRPC só enviava credenciais de chamada se a conexão estivesse protegida com TLS. Uma nova configuração no GrpcChannelOptions, chamada UnsafeUseInsecureChannelCallCredentials, permite que esse comportamento seja personalizado. Há implicações de segurança em não proteger uma conexão com TLS.
  • Um novo método chamado AddCallCredentials está disponível com o cliente gRPC de fábrica. AddCallCredentials é uma maneira rápida de configurar credenciais de chamada para um cliente gRPC e integra-se bem com a injeção de dependência (DI).

O código a seguir configura a fábrica do cliente gRPC para enviar metadados 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;
    });

Para mais informações, veja Configurar um token de autenticação com a fábrica do cliente gRPC.

SignalR

Resultados do cliente

O servidor agora suporta a solicitação de um resultado de um cliente. Isso requer que o servidor use ISingleClientProxy.InvokeAsync e o cliente retorne um resultado de seu manipulador de .On. Hubs fortemente tipados também conseguem devolver valores a partir dos métodos da interface.

Para obter mais informações, consulte resultados de clientes

Injeção de dependência para métodos de hub SignalR

Agora, os métodos do hub no SignalR suportam a injeção de serviços por meio de injeção de dependências (DI).

Os construtores de hub podem aceitar serviços de DI como parâmetros, que podem ser armazenados em propriedades na classe para uso em um método de hub. Para mais informações, consulte Injetar serviços num hub

Blazor

Manipular eventos de alteração de local e estado de navegação

No .NET 7, o Blazor oferece suporte a eventos de alteração de local e manutenção do estado de navegação. Isso permite que você avise os usuários sobre trabalhos não salvos ou execute ações relacionadas quando o usuário executa uma navegação de página.

Para obter mais informações, consulte as seguintes seções do artigo Roteamento e navegação:

Modelos de projeto Blazor vazios

Blazor tem dois novos modelos de projeto para começar a partir de uma folha em branco. Os novos modelos de projeto Blazor Server App Empty e Blazor WebAssembly App Empty são exatamente como seus homólogos não vazios, mas sem código de exemplo. Esses modelos vazios incluem apenas uma página inicial básica, e removemos o Bootstrap para que você possa começar com uma estrutura CSS diferente.

Para obter mais informações, consulte os seguintes artigos:

Blazor elementos personalizados

O pacote Microsoft.AspNetCore.Components.CustomElements permite criar elementos DOM personalizados baseados em padrões usando Blazor.

Para obter mais informações, consulte componentes do ASP.NET Core Razor.

Modificadores de ligação (@bind:after, @bind:get, @bind:set)

Importante

Os recursos @bind:after/@bind:get/@bind:set estão recebendo mais atualizações no momento. Para aproveitar as atualizações mais recentes, confirme se você instalou o SDK mais recente.

Não é suportado o uso de um parâmetro de callback de evento ([Parameter] public EventCallback<string> ValueChanged { get; set; }). Em vez disso, passe um método Action-return ou Task-return para @bind:set/@bind:after.

Para obter mais informações, consulte os seguintes recursos:

No .NET 7, você pode executar lógica assíncrona após a conclusão de um evento de vinculação usando o novo modificador @bind:after. No exemplo a seguir, o método assíncrono PerformSearch é executado automaticamente depois que quaisquer alterações no texto de pesquisa são detetadas:

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

@code {
    private string searchText;

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

No .NET 7, também é mais fácil configurar a vinculação para parâmetros de componentes. Os componentes podem suportar a vinculação de dados bidirecional definindo um par de parâmetros:

  • @bind:get: Especifica o valor a ser vinculado.
  • @bind:set: Especifica uma função de retorno para quando o valor muda.

Os modificadores @bind:get e @bind:set são sempre usados juntos.

Exemplos:

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

Para obter mais informações sobre o componente InputText, consulte componentes de entrada do ASP.NET Core Blazor.

Melhorias no Hot Reload

No .NET 7, o suporte a Hot Reload inclui o seguinte:

  • Os componentes redefinem seus parâmetros para seus valores padrão quando um valor é removido.
  • Blazor WebAssembly:
    • Adicione novos tipos.
    • Adicione classes aninhadas.
    • Adicione métodos estáticos e de instância aos tipos existentes.
    • Adicione campos estáticos e métodos a tipos existentes.
    • Adicione lambdas estáticos aos métodos existentes.
    • Adicione lambdas que capturam this a métodos existentes que já capturaram this anteriormente.

Pedidos de autenticação dinâmicos com MSAL no Blazor WebAssembly

Novo no .NET 7, Blazor WebAssembly oferece suporte à criação de solicitações de autenticação dinâmica em tempo de execução com parâmetros personalizados para lidar com cenários de autenticação avançada.

Para obter mais informações, consulte os seguintes artigos:

Blazor WebAssembly melhorias na depuração

A depuração de código Blazor WebAssembly tem as seguintes melhorias:

  • Suporte para a configuração Just My Code para mostrar ou ocultar elementos de tipo que não pertencem ao código do utilizador.
  • Suporte para inspeção de matrizes multidimensionais.
  • Pilha de Chamadas agora mostra o nome correto para métodos assíncronos.
  • Melhoria na avaliação das expressões.
  • Tratamento correto da palavra-chave new em membros derivados.
  • Suporte para atributos relacionados ao depurador no System.Diagnostics.

Suporte System.Security.Cryptography em WebAssembly

O .NET 6 suportava a família SHA de algoritmos de hash quando executado no WebAssembly. O .NET 7 permite mais algoritmos criptográficos, aproveitando SubtleCrypto, quando possível, e recorrendo a uma implementação .NET quando SubtleCrypto não pode ser usado. Os seguintes algoritmos são suportados no WebAssembly no .NET 7:

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

Para obter mais informações, consulte Desenvolvedores que visam o browser-wasm podem usar APIs de Cripto da Web (dotnet/runtime #40074).

Injetar serviços em atributos de validação personalizados

Agora você pode injetar serviços em atributos de validação personalizados. Blazor configura o ValidationContext para que ele possa ser usado como um provedor de serviços.

Para obter mais informações, consulte Blazorde validação de formulários .

Input* componentes fora de um EditContext/EditForm

Os componentes de entrada integrados agora são suportados fora de um formulário na componente de marcação Razor.

Para obter mais informações, consulte componentes de entrada do ASP.NET Core Blazor.

Alterações no modelo de projeto

Quando o .NET 6 foi lançado no ano passado, a marcação HTML da página _Host (Pages/_Host.chstml) foi dividida entre a página _Host e uma nova página de _Layout (Pages/_Layout.chstml) no modelo de projeto do .NET 6 Blazor Server.

No .NET 7, a marcação HTML foi recombinada com a página _Host em modelos de projeto.

Várias alterações adicionais foram feitas nos modelos de projeto Blazor. Não é viável listar todas as alterações nos modelos na documentação. Para migrar um aplicativo para o .NET 7 para adotar todas as alterações, consulte Migrar do ASP.NET Core 6.0 para o 7.0.

Componente QuickGrid experimental

O novo componente QuickGrid oferece uma grade de dados conveniente para os requisitos mais comuns, servindo também como arquitetura de referência e linha de base de desempenho para quem desenvolve componentes de grade de dados Blazor.

Para obter mais informações, consulte ASP.NET componente Core Blazor 'QuickGrid'.

Demonstração ao vivo: QuickGrid para Blazor aplicação de exemplo

Aprimoramentos de virtualização

Aprimoramentos de virtualização no .NET 7:

  • O componente Virtualize suporta o uso do próprio documento como a raiz de rolagem, como uma alternativa para ter algum outro elemento com overflow-y: scroll aplicado.
  • Se o componente Virtualize for colocado dentro de um elemento que exija um nome de tag filho específico, SpacerElement permite obter ou definir o nome da tag do espaçador de virtualização.

Para obter mais informações, consulte as seguintes seções do artigo Virtualization:

MouseEventArgs atualizações

MovementX e MovementY foram adicionados a MouseEventArgs.

Para obter mais informações, consulte o processamento de eventos do ASP.NET Core Blazor.

Nova página de carregamento de Blazor

O modelo de projeto Blazor WebAssembly tem uma nova interface de carregamento que mostra o progresso do carregamento do aplicativo.

Para obter mais informações, consulte ASP.NET Core Blazor startup.

Diagnósticos aprimorados para autenticação no Blazor WebAssembly

Para ajudar a diagnosticar problemas de autenticação em aplicações Blazor WebAssembly, está disponível um registo detalhado.

Para obter mais informações, consulte ASP.NET Core Blazor registo.

Interoperabilidade JavaScript no WebAssembly

JavaScript [JSImport]/[JSExport] interop API é um novo mecanismo de baixo nível para usar o .NET em aplicativos baseados em Blazor WebAssembly e JavaScript. Com esta nova funcionalidade de interoperabilidade JavaScript, é possível invocar código .NET a partir de JavaScript utilizando o runtime do .NET WebAssembly e chamar funcionalidades JavaScript a partir de .NET, sem qualquer dependência do modelo de componentes da interface de utilizador do Blazor.

Para mais informações:

Registro condicional do provedor de estado de autenticação

Antes do lançamento do .NET 7, AuthenticationStateProvider foi registrado no contêiner de serviço com AddScoped. Isso dificultou a depuração de aplicativos, pois forçou uma ordem específica de registros de serviço ao fornecer uma implementação personalizada. Devido a mudanças na estrutura interna ao longo do tempo, não é mais necessário registrar AuthenticationStateProvider com AddScoped.

No código do desenvolvedor, faça a seguinte alteração no registro do serviço do provedor de estado de autenticação:

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

No exemplo anterior, ExternalAuthStateProvider é a implementação de serviço do desenvolvedor.

Melhorias nas ferramentas de compilação do .NET WebAssembly

Novos recursos na carga de trabalho wasm-tools para .NET 7 que ajudam a melhorar o desempenho e lidar com exceções:

Para obter mais informações, consulte ferramentas de construção do ASP.NET Core Blazor WebAssembly e compilação antecipada (AOT).

Blazor Hybrid

URLs externas

Foi adicionada uma opção que permite abrir páginas da Web externas no navegador.

Para obter mais informações, consulte ASP.NET Core Blazor Hybrid roteamento e navegação.

Segurança

Novas orientações estão disponíveis para cenários de segurança Blazor Hybrid. Para obter mais informações, consulte os seguintes artigos:

Desempenho

Middleware de cache de saída

O cache de saída é um novo middleware que armazena respostas de um aplicativo Web e as atende a partir de um cache, em vez de computá-las sempre. O cache de saída difere do cache de resposta das seguintes maneiras:

  • O comportamento de cache é configurável no servidor.
  • As entradas de cache podem ser inválidas programaticamente.
  • O bloqueio de recursos reduz o risco de debandada de cache e rebanho trovejante.
  • A revalidação de cache significa que o servidor pode retornar um código de status HTTP 304 Not Modified em vez de um corpo de resposta em cache.
  • A mídia de armazenamento em cache é extensível.

Para obter mais informações, consulte Visão geral de cache e middleware de cache de saída.

Melhorias no HTTP/3

Esta versão:

  • Torna o HTTP/3 totalmente suportado pelo ASP.NET Core, não é mais experimental.
  • Melhora o suporte do Kestrelpara HTTP/3. As duas principais áreas de melhoria são a paridade de recursos com HTTP/1.1 e HTTP/2 e desempenho.
  • Fornece suporte completo para UseHttps(ListenOptions, X509Certificate2) com HTTP/3. Kestrel oferece opções avançadas para configurar certificados de conexão, como integrar-se com a Indicação de Nome do Servidor (SNI) .
  • Adiciona suporte para HTTP/3 no HTTP.sys e IIS.

O exemplo a seguir mostra como usar um retorno de chamada SNI para resolver opções 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);
            },
        });
    });
});

Um trabalho significativo foi feito no .NET 7 para reduzir as alocações HTTP/3. Você pode ver algumas dessas melhorias nos seguintes PRs do GitHub:

Melhorias de desempenho HTTP/2

O .NET 7 introduz uma rearquitetura significativa de como Kestrel processa solicitações HTTP/2. ASP.NET aplicativos principais com conexões HTTP/2 ocupadas experimentarão uso reduzido da CPU e maior taxa de transferência.

Anteriormente, a implementação de multiplexação HTTP/2 dependia de um bloqueio de para controlar qual solicitação pode gravar na conexão TCP subjacente. Uma fila thread-safe substitui o bloqueio de gravação. Agora, em vez de lutar por qual thread pode usar o bloqueio de escrita, as solicitações agora entram na fila e um consumidor dedicado processa-as. Recursos de CPU desperdiçados anteriormente estão disponíveis para o resto do aplicativo.

Um lugar onde essas melhorias podem ser notadas é no gRPC, um framework RPC popular que usa HTTP/2. Kestrel + benchmarks de gRPC mostram uma melhoria dramática:

desempenho de streaming do servidor gRPC

Foram feitas alterações no código de escrita de quadros HTTP/2 que melhora o desempenho quando há vários fluxos tentando gravar dados em uma única conexão HTTP/2. Passámos a enviar o trabalho TLS para o pool de threads e libertamos mais rapidamente um bloqueio de escrita que outros streams podem adquirir para escrever os seus dados. A redução nos tempos de espera pode gerar melhorias significativas de desempenho nos casos em que há disputa por esse bloqueio de gravação. Um benchmark gRPC com 70 fluxos numa única conexão (com TLS) mostrou uma melhoria de ~15% nas solicitações por segundo (RPS) com esta alteração.

Suporte a Http/2 WebSockets

O .NET 7 apresenta o suporte a WebSockets sobre HTTP/2 para Kestrel, o cliente JavaScript SignalR e SignalR com Blazor WebAssembly.

O uso de WebSockets sobre HTTP/2 aproveita os novos recursos, como:

  • Compressão de cabeçalho.
  • Multiplexação, que reduz o tempo e os recursos necessários ao fazer várias solicitações ao servidor.

Esses recursos suportados estão disponíveis em Kestrel em todas as plataformas habilitadas para HTTP/2. A negociação de versão é automática em navegadores e Kestrel, portanto, não são necessárias novas APIs.

Para obter mais informações, consulte o suporte a Http/2 WebSockets.

Kestrel melhorias de desempenho em máquinas de alto núcleo

Kestrel usa ConcurrentQueue<T> para muitos fins. Uma finalidade é agendar operações de E/S no transporte padrão de soquete do Kestrel. O particionamento do ConcurrentQueue com base no soquete associado reduz a contenção e aumenta a taxa de transferência em máquinas com muitos núcleos de CPU.

A criação de perfil em máquinas de alto núcleo no .NET 6 mostrou uma contenção significativa em uma das outras instâncias de Kestrel do ConcurrentQueue, a PinnedMemoryPool que Kestrel usa para armazenar buffers de bytes em cache.

No .NET 7, o pool de memória do Kestrelé particionado da mesma forma que sua fila de E/S, o que leva a uma contenção muito menor e a uma taxa de transferência mais alta em máquinas de alto núcleo. Nos VMs ARM64 de 80 núcleos, estamos a observar uma melhoria superior a 500% nas respostas por segundo (RPS) no teste de desempenho de texto simples TechEmpower. Em 48 VMs AMD Core, a melhoria é de quase 100% em nosso benchmark JSON HTTPS.

Evento ServerReady para medir o tempo de inicialização

Os aplicativos que usam EventSource podem medir o tempo de inicialização para entender e otimizar o desempenho da inicialização. O novo evento ServerReady no Microsoft.AspNetCore.Hosting representa o ponto em que o servidor está pronto para responder às solicitações.

Servidor

Novo evento ServerReady para medir o tempo de inicialização

O evento ServerReady foi adicionado para medir o tempo de inicialização dos aplicativos ASP.NET Core.

IIS

Cópia de sombra no IIS

A cópia instantânea de conjuntos de aplicações para o Módulo ASP.NET Core (ANCM) para IIS pode proporcionar uma melhor experiência do utilizador final do que parar a aplicação ao implantar um ficheiro de modo offline .

Para obter mais informações, consulte Cópia de sombra no IIS.

Diversos

Kestrel melhorias completas na cadeia de certificados

HttpsConnectionAdapterOptions tem uma nova propriedade ServerCertificateChain do tipo X509Certificate2Collection, que facilita a validação de cadeias de certificados, permitindo que uma cadeia completa, incluindo certificados intermediários, seja especificada. Consulte dotnet/aspnetcore#21513 para mais detalhes.

relógio dotnet

Saída de consola melhorada para relógio dotnet

A saída do console do relógio dotnet foi melhorada para se alinhar melhor com o registro do ASP.NET Core e se destacar com 😮emojis😍.

Aqui está um exemplo de como é a nova saída:

saída para o relógio dotnet

Para obter mais informações, consulte este pull request do GitHub.

Configurar o relógio dotnet para sempre reiniciar em caso de edições grosseiras

Edições rudes são edições que não podem ser recarregadas a quente. Para configurar o dotnet watch para reiniciar sempre sem solicitar em caso de edições rudes, defina a variável de ambiente DOTNET_WATCH_RESTART_ON_RUDE_EDIT como true.

Modo escuro da página de exceção do desenvolvedor

O suporte ao modo escuro foi adicionado à página de exceção do desenvolvedor, graças a uma contribuição do Patrick Westerhoff. Para testar o modo escuro em um navegador, na página de ferramentas do desenvolvedor, defina o modo como escuro. Por exemplo, no Firefox:

F12 ferramentas FF modo escuro

No Chrome:

F12 ferramentas Chrome modo escuro

Opção de modelo de projeto para usar o método Program.Main em vez de instruções de nível superior

Os modelos .NET 7 incluem uma opção para não usar instruções de nível superior e gerar um namespace e um método Main declarado numa classe Program.

Usando a CLI do .NET, utilize a opção '--use-program-main'.

dotnet new web --use-program-main

No Visual Studio, selecione a nova opção Não usar instruções de nível superior durante a criação do projeto:

caixa de seleção

Modelos Angular e React atualizados

O modelo de projeto Angular foi atualizado para Angular 14. O modelo de projeto React foi atualizado para React 18.2.

Gerencie Web Tokens JSON em desenvolvimento com dotnet user-jwts

A nova ferramenta de linha de comando dotnet user-jwts pode criar e gerenciar JSON Web Tokens (JWTs) locais específicos do aplicativo . Para obter mais informações, consulte Gerir JSON Web Tokens no desenvolvimento com dotnet user-jwts.

Suporte para cabeçalhos de solicitação adicionais no W3CLogger

Agora você pode especificar cabeçalhos de solicitação adicionais para registrar ao usar o registrador W3C chamando AdditionalRequestHeaders() em W3CLoggerOptions:

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

Para obter mais informações, consulte opções do W3CLogger.

Solicitar descompressão

O novo middleware de descompressão Request:

  • Permite que os pontos de extremidade da API aceitem solicitações com conteúdo compactado.
  • Usa o cabeçalho HTTP Content-Encoding para identificar e descompactar automaticamente solicitações que contêm conteúdo compactado.
  • Elimina a necessidade de escrever código para lidar com solicitações compactadas.

Para obter mais informações, consulte Pedido de middleware de descompactação.