Start Debugging

WebApplication.CreateBuilder vs CreateSlimBuilder vs CreateEmptyBuilder в ASP.NET Core 11

Используйте CreateBuilder для обычного приложения, CreateSlimBuilder, когда публикуете с обрезкой или Native AOT за TLS-прокси, и CreateEmptyBuilder только тогда, когда хотите зарегистрировать все сервисы сами. Вот матрица возможностей и подводные камни, которые определяют выбор.

Для обычного веб-приложения ASP.NET Core 11 используйте WebApplication.CreateBuilder(args). Это выбор по умолчанию не просто так: он подключает каждую возможность хостинга, которую вы ожидаете. Переходите на WebApplication.CreateSlimBuilder(args) только тогда, когда публикуете с обрезкой или Native AOT и работаете за прокси, завершающим TLS, потому что он отбрасывает HTTPS, HTTP/3, интеграцию с IIS, статические веб-ресурсы и два провайдера журналирования, чтобы уменьшить размер бинарного файла. Обращайтесь к WebApplication.CreateEmptyBuilder(...) лишь в редком случае, когда вам нужна почти нулевая базовая конфигурация и вы сами будете регистрировать сервер, маршрутизацию и конфигурацию. Эта статья ориентирована на .NET 11 (на момент написания Preview 6, общедоступный релиз в ноябре 2026 года) с Microsoft.NET.Sdk.Web и C# 14, но все три фабричных метода существуют начиная с .NET 8, поэтому рекомендации без изменений применимы к версиям с .NET 8 по 11.

Что на самом деле означают здесь “значения по умолчанию”

Три метода различаются ровно в одном: в том, сколько они регистрируют в WebApplicationBuilder до запуска вашего кода. Всё остальное, коллекция builder.Services, builder.Build(), app.MapGet(...), идентично. Поэтому всё решение сводится к тому, какие значения по умолчанию вы хотите получить в готовом виде, а какие готовы добавить вручную.

CreateBuilder даёт вам полный хост по умолчанию. CreateSlimBuilder даёт тщательно отобранное подмножество, выбранное так, чтобы быть безопасным при обрезке и небольшим. CreateEmptyBuilder не даёт почти ничего и ожидает, что вы явно подключите каждый компонент. Внутри они даже разделяют механику: CreateSlimBuilder построен на том же пустом построителе хост-приложения, который предоставляет CreateEmptyBuilder, а затем поверх него заново добавляет облегчённый набор сервисов. Именно поэтому приведённый ниже порядок образует строгую цепочку надмножеств: CreateBuilder включает всё, что есть в CreateSlimBuilder, который включает всё, что есть в CreateEmptyBuilder.

Матрица возможностей

Каждая строка проверена по документации ASP.NET Core 11 и исходному коду WebApplication.cs. “Вручную” означает, что возможность не регистрируется за вас, но вы можете добавить её показанным вызовом.

ВозможностьCreateBuilderCreateSlimBuilderCreateEmptyBuilder
appsettings.json + appsettings.{env}.jsonдадавручную
Пользовательские секреты (Development)дадавручную
Конфигурация из переменных среды и командной строкидадавручную
Журналирование в консольдадавручную (AddConsole)
Журналирование Debug / EventSource / EventLogданетнет
Сервер Kestrelполностьюядро (UseKestrelCore)вручную (UseKestrelCore)
HTTPS-эндпоинты в Kestrelданет (UseKestrelHttpsConfiguration)вручную
HTTP/3 (QUIC)данет (UseQuic)вручную
Интеграция с IISданетнет
Статические веб-ресурсыданетнет
Сборки для запуска хостинга / UseStartupданетнет
Ограничения маршрутизации regex и alphaданетнет
Маршрутизация / MapGet и т. д.дадавручную

Самый важный вывод из этой таблицы: CreateSlimBuilder по-прежнему сохраняет ваши источники конфигурации и журналирование в консоль. Он не убирает то, чем вы пользуетесь каждый день. Он удаляет возможности протоколов и платформы, которые обычно не нужны облачному развёртыванию за прокси, плюс три провайдера журналирования, которые вы редко читаете в продакшене.

Когда выбирать CreateBuilder

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

Когда выбирать CreateSlimBuilder

CreateSlimBuilder был представлен в .NET 8 специально для того, чтобы стать вариантом по умолчанию для шаблона Web API с Native AOT (dotnet new webapiaot). Выбирайте его, когда ваше развёртывание описывается следующим.

Если вы выбрали облегчённый вариант и позже обнаружили, что HTTPS или HTTP/3 всё же нужны, менять построитель не придётся. Добавьте их обратно явно:

// .NET 11, C# 14
var builder = WebApplication.CreateSlimBuilder(args);

// Re-enable HTTPS endpoints that CreateSlimBuilder omits by default.
builder.WebHost.UseKestrelHttpsConfiguration();

// Re-enable HTTP/3 (QUIC) if a client actually needs it.
builder.WebHost.UseQuic();

