С выходом .NET 9 пакет Swashbuckle.AspNetCore выпилили из шаблона Web API. Это означает, что при создании нового приложения ASP.NET Core Web API у нас больше нет привычного зеленого пользовательского интерфейса Swagger для тестирования endpoint-ов. В статье — краткий разбор, почему это произошло, и обзор альтернативы Scalar.
Что не так со Swagger в .NET
Раньше, чтобы создать документацию OpenAPI в ASP.NET Core, многие пользовались Swashbuckle. Это было настолько популярным решением, что Microsoft включила его в дефолтные шаблоны Web API.
Но в какой-то момент основные разработчики Swashbuckle покинули проект и начались трудности: копился техдолг, и запоздалая поддержка .NET 8 привела к проблемам совместимости. Тогда Microsoft засомневались, что продукт будет развиваться и вовремя поддерживать новые версии .NET.
Чтобы перестраховаться, Microsoft отказались от Swashbuckle и сделали собственное решение — ведь поддерживать и интегрировать своё проще, чем чужое. Теперь при создании решения в .NET 9 из шаблона Web API в проекте будет пакет Microsoft.AspNetCore.OpenApi.
С пакетом OpenApi разработчики получили больше собственных способов тестирования и документирования API. Например, теперь есть поддержка файлов .http в Visual Studio и Endpoints Explorer. Это делает Swagger UI менее необходимым.
Прочитать мнение Microsoft по этому поводу
А что, Swagger больше совсем не работает?
Пакет Swashbuckle.AspNetCore доступен, его можно установить, и нет предпосылок к тому, что это изменится. Проблема в том, что проект развивается крайне медленно и не успевает за новыми фичами ASP.NET Core.
Но для тех, кто хочет продолжать использовать Swagger, есть целых два способа. Первый — заменить пакет Microsoft.AspNetCore.OpenApi на Swashbuckle.AspNetCore. Затем добавить привычные вызовы.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.MapGet("/", => "Hello World!");
app.Run();
Тогда OpenAPI-спецификация будет генерироваться с помощью библиотеки Swashbuckle как и раньше.
Второй способ — оставить пакет Microsoft.AspNetCore.OpenApi для генерации спецификации, а подключить только Swagger UI.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.UseSwaggerUI(o =>
o.SwaggerEndpoint("/openapi/v1.json", "v1"));
app.MapGet("/", => "Hello World!");
app.Run();
В этом случае при вызове UseSwaggerUI важно указать путь для файла со спецификацией.
Немного про настройку OpenAPI
Генерацию спецификации через пакет OpenApi можно гибко настраивать, как и при Swagger. Вот основные значения, которые можно указать:
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, cancellationToken) =>
{
document.Info.Version = "Версия документа OpenAPI";
document.Info.Title = "Заголовок";
document.Info.Description = "Описание";
document.Info.TermsOfService = new Uri("https://mycompany.com/terms");
document.Info.Contact = new OpenApiContact
{
Name = "Ivan Ivanov",
Email = "iivanov@mycompany.com",
Url = new Uri("https://habr.com/")
};
document.Info.License = new OpenApiLicense
{
Name = "MIT License",
Url = new Uri("https://opensource.org/licenses/MIT")
};
//Информация о подключении к целевому серверу
document.Servers.Add(new OpenApiServer
{
Url = "https://my.app.com/v1",
Description = "Описание для хоста"
});
return Task.CompletedTask;
});
});
Можно настроить метаданные OpenAPI для endpoint-ов Minimal API в ASP.NET Core:
app.MapGet("/{answer}",
(
[Description("Your answer.")]
[DefaultValue("42")]
string answer
) => Results.Ok(new { Message = $"Answer: {answer}!" }))
.WithName("GetAnswer") // Идентификатор операции
.WithSummary("Answer to the Question.") // Заголовок
.WithDescription("Answer to the Ultimate Question of Life, the Universe, and Everything.") // Полное описание
.WithTags("DeepThought") // Теги для категоризации
.Produces<object>(200) // Статус ответа 200 и возвращаемый тип данных
.Produces(400) // Статус ответа 400
.ProducesProblem(500) // Статус ответа 500 при неуспешной операции
.RequireAuthorization(); // Необходимость авторизации
Scalar как альтернатива SwaggerUI
Scalar — это платформа с открытым исходным кодом для документирования и взаимодействия с RESTful API. Он поддерживает спецификации OpenAPI и Swagger, так что его можно легко интегрировать в большинство существующих решений.
Счётчик скачивания пакетов и больше 10K звезд на GitHub наводят на мысль, что в сообществе .NET его всё чаще выбирают как альтернативу SwaggerUI.
У Scalar более современный и удобный дизайн, его проще настраивать. Есть мощная функция генерации клиентского кода для различных языков программирования. А ещё с ним легко добавлять или изменять файлы cookie, заголовки и параметры при работе с запросами.
Начало работы со Scalar
Первым делом необходимо добавить nuget-пакет Scalar.AspNetCore. А затем подключить Scalar в Program.cs:
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.MapScalarApiReference();
}
Ещё можно изменить файл launchSettings.json, чтобы Scalar UI запускался сразу после старта приложения.
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "scalar/v1",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
Этого достаточно, чтобы при запуске приложения по пути /scalar/v1 открывалась соответствующая страница.

