Среди улучшений ASP.NET Core поддержка фильтров обработчиков маршрутов Minimal API, повышение тестируемости обработчиков маршрутов Minimal API, биндинг в контроллерах MVC и контроллерах API с помощью TryParse и не только. Материалом из блога разработчиков делимся к старту курса по разработке на C#.
Чтобы больше узнать о работе над ASP.NET Core для .NET 7, смотрите план развития ASP.NET Core для .NET 7 на GitHub.
Начнём
Загрузить SDK .NET 7 можно здесь.
Если вы на Windows и работаете с Visual Studio, мы рекомендуем установить последнюю предварительную версию Visual Studio 2022. На Visual Studio версии для Mac поддержки .NET 7 Preview 3 пока нет, но скоро она появится.
Чтобы установить последние инструменты сборки .NET WebAssembly, выполните эту команду с повышенными привилегиями:
dotnet workload install wasm-tools
Cоздание проектов .NET 6 Blazor с помощью SDK .NET 7 и инструментов сборки .NET 7 WebAssembly пока не поддерживается. Мы исправим это в обновлении .NET 7.
Обновление существующего проекта
Чтобы обновить существующее приложение ASP.NET Core с .NET 7 Preview 2 до .NET 7 Preview 3, измените:
все ссылки на пакеты Microsoft.AspNetCore.* — до версии 7.0.0-preview.3.*;
все ссылки на пакеты Microsoft.Extensions.* — до версии 7.0.0-preview.3.*;
Список изменений, ломающих обратную совместимость, смотрите по ссылке.
Поддержка фильтров обработчиков маршрутов в Minimal API
Теперь в обработчиках маршрутов приложений Minimal поддерживаются фильтры, выполняются они перед выполнением основной логики обработчика маршрута. Эти фильтры можно использовать, чтобы проверить и изменить обработчик, а также перехватить его выполнение. Регистрируются эти фильтры по-разному. К примеру, через RouteHandlerFilterDelegate и метод расширения AddFilter:
app.MapGet("/hello/{name}", (string name) => $"Hello, {name}!")
.AddFilter((context, next) =>
{
var name = (string) context.Parameters[0];
if (name == "Bob")
{
return Result.Problem("No Bob's allowed");
}
return next(context);
});
Или с помощью стратегии фабрики фильтров, которая открывает доступ к RouteHandlerContext. Последний, в свою очередь, предоставляет доступ к связанному с обработчиком MethodInfo, а также к метаданным, зарегистрированным в конечной точке:
app.MapGet("/hello/{name}", (string name) => $"Hello, {name}!")
.AddFilter((routeHandlerContext, next) =>
{
var parameters = routeHandlerContext.GetParameters();
var hasCorrectSignature = parameters.Length == 1 && parameters[0].GetType() == typeof(string);
return (context) =>
{
if (hasCorrectSignature)
{
var name = (string) context.Parameters[0];
if (name == "Bob")
{
return Result.Problem("No Bob's allowed");
}
}
return next(context);
}
});
Фильтры могут реализовывать интерфейс IRouteHandlerFilter, разрешаться из инъекции зависимостей или передаваться в качестве экземпляра:
app.MapGet("/hello/{name}", (string name) => $"Hello, {name}!")
.AddFilter<MyFilter>();
Повышена тестируемость обработчиков маршрутов Minimal API
Типы реализации IResult с суффиксом HttpResult
(OkObjectHttpResult
, ProblemHttpResult
и так далее) теперь открыты в пространстве имён Microsoft.AspNetCore.Http
. Благодаря этим типам проще тестировать обработчики маршрутов Minimal API, вместо лямбда-выражений используя именованные методы:
[Fact]
public async Task GetTodoReturnsTodoFromDatabase()
{
var todo = new Todo { Id = 42, Name = "Improve Results testability!" };
var mockDb = new MockTodoDb(new[] { todo });
var result = (OkObjectHttpResult)await TodoEndpoints.GetTodo(mockDb, todo.Id);
//Assert
Assert.Equal(200, result.StatusCode);
var foundTodo = Assert.IsAssignableFrom<Models.Todo>(result.Value);
Assert.Equal(id, foundTodo.Id);
}
[Fact]
public void CreateTodoWithValidationProblems()
{
//Arrange
var newTodo = default(Todo);
var mockDb = new MockTodoDb();
//Act
var result = TodoEndpoints.CreateTodo(mockDb, newTodo);
//Assert
var problemResult = Assert.IsAssignableFrom<ProblemHttpResult>(result);
Assert.NotNull(problemResult.ProblemDetails);
Assert.Equal(400, problemResult.StatusCode);
}
Биндинг с помощью TryParse в контроллерах MVC и контроллерах API
Значения параметров действия контроллера теперь можно привязывать с помощью метода TryParse с одной из этих сигнатур:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
Ниже действие Get привязывает данные из строки запроса через метод типа-параметра TryParse:
public class TryParseController : ControllerBase
{
// GET /tryparse?data=MyName
[HttpGet]
public ActionResult Get([FromQuery]CustomTryParseObject data) => Ok();
public class CustomTryParseObject
{
public string? Name { get; set; }
public static bool TryParse(string s, out CustomTryParseObject result)
{
if (s is null)
{
result = default;
return false;
}
result = new CustomTryParseObject { Name = s };
return true;
}
}
}
Новые перегрузки Results.Stream()
Для ситуаций, когда к базовому потоку ответов HTTP нужен доступ без буферизации, написаны новые перегрузки Results.Stream(...). Эти перегрузки упрощают передачу данных в поток ответов HTTP через API, например из хранилища BLOB-объектов Azure. Ниже Results.Stream() используется в обработке изображений через сервис ImageSharp:
app.MapGet("/process-image", async (HttpContext http) =>
{
using var image = await Image.LoadAsync("puppy.jpeg");
int width = image.Width / 2;
int height = image.Height / 2;
image.Mutate(x => x.Resize(width, height));
http.Response.Headers.CacheControl = $"public,max-age={FromHours(24).TotalSeconds}";
return Results.Stream(stream => image.SaveAsync(stream, PngFormat.Instance), "image/png");
});
Повышена производительность соединения HTTP/2 с несколькими стримами
Мы изменили код записи фреймов HTTP/2. Этот код повышает производительность при наличии нескольких стримов, пытающихся записать данные в одном соединении HTTP/2. Теперь работа TLS отправляется в пул потоков.
Блокировка записи, которую другие стримы могут получить для записи своих данных, освобождается быстрее. Когда за эту блокировку есть конкуренция, сокращение времени ожидания может значительно повысить производительность.
Тест gRPC с 70 потоками в одном соединении с TLS показал увеличение количества запросов в секунду примерно на 15%.
Новое событие измерения времени запуска приложения — ServerReady
Если для измерений или диагностики вы используете EventSource и хотите измерить время запуска своего приложения, можно использовать новое событие ServerReady в источнике Microsoft.AspNetCore.Hosting
. Это событие представляет момент, когда сервер запущен и работает.
Тёмная тема страницы исключений для разработчиков
Страница исключений для разработчиков ASP.NET Core теперь поддерживает тёмную тему:
За это улучшение благодарим @poke!
Обратная связь
Надеемся, что вам понравится этот предварительный релиз ASP.NET Core в .NET 7. Сообщите нам, что вы думаете об этих улучшениях, отправив Issues на GitHub. Спасибо, что попробовали ASP.NET Core!
А мы поможем прокачать скиллы или с самого начала освоить IT-профессию, актуальную в любое время:
Выбрать другую востребованную профессию.
Краткий каталог курсов и профессий
Data Science и Machine Learning
Python, веб-разработка
Мобильная разработка
Java и C#
От основ — в глубину
А также
Dr9vik
а куда они спешат?
я только недавно начал 6 ковырять, а тут уже 7 наподлёте
и больше похоже на минорные изменения, назвали бы 5.2 ничего бы не изменилось
ZZnOB
Ковыряйте на здоровье, Net 6 же LTS, потом будете ковырять Net 8, пока на Net 7 можно посматривать из праздного любопытства.