Controller — [ApiController], [Route], ControllerBase

~20 daq · .NET Backend · Web API — Controller va Routing

Muammodan boshlaylik

Do'kon API sida o'nlab endpoint: mahsulotlar, kategoriyalar, buyurtmalar, foydalanuvchilar. Hammasini Program.cs da app.MapGet(...) bilan yozsangiz — yuzlab qatorli fayl. Kerak: bog'liq endpoint larni guruhlash, umumiy sozlamalarni (URL prefiksi, avtorizatsiya) bir joyda berish.


Controller nima?

Controller — bitta resurs (mahsulot, buyurtma) bilan bog'liq HTTP endpoint lar (action lar) to'plangan klass:

using Microsoft.AspNetCore.Mvc;

namespace DokonApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class MahsulotlarController(IMahsulotService service) : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<List<MahsulotDto>>> Hammasi(CancellationToken ct) =>
        Ok(await service.HammasiAsync(ct));

    [HttpGet("{id:int}")]
    public async Task<ActionResult<MahsulotDto>> Ol(int id, CancellationToken ct)
    {
        var m = await service.OlAsync(id, ct);
        return m is null ? NotFound() : Ok(m);
    }
}

Qoidalar:

  • Klass nomi ...Controller bilan tugaydi
  • ControllerBase dan meros (API uchun; Controller — MVC View lari bilan)
  • public metodlar — action lar
  • Bog'liqliklar — konstruktor orqali (38-dars)

Program.cs da:

builder.Services.AddControllers();
// ...
app.MapControllers();

Hayotiy o'xshatma

Bank filiallaridagi bo'limlar. "Kreditlar" bo'limi (controller) — kredit bilan bog'liq barcha xizmatlar: ariza berish, holatini bilish, to'lash (action lar). Eshik ustidagi yozuv ([Route]) qaysi bo'lim ekanini ko'rsatadi. Har bir bo'lim o'z ishini biladi va boshqalariga aralashmaydi.


[ApiController] — nima beradi

Imkoniyat Ma'nosi
Avtomatik 400 Model validatsiyasidan o'tmasa — action chaqirilmaydi, 400 + xatolar (46-dars)
Manba taxmini Murakkab tur — [FromBody], oddiy — route/query dan
ProblemDetails Xatolar standart formatda (RFC 7807, 65-dars)
Attribute routing majburiy Har bir controller da [Route] bo'lishi kerak

Barcha API controller larga qo'ying.


[Route] — URL

[Route("api/[controller]")]          // api/mahsulotlar
[Route("api/v1/mahsulotlar")]        // aniq yozilgan
[Route("api/[controller]/[action]")] // api/mahsulotlar/qidirish — metod nomi bilan (kam ishlatiladi)

[controller] — klass nomidan Controller qismi olib tashlangan (MahsulotlarController → Mahsulotlar; URL lar katta-kichik harfga sezgir emas).

Action darajasidagi route — klassnikiga qo'shiladi:

[Route("api/mahsulotlar")]
public class MahsulotlarController : ControllerBase
{
    [HttpGet]                       // GET api/mahsulotlar
    [HttpGet("{id:int}")]           // GET api/mahsulotlar/5
    [HttpGet("qidiruv")]            // GET api/mahsulotlar/qidiruv?q=...
    [HttpGet("{id:int}/sharhlar")]  // GET api/mahsulotlar/5/sharhlar
    [HttpGet("/api/aksiyalar")]     // "/" bilan — klass prefiksini e'tiborsiz qoldiradi
}

Route constraint lar

[HttpGet("{id:int}")]               // faqat butun son
[HttpGet("{slug:alpha}")]           // faqat harflar
[HttpGet("{id:guid}")]
[HttpGet("{sana:datetime}")]
[HttpGet("{sahifa:int:min(1)}")]

/api/mahsulotlar/abc — {id:int} ga mos kelmaydi → 404, action ga noto'g'ri qiymat yetib bormaydi.


ControllerBase yordamchilari

return Ok(natija);                         // 200
return Created(
quot;/api/mahsulotlar/{m.Id}", m); return CreatedAtAction(nameof(Ol), new { id = m.Id }, m); // 201 + Location return NoContent(); // 204 return BadRequest("Noto'g'ri so'rov"); // 400 return Unauthorized(); // 401 return Forbid(); // 403 return NotFound(); // 404 return Conflict("Bu email band"); // 409 return Problem("Xato", statusCode: 500); // ProblemDetails

Status kodlar — 48-dars.

User.Identity?.Name       // joriy foydalanuvchi (60-dars)
HttpContext               // so'rov konteksti
Request.Headers           // sarlavhalar

Yupqa controller

[!TIP] Controller — yupqa bo'lsin: so'rovni qabul qilish, servisni chaqirish, HTTP javobini qaytarish. Biznes mantiq (narx hisoblash, qoidalar), baza so'rovlari — servislarda. Shunda mantiqni testlash va boshqa joydan (fon vazifasi, boshqa endpoint) chaqirish oson.

// ❌ hamma narsa controller da
[HttpPost]
public async Task<IActionResult> Yarat(BuyurtmaDto dto)
{
    var mahsulot = await _db.Mahsulotlar.FindAsync(dto.MahsulotId);
    if (mahsulot.Qoldiq < dto.Soni) return BadRequest();
    mahsulot.Qoldiq -= dto.Soni;
    var summa = mahsulot.Narx * dto.Soni * (dto.Vip ? 0.9m : 1m);
    // ... 40 qator
}

// ✅
[HttpPost]
public async Task<IActionResult> Yarat(BuyurtmaDto dto, CancellationToken ct)
{
    var natija = await _buyurtmaService.YaratAsync(dto, ct);
    return CreatedAtAction(nameof(Ol), new { id = natija.Id }, natija);
}

Umumiy sozlamalar — atributlar va ota klass

[ApiController]
[Route("api/[controller]")]
[Authorize]                          // barcha action larga
[Produces("application/json")]
public abstract class ApiControllerBase : ControllerBase { }

public class BuyurtmalarController : ApiControllerBase
{
    [AllowAnonymous]                 // istisno
    [HttpGet("holat/{kod}")]
    public IActionResult Holat(string kod) => Ok();
}

Tez-tez uchraydigan xatolar

[Route] yo'q:

InvalidOperationException: Action '...' does not have an attribute route. Action methods on controllers annotated with ApiControllerAttribute must be attribute routed.

Ikki action bir xil route va metod:

AmbiguousMatchException: The request matched multiple endpoints.

public yordamchi metod — u ham action deb hisoblanadi; yordamchilarni private qiling yoki [NonAction].


Xulosa

Controller — bitta resurs uchun endpoint lar guruhi: ...Controller nomi, ControllerBase dan meros, public metodlar — action lar. [ApiController] — avtomatik validatsiya (400), manba taxmini, ProblemDetails.

[Route("api/[controller]")] + action route lari ([HttpGet("{id:int}")]) qo'shiladi; constraint lar (:int, :guid) noto'g'ri qiymatni o'tkazmaydi. Yordamchilar: Ok, CreatedAtAction, NoContent, NotFound, BadRequest. Controller yupqa — mantiq servislarda; umumiy sozlamalar — atributlar va ota klass.


Keyingi dars

42-dars: HTTP GET va POST — [HttpGet], [HttpPost], IActionResult