BlazorJuniorCoding

Что такое компонент 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 на конкретном примере, а не только определением.
  • Указывает последствия для производительности, тестируемости и поддержки.
  • Различает документированное поведение текущего стека и устаревшие практики.

Sources

Related topics