ASP.NET Core и разработка на .NET
ASP.NET Core - кроссплатформенная платформа для разработки веб-приложений, API и серверных сервисов в экосистеме .NET. Она используется в корпоративных системах, интеграционных сервисах, личных кабинетах, административных приложениях и backend-системах с высокими требованиями к производительности и поддерживаемости.
ASP.NET Core работает на Windows, Linux и macOS и может запускаться как непосредственно на сервере, так и в контейнерах.
Типовая архитектура может выглядеть так:
Browser / Client
↓
Reverse Proxy
↓
ASP.NET Core
↓
Application Logic
↓
Database / Cache / Queue / External APIОсновные возможности ASP.NET Core
- Web API для мобильных приложений, SPA, интеграций и внутренних сервисов.
- MVC и Razor Pages для серверных веб-интерфейсов.
- Blazor для разработки интерактивных интерфейсов в экосистеме .NET.
- Встроенный Dependency Injection.
- Middleware pipeline для обработки HTTP-запросов.
- Аутентификация и авторизация.
- SignalR для real-time взаимодействия.
- gRPC для взаимодействия сервисов.
- Конфигурация и управление окружениями.
- Интеграция с системами логирования, метрик и трассировки.
Middleware Pipeline
Один из основных механизмов ASP.NET Core - последовательность middleware, через которую проходит HTTP-запрос.
Упрощенно:
HTTP Request
↓
Exception Handling
↓
HTTPS / Security
↓
Routing
↓
Authentication
↓
Authorization
↓
Endpoint
↓
HTTP ResponseКаждый middleware может:
- Обработать запрос.
- Изменить запрос или ответ.
- Передать выполнение дальше.
- Прервать pipeline и вернуть собственный ответ.
Порядок middleware имеет значение, поскольку аутентификация, маршрутизация, обработка ошибок и другие механизмы зависят друг от друга.
Dependency Injection
ASP.NET Core имеет встроенный Dependency Injection container.
Зависимости регистрируются в приложении и передаются компонентам через конструкторы или другие поддерживаемые механизмы.
Например:
builder.Services.AddScoped<IUserService, UserService>();Основные lifetime:
- Transient - новый экземпляр при каждом запросе зависимости.
- Scoped - один экземпляр в пределах scope, обычно HTTP-запроса.
- Singleton - один экземпляр на время работы приложения.
Корректный выбор lifetime особенно важен при работе с базой данных, кешами и объектами, имеющими внутреннее состояние.
Web API
ASP.NET Core широко используется для разработки HTTP API.
API может обслуживать:
- SPA-приложения.
- Мобильные приложения.
- Внешние интеграции.
- Микросервисы.
- Внутренние корпоративные системы.
При проектировании API учитываются:
- Структура endpoint.
- HTTP-методы.
- Коды ответов.
- Валидация.
- Пагинация.
- Фильтрация.
- Версионирование.
- Аутентификация.
- Ограничение частоты запросов.
Controllers и Minimal APIs
ASP.NET Core поддерживает несколько способов описания HTTP endpoint.
Controllers
Controllers подходят для приложений, где требуется структурированное разделение endpoint, фильтров, авторизации и моделей запросов.
Minimal APIs
Minimal APIs позволяют определять endpoint с меньшим количеством инфраструктурного кода.
Например:
app.MapGet("/users/{id}", async (int id, IUserService users) =>
{
return await users.GetByIdAsync(id);
});Такой подход удобен для небольших API и сервисов, но архитектурная структура приложения все равно должна соответствовать его сложности.
MVC и Razor Pages
ASP.NET Core может использоваться не только как backend для отдельного frontend-приложения.
Серверный HTML может формироваться через:
- MVC.
- Razor Pages.
- Razor Views.
Такой подход подходит для сайтов и приложений, где нет необходимости переносить всю логику интерфейса в SPA.
Blazor
Blazor позволяет разрабатывать интерактивные веб-интерфейсы с использованием C# и компонентов .NET.
В зависимости от архитектуры выполнение может происходить на сервере, в браузере или использовать комбинированную модель.
Blazor может быть полезен в проектах, где:
- Основной технологический стек построен на .NET.
- Команда преимущественно работает с C#.
- Требуется разделять код и модели между frontend и backend.
Работа с базами данных
ASP.NET Core не привязан к конкретной СУБД.
В приложениях могут использоваться:
- Microsoft SQL Server.
- PostgreSQL.
- MySQL.
- SQLite.
- Другие хранилища данных.
Entity Framework Core
Entity Framework Core - ORM для работы с реляционными базами данных в .NET.
Он позволяет описывать модели в коде и работать с данными через LINQ.
Например:
var users = await db.Users
.Where(x => x.IsActive)
.OrderBy(x => x.Name)
.ToListAsync();EF Core поддерживает:
- LINQ-запросы.
- Change Tracking.
- Миграции.
- Транзакции.
- Связи между сущностями.
- Optimistic Concurrency.
Производительность работы с базой данных
Использование ORM не отменяет необходимость понимать SQL и работу реляционной базы данных.
При анализе производительности учитываются:
- Количество выполняемых запросов.
- Индексы.
- Планы выполнения.
- Размер выборок.
- N+1.
- Пагинация.
- Транзакции.
Для read-only операций в EF Core также может быть полезно отключение Change Tracking там, где отслеживание изменений не требуется.
Архитектура приложения
Бизнес-логика не должна обязательно размещаться непосредственно в Controllers.
По мере роста приложения обычно выделяются отдельные уровни или модули:
API / UI
↓
Application
↓
Domain
↓
Infrastructure
↓
Database / External SystemsКонкретное количество слоев зависит от размера системы.
Небольшому приложению не требуется сложная архитектура только ради формального соблюдения шаблона.
Clean Architecture
Clean Architecture - один из способов организовать зависимости между слоями приложения.
Основная идея заключается в том, чтобы бизнес-правила не зависели напрямую от конкретной базы данных, web-framework или внешнего сервиса.
Например:
Presentation
↓
Application
↓
Domain
Infrastructure → реализует внешние зависимостиПодход может быть полезен в системах со сложной бизнес-логикой и большим сроком эксплуатации, но добавляет дополнительную структуру и количество абстракций.
Domain-Driven Design
Domain-Driven Design используется в проектах со сложной предметной областью.
В нем могут применяться:
- Entities.
- Value Objects.
- Aggregates.
- Domain Services.
- Domain Events.
- Bounded Contexts.
DDD не требуется для обычного CRUD-приложения и применяется там, где сложность предметной области действительно оправдывает дополнительную архитектуру.
CQRS
CQRS предполагает разделение моделей чтения и изменения данных.
Упрощенно:
Command → изменение состояния
Query → получение данныхCQRS может применяться как внутри обычного монолита, так и в более сложных распределенных системах.
Полное разделение хранилищ чтения и записи требуется значительно реже, чем простое логическое разделение команд и запросов.
MediatR и Mediator Pattern
В .NET-проектах может использоваться Mediator Pattern для уменьшения прямых зависимостей между точками входа и обработчиками бизнес-операций.
Одна из известных библиотек для такого подхода - MediatR.
Схема может выглядеть так:
Controller
↓
Command / Query
↓
Mediator
↓
HandlerПодход позволяет централизовать дополнительные механизмы, например:
- Валидацию.
- Логирование.
- Метрики.
- Транзакционную обработку.
При этом использование Mediator не является обязательным требованием для архитектуры ASP.NET Core.
Модульный монолит
Для значительного количества систем подходит архитектура модульного монолита.
Приложение остается единым deployment unit, но внутри разделяется на функциональные области.
Например:
Application
├── Users
├── Catalog
├── Orders
├── Payments
├── Billing
└── NotificationsТакой подход позволяет сохранить сравнительно простую эксплуатацию и одновременно сформировать понятные границы между функциональными областями.
Микросервисы
ASP.NET Core подходит для разработки микросервисов, но использование микросервисной архитектуры определяется требованиями системы, а не возможностями framework.
Разделение может быть оправдано, если требуются:
- Независимые релизы.
- Независимое масштабирование.
- Четкие бизнес-границы.
- Автономная работа нескольких команд.
- Разные требования к нагрузке отдельных компонентов.
При этом микросервисы добавляют:
- Сетевое взаимодействие.
- Распределенные данные.
- Дополнительный мониторинг.
- Более сложный deployment.
- Необходимость обработки частичных отказов.
gRPC
gRPC может использоваться для взаимодействия между сервисами.
Он использует строго описанные контракты и Protocol Buffers.
Подходит для сценариев, где важны:
- Типизированные контракты.
- Эффективное внутреннее взаимодействие сервисов.
- Streaming.
- Генерация клиентского и серверного кода.
SignalR
SignalR используется для real-time взаимодействия между сервером и клиентами.
Типовые сценарии:
- Уведомления.
- Чаты.
- Обновление статусов.
- Панели мониторинга.
- Совместная работа пользователей.
SignalR управляет абстракцией соединения и может использовать доступные транспортные механизмы в зависимости от клиента и инфраструктуры.
Фоновые задачи
Длительные операции не рекомендуется выполнять непосредственно внутри пользовательского HTTP-запроса, если результат не требуется для формирования ответа.
В фон могут переноситься:
- Отправка уведомлений.
- Импорт и экспорт.
- Формирование документов.
- Синхронизация данных.
- Тяжелая обработка файлов.
Для этого могут использоваться BackgroundService, очереди сообщений и специализированные системы выполнения фоновых задач.
Асинхронное программирование
ASP.NET Core активно использует модель async/await.
Асинхронность особенно полезна для I/O-операций:
- Запросов к базе данных.
- HTTP-запросов.
- Работы с файловыми хранилищами.
- Внешних сервисов.
Во время ожидания I/O поток может использоваться для обработки других запросов, что помогает эффективнее использовать серверные ресурсы.
Кеширование
ASP.NET Core поддерживает несколько уровней кеширования.
В зависимости от задачи могут использоваться:
- In-Memory Cache.
- Distributed Cache.
- Redis.
- HTTP Cache.
- Output Caching.
Выбор зависит от того, должен ли кеш быть локальным для одного экземпляра приложения или общим для нескольких узлов.
Масштабирование
ASP.NET Core приложения могут масштабироваться вертикально и горизонтально.
Вертикальное масштабирование
Увеличиваются ресурсы одного экземпляра:
- CPU.
- RAM.
- Производительность диска.
Горизонтальное масштабирование
Несколько экземпляров приложения работают параллельно:
Load Balancer
/ | \
/ | \
App #1 App #2 App #3
\ | /
\ | /
Shared InfrastructureВ такой архитектуре необходимо отдельно учитывать:
- Сессии.
- Кеш.
- Файлы.
- Фоновые задачи.
- Distributed Locks.
Rate Limiting
ASP.NET Core позволяет ограничивать частоту запросов к определенным endpoint.
Это может использоваться для:
- Защиты публичных API.
- Ограничения brute-force попыток.
- Контроля ресурсоемких операций.
- Защиты отдельных бизнес-сценариев от перегрузки.
Аутентификация и авторизация
ASP.NET Core разделяет проверку личности пользователя и проверку его прав.
Аутентификация отвечает на вопрос:
Кто выполняет запрос?
Авторизация:
Разрешено ли этому пользователю выполнить действие?
Могут использоваться:
- Cookies.
- JWT.
- OAuth 2.0.
- OpenID Connect.
- Корпоративные Identity Provider.
ASP.NET Core Identity
ASP.NET Core Identity предоставляет инфраструктуру для управления пользовательскими учетными записями.
Она включает:
- Пользователей.
- Пароли.
- Роли.
- Claims.
- Tokens.
- Two-Factor Authentication.
Конкретная модель авторизации при этом может дополнительно строиться через роли, claims или policies.
Policy-Based Authorization
Для сложных правил доступа можно использовать policies.
Например:
User
+
Role
+
Claim
+
Resource
+
Business Rule
↓
Access Granted / DeniedЭто позволяет не ограничиваться проверкой одной роли и учитывать дополнительные условия доступа.
Безопасность API
Безопасность ASP.NET Core приложения включает несколько уровней.
- Аутентификацию.
- Авторизацию.
- Валидацию входных данных.
- HTTPS.
- CORS.
- Rate Limiting.
- Управление секретами.
- Контроль зависимостей.
CORS
Cross-Origin Resource Sharing определяет, какие web-origin могут обращаться к API из браузера.
CORS не является механизмом аутентификации и не должен использоваться как единственный способ защиты API.
Политика должна разрешать только необходимые origin, методы и заголовки.
CSRF
CSRF особенно актуален для приложений, в которых браузер автоматически отправляет данные аутентификации, например cookie.
Для соответствующих сценариев ASP.NET Core предоставляет механизмы antiforgery protection.
XSS
Razor по умолчанию экранирует обычный текстовый вывод, однако приложение все равно должно контролировать данные, которые вставляются в HTML или передаются в потенциально опасные контексты.
Секреты и конфигурация
Пароли, токены и connection strings не должны храниться непосредственно в исходном коде.
Для конфигурации могут использоваться:
- appsettings.json.
- Переменные окружения.
- User Secrets для локальной разработки.
- Внешние Secret Storage.
Production-секреты должны храниться отдельно от репозитория приложения.
Обработка ошибок
Ошибки API желательно возвращать в единообразном формате.
Например:
{
"type": "validation_error",
"title": "Invalid request",
"status": 400,
"traceId": "..."
}Клиент должен иметь возможность определить тип ошибки без разбора случайного текстового сообщения.
OpenAPI и Swagger
HTTP API может документироваться через спецификацию OpenAPI.
Она описывает:
- Endpoint.
- HTTP-методы.
- Параметры.
- Модели запросов.
- Модели ответов.
- Коды ошибок.
- Механизмы аутентификации.
Из OpenAPI также могут генерироваться клиентские библиотеки и интерактивная документация.
Интеграции с внешними API
При работе с внешними системами необходимо учитывать частичные отказы.
Важны:
- Timeouts.
- Cancellation.
- Retry только для подходящих операций.
- Circuit Breaker в соответствующих сценариях.
- Ограничение параллельных запросов.
- Логирование ошибок интеграции.
Повторный запрос не должен автоматически применяться к любой операции, особенно если она не является идемпотентной.
Тестирование
В ASP.NET Core проектах используются разные уровни тестирования.
Unit-тесты
Проверяют отдельные функции и бизнес-правила без запуска полной инфраструктуры приложения.
Integration-тесты
Проверяют взаимодействие компонентов, работу API, базы данных или внешней инфраструктуры.
Contract-тесты
Используются для проверки совместимости интеграций между сервисами и клиентами.
End-to-End тесты
Проверяют критический сценарий целиком:
Authenticate
↓
Create Order
↓
Process Payment
↓
Update Status
↓
Return ResultСтатический анализ
Помимо тестов могут использоваться статические проверки кода.
Они позволяют выявлять:
- Потенциальные ошибки.
- Нарушения соглашений.
- Неиспользуемый код.
- Проблемы nullable reference types.
- Некоторые классы проблем безопасности.
Логирование
ASP.NET Core предоставляет стандартные abstractions для логирования.
В production обычно предпочтительны структурированные логи.
Вместо:
Order failedполезнее иметь структурированный контекст:
OrderId
UserId
Operation
Duration
TraceId
ErrorCodeМетрики и трассировка
Наблюдаемость приложения обычно включает:
- Метрики.
- Логи.
- Distributed Tracing.
Для распределенной системы запрос может проходить через несколько компонентов:
API Gateway
↓
Order Service
↓
Payment Service
↓
DatabaseTrace позволяет связать эти операции в один пользовательский запрос.
Основные метрики
Обычно контролируются:
- Request Rate.
- Latency.
- Error Rate.
- CPU.
- Memory.
- Saturation.
- Database Latency.
- Queue Lag.
Docker
ASP.NET Core приложения могут запускаться в Docker-контейнерах.
Контейнер обычно содержит:
Application
+
.NET Runtime
+
Required DependenciesЭто позволяет использовать одинаковую модель запуска на development, test и production окружениях.
Kubernetes
Для систем, которым требуется оркестрация большого количества контейнеров, может использоваться Kubernetes.
Он предоставляет механизмы:
- Deployment.
- Service Discovery.
- Health Checks.
- Scaling.
- Rolling Update.
- Configuration Management.
Kubernetes добавляет существенную инфраструктурную сложность и не требуется каждому ASP.NET Core приложению.
Health Checks
Приложение может публиковать endpoint для проверки своего состояния.
При этом полезно различать:
- Liveness - способен ли процесс продолжать работу.
- Readiness - способен ли экземпляр принимать пользовательский трафик.
Эти проверки могут использоваться балансировщиками и контейнерными платформами.
CI/CD
Типовой pipeline может выглядеть так:
Commit
↓
Restore
↓
Build
↓
Static Analysis
↓
Tests
↓
Package
↓
Deploy
↓
Migrations
↓
VerificationВ зависимости от проекта дополнительно применяются:
- Staging-окружения.
- Rolling Deployment.
- Blue-Green Deployment.
- Canary Deployment.
- Feature Flags.
Миграции и релизы
Изменения приложения часто сопровождаются изменением схемы базы данных.
При этом новая версия приложения и новая схема должны оставаться совместимыми во время rollout.
Для крупных систем изменения базы могут разделяться на несколько этапов:
Добавить новую структуру
↓
Развернуть совместимый код
↓
Перенести данные
↓
Переключить использование
↓
Удалить старую структуруЧек-лист перед production
- Настроена валидация входных данных.
- Ограничен размер входящих запросов там, где это необходимо.
- Реализована пагинация для больших выборок.
- Настроены timeouts для внешних сервисов.
- Определена политика retry.
- Проверены authentication и authorization.
- Секреты вынесены из репозитория.
- Настроена обработка ошибок.
- Добавлен traceId или другой correlation identifier.
- Настроены структурированные логи.
- Настроены метрики и алерты.
- Проверены health checks.
- Выполнены тесты критических сценариев.
- Проверен процесс deployment и rollback.
Когда ASP.NET Core подходит для проекта
ASP.NET Core может использоваться как для небольшого API, так и для крупной корпоративной системы.
Особенно естественно он вписывается в проекты, где:
- Используется экосистема .NET.
- Требуется сложная серверная бизнес-логика.
- Есть большое количество интеграций.
- Нужна строгая модель аутентификации и авторизации.
- Требуется горизонтальное масштабирование.
- Система рассчитана на длительное развитие.
При этом наличие большого количества возможностей framework не означает, что все они должны использоваться одновременно.
Архитектура ASP.NET Core приложения должна соответствовать сложности самой задачи: для небольшого API может быть достаточно Minimal APIs и нескольких сервисов, а сложная корпоративная система может потребовать модульного разделения, очередей, распределенного кеша, нескольких баз данных и отдельной инфраструктуры наблюдаемости.