Razor Pages — первая программа
Razor Pages — первая программа
Razor Pages — серверный HTML
Web API (4511) отдаёт JSON — данные для программ. Razor Pages отдаёт готовый HTML: сервер собирает страницу из шаблона и отправляет браузеру. Удобно для админок, внутренних панелей, форм регистрации, отчётов — без отдельного React/Vue.
Модель простая: одна страница = два файла
Something.cshtml— разметка (HTML + директивы Razor);Something.cshtml.cs— класс PageModel с методамиOnGet,OnPost.
| Подход | Когда выбирать |
|---|---|
| Web API | Мобильное приложение, SPA, интеграции |
| Razor Pages | HTML с сервера, CRUD-формы, отчёты |
| Blazor | Интерактивный UI на C# в браузере (SignalR или WASM) |
| MVC (в 451) | Крупный сайт: один контроллер на много разных View |
Мы сделаем мини-сайт «Заметки»: список и форма добавления. Данные в памяти — как в 4511; с БД — 441.
Словарь
| Термин | Простыми словами |
|---|---|
| PageModel | Класс с данными страницы и обработчиками HTTP. |
| OnGet | Выполняется при GET — показать страницу. |
| OnPost | Выполняется при отправке формы method="post". |
| Model binding | Значения из формы попадают в свойства с [BindProperty]. |
| ModelState | Список ошибок валидации после привязки. |
| Tag Helper | Атрибуты asp-for, asp-validation-for — связь HTML и модели. |
| PRG | Post-Redirect-Get: после POST редирект на GET, чтобы F5 не дублировал отправку. |
| CSRF | Подделка запроса с чужого сайта; формы защищают скрытым токеном. |
Что получится
| URL | Файл | Действие |
|---|---|---|
/ | Pages/Index.cshtml | Приветствие |
/Notes | Pages/Notes/Index | Список + форма |
POST /Notes | тот же PageModel | Добавить заметку |
Требования
- .NET SDK 8+
- Базовый HTML помогает читать разметку, но не обязателен
Создание проекта
dotnet new webapp -n NotesRazor -o NotesRazor
cd NotesRazor
dotnet run
Шаблон webapp включает Razor Pages (папка Pages/). Откройте URL из консоли — стартовая страница уже работает.
Как устроена страница
Директива вверху .cshtml:
@page "/notes"
Без @page файл — просто фрагмент; с @page — маршрут. По умолчанию путь строится из папки: Pages/Notes/Index.cshtml → /Notes.
Структура:
Pages/
Notes/
Index.cshtml ← разметка
Index.cshtml.cs ← OnGet, OnPost, свойства
Модель заметки
Models/Note.cs:
namespace NotesRazor.Models;
public class Note
{
public int Id { get; set; }
public string Text { get; set; } = "";
public DateTime Created { get; set; } = DateTime.UtcNow;
}
Services/NoteStore.cs — хранилище в памяти:
using NotesRazor.Models;
namespace NotesRazor.Services;
public class NoteStore
{
private readonly List<Note> _items = new();
private int _nextId = 1;
public IReadOnlyList<Note> GetAll() =>
_items.OrderByDescending(n => n.Created).ToList();
public void Add(string text)
{
_items.Add(new Note { Id = _nextId++, Text = text.Trim() });
}
}
Program.cs:
builder.Services.AddSingleton<NoteStore>();
Singleton — один список на всё приложение (для учебного примера достаточно; с БД будет DbContext со Scoped).
PageModel — список и добавление
Pages/Notes/Index.cshtml.cs:
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using NotesRazor.Services;
namespace NotesRazor.Pages.Notes;
public class IndexModel : PageModel
{
private readonly NoteStore _store;
public IndexModel(NoteStore store) => _store = store;
public IReadOnlyList<Models.Note> Items { get; private set; } = [];
[BindProperty]
[Required(ErrorMessage = "Введите текст заметки")]
[StringLength(500)]
public string NewText { get; set; } = "";
public void OnGet()
{
Items = _store.GetAll();
}
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
Items = _store.GetAll();
return Page();
}
_store.Add(NewText);
return RedirectToPage();
}
}
Разбор PageModel
| Элемент | Смысл |
|---|---|
: PageModel | Базовый класс Razor Pages; даёт ModelState, RedirectToPage, Page(). |
Конструктор NoteStore | DI подставляет зарегистрированный сервис. |
Items | Данные для списка в разметке (Model.Items). |
[BindProperty] | При POST поле формы с именем NewText заполнит свойство. |
[Required], [StringLength] | Валидация; ошибки попадут в ModelState. |
OnGet() | Подготовить данные и показать страницу (без изменений). |
!ModelState.IsValid | Ошибка валидации — снова показать форму с сообщениями. |
return Page() | Отрендерить тот же .cshtml с текущей моделью. |
RedirectToPage() | PRG: после успеха редирект на GET /Notes — обновление F5 только перечитает список. |
Разметка страницы
Pages/Notes/Index.cshtml:
@page
@model NotesRazor.Pages.Notes.IndexModel
<h1>Заметки</h1>
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="NewText" class="form-control" placeholder="Новая заметка" />
<span asp-validation-for="NewText" class="text-danger"></span>
<button type="submit" class="btn btn-primary mt-2">Добавить</button>
</form>
<ul class="mt-4">
@foreach (var note in Model.Items)
{
<li><small>@note.Created.ToLocalTime():g</small> — @note.Text</li>
}
</ul>
| Tag Helper | Что делает |
|---|---|
asp-for="NewText" | name, id, значение поля связаны с NewText; для POST — правильное имя. |
asp-validation-for="NewText" | Показать текст ошибки из ModelState. |
asp-validation-summary="All" | Сводка всех ошибок над формой. |
<form method="post"> | Отправка на тот же URL → вызов OnPost. |
Форма с tag helpers добавляет anti-forgery token — скрытое поле, без которого POST вернёт 400 (защита от CSRF).
Pages/_ViewImports.cshtml (шаблон создаёт сам):
@using NotesRazor
@namespace NotesRazor.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Ссылка с главной
Pages/Index.cshtml:
<p><a href="/Notes">Мои заметки</a></p>
dotnet run
Добавьте заметки, нажмите F5 — дубликатов POST не будет благодаря redirect.
Razor Pages и Web API в одном проекте
builder.Services.AddRazorPages();
builder.Services.AddControllers();
var app = builder.Build();
app.MapRazorPages();
app.MapControllers();
Админка на Razor, публичное API — на контроллерах. Архитектура: 451.
Частые ошибки
| Симптом | Причина |
|---|---|
404 на /Notes | Нет @page или файл не Pages/Notes/Index.cshtml |
| POST не сохраняет | Нет [BindProperty] или method="get" у формы |
| Двойная отправка при F5 | Нет RedirectToPage() после успешного POST |
| Валидация не видна | Нет asp-validation-for / tag helpers |
| 400 Bad Request на POST | Убрали tag helpers — нет anti-forgery token |
Что попробовать
OnPostDelete(int id)с кнопкой удаления в форме.- Замените
NoteStoreна EF Core. [Authorize]на папкеNotesпосле 4515.
Дальше
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). C# как язык платформы .NET - устройство проекта, роль `.cs`-файлов и базовые принципы организации кода. C# — это современный, типизированный язык программирования общего назначения, разработанный корпорацией Microsoft. Справочник-шпаргалка по конфигурациям в C — типы, синтаксис, стандартная библиотека, типовые паттерны. Не заменяет пошаговое обучение. Учебный курс — раздел. Набор советов, правил, принципов и обычаев в разработке на этом языке. Кавычки, точки, запятые, скобки и прочие знаки препинания. Ключевые слова C# - назначение базовых конструкций языка и примеры их применения в типичном коде. Набор функций, которые включены в стандартную библиотеку языка. Пространства имён в C# - организация модулей, `file-scoped namespace` и поддержание чистой структуры кода. манипулировать данными (арифметические, логические, сравнительные операторы). Самый базовый способ ветвления — оператор if. Он проверяет условие и, если оно истинно (true), выполняет блок кода. Обработка исключений в C# - типы исключений, `try/catch/finally` и практики надежного кода. Платформо-зависимые исключения — например, PlatformNotSupportedException используется в кроссплатформенных API, когда функция недоступна на текущей ОС.C# - язык программирования платформы .NET
Что требуется знать перед началом изучения языка программирования C#
Справочник по конфигурациям в C#
Рекомендации по разработке на C#
Синтаксис и пунктуация в C#
Ключевые слова языка C#
Встроенные функции и методы C#
Пространства имён в C#
Управляющие конструкции и логические операторы
Условные выражения и ветвления
Обработка исключений в C#
Иерархия классов исключений в C#