Слева отображаются все сгруппированные по тегам endpoint-ы и все модели. На моём скриншоте виден единственный endpoint и относящаяся к нему модель ProblemDetails. На основной части страницы отображается информация о приложении, полученная из OpenAPI-схемы. Есть поиск с удобной навигацией по endpoint-ам и моделям.

Если выбрать endpoint из списка на основной странице или на странице поиска, отобразится описание запроса с параметрами и коды ответа.

Чтобы отправить запрос в приложение, нужно нажать Test Request.

Слева на странице можно посмотреть и изменить параметры запроса, заголовки и куки. В поле Code Snippet формируется код запроса с актуальными параметрами. По дефолту выбрана системная программа Curl, но в выпадающем списке спрятано много языков программирования — в том числе C#.
Send отправляет запрос, а справа отображается ответ. В целом вся эта страница по функционалу напоминает Postman.
Конфигурация Scalar
Сильная сторона Scalar — это количество возможных настроек. Изменить можно тему, переключатели темного режима и многое другое.
app.MapScalarApiReference(options =>
{
options
.WithTheme(ScalarTheme.Kepler)
.WithDarkModeToggle(true)
.WithClientButton(true);
});
Про темы. Сейчас много готовых тем, но если хочется, можно полностью изменить внешний вид страницы, используя CSS. Прочитать
Про работу с аутентификацией. Scalar поддерживает различные схемы аутентификации, включая API Key, OAuth2 и HTTP Basic/Bearer. Это позволяет предустанавливать определённые данные аутентификации. Пример настройки аутентификации OAuth2:
app.MapScalarApiReference(options => options
.AddPreferredSecuritySchemes("OAuth2")
.AddOAuth2Authentication("OAuth2", scheme =>
{
scheme.Flows = new ScalarFlows
{
AuthorizationCode = new AuthorizationCodeFlow
{
ClientId = "your-client-id",
RedirectUri = "https://your-app.com/callback"
},
ClientCredentials = new ClientCredentialsFlow
{
ClientId = "your-client-id",
ClientSecret = "your-client-secret"
}
};
scheme.DefaultScopes = ["profile", "email"];
})
);
Полная информация о подключении различных типов аутентификации и о настройке Scalar в целом — в официальной документации.
Итог
Мне Scalar понравился. Из плюсов — простое подключение и начало работы, гибкая настройка, хорошая документация с примерами. Ещё большой плюс — активное развитие кодовой базы. По функционалу Scalar сильно выигрывает у SwaggerUI.
Из минусов отмечу непривычный после Swagger-а интерфейс, который скорее напоминает Postman на минималках. И уверен, что все имеющиеся функции нужны далеко не в каждом проекте.