var app = builder.Build();
app.MapGet("/", () => "Hello from a slim host");
app.Run();

Когда выбирать CreateEmptyBuilder

CreateEmptyBuilder(WebApplicationOptions) создаёт построитель вообще без встроенного поведения. Приложение, которое он собирает, содержит только те сервисы и middleware, которые вы явно настроили. Это специализированный инструмент, а не общий вариант по умолчанию. Обращайтесь к нему, когда строите максимально малый сервис и хотите контролировать каждую регистрацию, либо когда экспериментируете с тем, как мало на самом деле нужно ASP.NET Core, чтобы обслужить запрос.

Вот канонический минимальный пример из заметок о выпуске .NET 8, который по-прежнему компилируется без изменений на .NET 11:

// .NET 11, C# 14
var builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions());

// Nothing is registered by default, so add the server yourself.
builder.WebHost.UseKestrelCore();

var app = builder.Build();

app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello, World!");
    await next(context);
});

Console.WriteLine("Running...");
app.Run();

Обратите внимание на то, чего здесь нет и что пришлось бы добавить вручную, если бы понадобилось: нет загрузки appsettings.json, нет журналирования в консоль, нет маршрутизации (то есть нет MapGet; вместо этого вы пишете сырое middleware) и нет привязки конфигурации. Каждое из этого вы добавляете явным вызовом: builder.Configuration.AddJsonFile("appsettings.json"), builder.Logging.AddConsole(), builder.Services.AddRouting() и так далее. В этом весь смысл пустого построителя: вы платите ровно за то, что используете.

История о размере, и почему это история об обрезке

Причина, по которой все три существуют, это размер бинарного файла и время запуска для Native AOT, а не чистая пропускная способность по запросам. Для JIT-компилируемого приложения три построителя регистрируют разные графы сервисов, но, как только приложение прогрелось, разница в запросах в секунду не там, где ценность. Ценность проявляется, когда вы применяете обрезку и AOT-компиляцию.

Собственный бенчмарк Microsoft для шаблона Web API с Native AOT сравнивает публикацию с Native AOT с обрезанной сборкой на среде выполнения и необрезанной сборкой на среде выполнения и сообщает, что AOT-приложение имеет наименьший размер приложения, потребление памяти и время запуска из трёх. Заметки о выпуске .NET 8 дают конкретную опору для нижнего края спектра: приведённый выше пример “Hello, World” с CreateEmptyBuilder, опубликованный с Native AOT на машине linux-x64, дал самодостаточный нативный исполняемый файл размером примерно 8.5 МБ. Эта цифра и есть то, как выглядит почти нулевая базовая конфигурация, когда AOT и обрезка делают своё дело.

Практический порядок, от наибольшего к наименьшему опубликованному размеру, таков: CreateBuilder, затем CreateSlimBuilder, затем CreateEmptyBuilder. Но разрыв между ними открывается только при PublishAot или PublishTrimmed. Поставьте обычную сборку, и вы заплатите за церемонию облегчённого или пустого построителя, не получив награды. Это самая распространённая ошибка: выбор облегчённого построителя для обычного развёртывания, потому что “slim звучит быстрее”. Он не быстрее во время выполнения; он меньше при обрезке. Если вы не применяете обрезку, во что на самом деле обходится вам Native AOT стоит прочитать, прежде чем связывать себя с облегчённым путём, а Native AOT vs ReadyToRun vs JIT охватывает, где выигрывает каждый режим публикации.

Подводный камень, который выбирает за вас

Предпочтения редко решают этот вопрос. Обычно решает одно из перечисленного.

Итоговый выбор

По умолчанию берите CreateBuilder. Это правильный выбор для подавляющего большинства приложений ASP.NET Core 11, включая каждое приложение, которое использует IIS, статические веб-ресурсы, MVC, Blazor или ограничения маршрутов regex. Переходите к CreateSlimBuilder тогда и только тогда, когда публикуете с обрезкой или Native AOT и находитесь за прокси, завершающим TLS, это ровно тот сценарий, на который нацелен шаблон webapiaot; заново добавляйте HTTPS или HTTP/3 одним вызовом UseKestrelHttpsConfiguration() или UseQuic(), если они вам нужны. Держите CreateEmptyBuilder про запас для по-настоящему минимального сервиса, где вы хотите зарегистрировать каждый последний компонент сами и измерить нижнюю границу. Единственное, чего делать не стоит, это выбирать облегчённый или пустой построитель для обычного JIT-развёртывания в расчёте на то, что он быстрее. Он меньше при обрезке, а не быстрее при работе, и на обычной сборке вы получаете трение без отдачи. Если вы вообще переносите более старый хост на эту модель, миграция с IWebHostBuilder на WebApplication.CreateBuilder это тот рубеж, который нужно пройти, прежде чем оптимизировать, какой фабричный метод вы вызываете.

По теме

Источники

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Назад