Ответ
Да, неоднократно. Типичный стек для нового проекта включает:
- Backend: ASP.NET Core Web API для RESTful-сервисов или MVC для серверного рендеринга.
- Аутентификация/Авторизация: JWT-токены или Identity Server.
- Доступ к данным: Entity Framework Core (Code-First или Database-First) с репозиториями и Unit of Work.
- Документация API: Интеграция Swagger (Swashbuckle) с XML-комментариями.
- Фронтенд: Для SPA — отдельное приложение на React/Angular/Vue, взаимодействующее с API. Для более простых случаев — Razor Pages или Blazor Server/WASM.
- Инфраструктура: Docker-контейнеризация, развертывание в облаке (Azure/AWS), настройка CI/CD пайплайнов (GitHub Actions, GitLab CI).
Пример контроллера для Web API:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<ProductDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAll()
{
var products = await _productService.GetAllAsync();
return Ok(products);
}
[HttpPost]
[ProducesResponseType(typeof(ProductDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create([FromBody] CreateProductRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var createdProduct = await _productService.CreateAsync(request);
return CreatedAtAction(nameof(GetById), new { id = createdProduct.Id }, createdProduct);
}
}
Ключевые практики: разделение ответственности (Controllers -> Services -> Repositories), использование DTO, валидация запросов, корректные HTTP-статусы и обработка ошибок глобально через middleware.
Ответ 18+ 🔞
А, ну ты спрашиваешь, что обычно берут для нового проекта? Ну, блядь, классика жанра, как говорится, в рот меня чих-пых. Каждый раз одно и то же, но работает же, чёрт возьми.
Смотри, обычно это выглядит как какой-то овердохуища стандартный набор:
- Бэкенд: Ну, ASP.NET Core Web API, если делаем эти ваши REST-сервисы. А если проект — какая-нибудь древняя контора, где всё должно быть просто и сразу, то MVC для серверного рендеринга, чтобы не заморачиваться.
- Вход-выход: JWT-токены, чтобы не хранить сессии, либо Identity Server, если всё совсем серьёзно и хочется поумничать.
- База данных: Entity Framework Core, само собой. Code-First, если мы боги и проектируем с нуля, или Database-First, если нам досталась какая-то ебанько-наследие от предков. И конечно, репозитории с Unit of Work, чтобы все архитектурные гуру в команде не сосали с нас.
- Документация для API: Swagger (Swashbuckle), куда же без него. Только не забудь XML-комментарии навесить, а то будет пустая страница, и фронтендеры тебе мозг вынесут.
- Фронтенд: Если делаем модное SPA — тогда отдельное приложение на React, Angular или Vue, которое будет дергать наш API. Если проект попроще — Razor Pages или Blazor, чтобы не бегать между двумя студиями.
- Всякая инфраструктурная хуйня: Docker, чтобы упаковать всё это добро, облако (Azure обычно), и CI/CD пайплайны (GitHub Actions, GitLab CI), чтобы автоматически деплоить после каждого коммита и ломать продакшн в три часа ночи.
Вот, смотри, как обычно выглядит контроллер, чтоб ты понимал масштаб трагедии:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
[ProducesResponseType(typeof(IEnumerable<ProductDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAll()
{
var products = await _productService.GetAllAsync();
return Ok(products);
}
[HttpPost]
[ProducesResponseType(typeof(ProductDto), StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create([FromBody] CreateProductRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
var createdProduct = await _productService.CreateAsync(request);
return CreatedAtAction(nameof(GetById), new { id = createdProduct.Id }, createdProduct);
}
}
А главное, что все делают вид, что следуют каким-то высшим практикам: разделение ответственности (контроллеры -> сервисы -> репозитории), использование DTO, валидация, правильные HTTP-статусы. И конечно, глобальная обработка ошибок через middleware, чтобы не засирать каждый метод одинаковыми try-catch блоками. Выглядит умно, а по факту — стандартная обвязка, без которой сейчас ни один проект не обходится, ёпта.