Что такое компонент Blazor и как он структурирован в файле .razor?
Компонент Blazor — это файл .razor, компилируемый в C#-класс. Он состоит из директив (@page, @inject), HTML-шаблона с Razor-выражениями и блока @code с логикой. Параметры объявляются через атрибут [Parameter] на публичных свойствах.
Что такое компонент Blazor
Компонент Blazor — это самодостаточная единица UI, описанная в файле с расширением .razor. При компиляции Roslyn превращает его в C#-класс, наследующий Microsoft.AspNetCore.Components.ComponentBase. Компоненты переиспользуются, принимают параметры, хранят локальное состояние и реагируют на события.
Структура файла .razor
Файл .razor состоит из трёх необязательных секций, которые могут идти в любом порядке, но соглашение — сверху вниз:
- Директивы — строки, начинающиеся с
@:@page,@inject,@using,@inherits,@implements. - HTML-разметка с Razor-выражениями — шаблон компонента.
- Блок
@code { ... }— C#-поля, свойства, методы, обработчики событий.
Минимальный пример
@* Counter.razor *@
@page "/counter"
<h1>Счётчик: @_count</h1>
<button @onclick="Increment">+1</button>
@code {
private int _count = 0;
private void Increment() => _count++;
}
Параметры компонента
Публичные свойства, помеченные [Parameter], становятся атрибутами при использовании компонента:
@* Greeting.razor *@
<p>Привет, @Name!</p>
@code {
[Parameter] public string Name { get; set; } = "World";
// Для событий наружу
[Parameter] public EventCallback<string> OnGreeted { get; set; }
}
Использование в родителе:
<Greeting Name="Blazor" OnGreeted="HandleGreet" />
RenderFragment — слоты для контента
@* Card.razor *@
<div class="card">
<div class="card-header">@Title</div>
<div class="card-body">@ChildContent</div>
</div>
@code {
[Parameter] public string Title { get; set; } = "";
[Parameter] public RenderFragment? ChildContent { get; set; }
}
<Card Title="Моя карточка">
<p>Произвольный HTML внутри</p>
</Card>
Разделение на partial class
Логику можно вынести в файл Counter.razor.cs — он автоматически становится частичным классом того же компонента:
// Counter.razor.cs
namespace MyApp.Pages;
public partial class Counter
{
private int _count = 0;
private void Increment() => _count++;
}
Файл .razor при этом содержит только разметку, без @code.
Инъекция зависимостей
@inject HttpClient Http
@inject ILogger<Counter> Logger
В partial class аналог: атрибут [Inject] на свойстве.
Подводные камни
- Имя файла = имя класса: Blazor выводит имя компонента из имени файла. Если файл называется
my-counter.razor, компонент не скомпилируется — используйте PascalCase. - [Parameter] должен быть public set: свойство с
private setили только геттером не биндится и не вызывает ошибку компиляции, а просто молча игнорируется. - Мутация параметра внутри компонента: изменение параметра напрямую нарушает однонаправленный поток данных; используйте
EventCallbackдля уведомления родителя. - @page без leading slash: маршрут
@page "counter"(без/) не будет работать — Blazor требует абсолютный путь. - ChildContent и именованные слоты: нельзя иметь и
ChildContent, и другиеRenderFragment-параметры без явного тега внутри — компилятор не поймёт, куда класть контент. - Нет async в блоке @code напрямую: конструкция
@code { await ... }вне метода не компилируется — весь async-код должен быть внутри методов.
Common mistakes
- Путать структура Razor-компонента и связка markup/code с похожим механизмом из другой версии или платформы.
- Игнорировать runtime-границы Blazor: lifecycle, DI scope, SQL translation, UI thread или platform API.
- Не обсуждать null/empty/error cases и поведение под нагрузкой.
What the interviewer is testing
- Кандидат объясняет структура Razor-компонента и связка markup/code на конкретном примере, а не только определением.
- Указывает последствия для производительности, тестируемости и поддержки.
- Различает документированное поведение текущего стека и устаревшие практики.