KREIRANJE KONTROLERA U ASP.NET WEB API APLIKACIJI
Za čitanje podataka iz baze(GET metoda), upisivanje podataka o novom proizvodu(POST), ažuriranje postojećeg proizvoda (PUT i PATCH) kao i brisanje proizvoda iz baze, zadužene su metode koje treba da se kreiraju u kontroler klasi. Kontroler treba da se kreira u posebnom folderu "Controllers". Kreirajmo sada kontroler pod nazivom ProductController:
Kontroler je klasa koja mora biti izvedena iz klase ControllerBase ili njome nasleđene klase Controller. Takođe je bitno da se postavi atribut [ApiController] iznad konstruktora kao i atribut [Route("[controller]")]. Prvi atribut govori o tome da je u pitanju api kontroler, a drugi je ruta gde se "[controller]" zamenjuje sa prefiksom u nazivu kontrolera. U ovom slučaju to je reč products, s obzirom da je naziv kontrolera ProductsController. Kada određena klijent aplikacija zatraži uslugu od api web servisa, a da bi se pozvao ovaj kontroler(ProductController) u polju za URL adrese treba ukucati:
http://naziv_servera:port/products
Ako je aplikacija na lokalnom računaru i ako je server podignut na portu 5001, poziv će biti:
https://localhost:5001/products
U ovo slučaju je upućen GET zahtev koji će iz baze vratiti listu svih proizvoda iz baze, kao što se može videti na sledećoj slici:
S obzirom da je u Startup klasi kreirana konekcija ka bazi koja je dodata u kolekciju dostupnih servisa, ona je preko konstruktora prosleđena kontroleru i dodata polju klase _conn, što je zapravo objekat tipa IDbConnection. Pogledajte u nastavku kako treba implementirati: GET, POST, DELETE, PUT i PATCH metode unutar kontrolera.
Get zahtevi unutar API kontrolera
Prikazana metoda pod nazivom GetAllProducts je asinhrona metoda koja se poziva od strane nekog klijenta, web pretraživača, druge web aplikacije, mobilne aplikacije ili sl. i koja iz baze podataka izvlači listu proizvoda i kao povratnu vrednost vraća IEnumerable objekat, što je zapravo niz objekata klase Product. Kod asinhronih poziva, a na to nas upućuju reči async i await u kombinaciji, zadaci mogu da se izvršavaju paralelno i na taj način se ubrzava proces. Više o asinhronim metodama pročitajte na sledećoj web lokaciji: docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
Unutar metode se kreira SQL querry koji iz tabele Product treba da izvuče i vrati sve zapise u kojima se nalaze podaci o proizvodima. Preko objekta konekcije se poziva metoda QuerryAsync koja kao parametar koristi prethodno kreirani querry u obliku stringa. Metoda vraća Task i to je asinhrona metoda koja treba na kraju da vrati listu proizvoda IEnumerable<Product>. Metoda asList pretvara skup objekata u listu List<Product> i ta lista će biti vraćena klijentu, ali tek pošto se svi podaci prikupe.
Get zahtev koji vraća određeni proizvod sa zahtevanim id-om
Da bi se dobio jedan, određeni proizvod iz baze npr sa id=15, u URL polju za adrese treba otkucati:
https://localhost:5001/products/15
To je takođe get zahtev ali sa malo drugačijom rutom koja zahteva i id proizvoda, pa će metoda izgledati:
Metoda GetProduct dobija id kao parametar i to je iskorišćeno za formiranje querry stringa pomoću koga će se proizvod izvući iz baze. Ovde se sada pomenuti querry prosleđuje asinhronoj metodi QuerySingleOrDefaultAsync objekta konekcije _conn i koja asinhrono vraća određeni proizvod iz baze. I u ovom slučaju je povratna vrednost Task sa podtipom ActionResult<Product>
Post zahtev za unos novog podatka u bazu
Post zahtev može biti upućen iz druge aplikacije sa istog ili različitog uređaja, istog ili različitog domena i ako posmatramo tekući primer zahtev bi bio:
https://localhost:5001/products/Create
Ovo je zapravo poziv POST metodi da se izvrši i ona treba da bude definisana na sledeći način:
[HttpPost("Create")] atribut je potreban da bi metoda PostAsync odgovorila na POST zahtev, a "Create" je deo URL adrese koji treba upisati posle poziva servera i prefiksa naziva kontrolera.
Metoda prihvata objekat klase Product za parametar i iz njega će biti izvučene vrednosti polja koje će se umetnuti unutar stringa querry, a koji predstavlja upit za unos novog reda u tabelu unutar baze podataka. Pomoću ovog upita i _conn objekta(SqlConnection) kreira se Sql komanda(SqlCommand), gde su pomenuti objekti prosleđeni kao parametri konstruktora SqlCommand klase.
Sql komanda će se izvršiti asinhrono izvršenjem metode ExecuteAsync koja će uneti podatke o proizvodu u bazu i vratiti Task objekat koji u sebi čuva podatak o broju ubačenih redova u bazu.
Metoda prihvata objekat klase Product za parametar i iz njega će biti izvučene vrednosti polja koje će se umetnuti unutar stringa querry, a koji predstavlja upit za unos novog reda u tabelu unutar baze podataka. Pomoću ovog upita i _conn objekta(SqlConnection) kreira se Sql komanda(SqlCommand), gde su pomenuti objekti prosleđeni kao parametri konstruktora SqlCommand klase.
Sql komanda će se izvršiti asinhrono izvršenjem metode ExecuteAsync koja će uneti podatke o proizvodu u bazu i vratiti Task objekat koji u sebi čuva podatak o broju ubačenih redova u bazu.
Izmena podataka o određenom proizvodu
Da bi se ažurirali podaci o proizvodu koji ima neki svoj identifikacioni broj (id) treba da se uputi PUT poziv čiji URL treba da bude:
https://localhost:5001/products/Update/5
Tada se poziva metoda koja ima atribut [HttpPut] i kao parametar prihvata id proizvoda kao i podatke o novom proizvodu što se može videti na sledećos slici:
Kao i kod prethodnih metoda i ova se izvršava asinhrono i kao povratnu vrednost vraća Task<ActionResult> gde ActionResult omogućava vraćanje različitih statusa u zavisnosti da li su podaci uspešno ažurirani ili ne. Posle provere broja ažuriranih redova koji su vraćeni, ako je ova vrednost nula poziva se NotFound(), nasleđena metoda iz klase BaseController koja proizvodi status Status404NotFound u odgovoru(response). U suprotnom, ako su redovi u bazi uspešno ažurirani pozvaće se metooda NoContent() koja vraća status Status204NoContent za odgovor.
Sql komanda koja se formira koristeći poznati sql querry za ažuriranje(update) i objekat konekcije _conn , i izvršava kao i kod POST metode pozivom ExecuteAsync metode koja vraća kao povratnu vrednost broj ažuriranih redova u bazi.
Sql komanda koja se formira koristeći poznati sql querry za ažuriranje(update) i objekat konekcije _conn , i izvršava kao i kod POST metode pozivom ExecuteAsync metode koja vraća kao povratnu vrednost broj ažuriranih redova u bazi.
Neka je npr. pokrenuta druga aplikacija na istom računaru, web aplikacija koja treba da prikaže proizvode ili jedan poizvod, kreira nov, menja ili briše postojeći, tako što komunicira preko web API servera kao posrednikom za rad sa bazom podataka. Primer izmene proizvoda može se videti na sledećoj slici:
-Vidi se da je aplikacija pokrenuta isto na localhostu kao i web API, ali na različitom portu, u ovom slučaju na portu 5021, za razliku od web API aplikacije koja je na portu 5001.
Ako se npr za količinu koja je bila 1, promeni vrednost na npr. 3 i klikne na edit dugme kreira se PUT zahtev web API aplikaciji gde je url zahtev:
Ako se npr za količinu koja je bila 1, promeni vrednost na npr. 3 i klikne na edit dugme kreira se PUT zahtev web API aplikaciji gde je url zahtev:
https://localhost:5001/products/Update/1013
Ovim je upućen zahtev za izmenu proizvoda sa id = 1013, što znači da će biti pozvana PUT metoda web API-ja što se može videti na sledećoj slici:
Na slici je prikazana metoda koja se izvršava pomoću Debbuger-a u VS Code alatu. Može se primetiti da podaci o proizvodu prosleđeni preko parametra product, odgovaraju onim, koje su se videli na edit formi u okviru web aplikacije koja je uputila zahtev ka web API serveru (localhost:5021).
Posle ažuriranja početna strana ove aplikacije izgleda kao na sledećoj slici:
Posle ažuriranja početna strana ove aplikacije izgleda kao na sledećoj slici:
Može se videti da je vrednost Quantity osobine promenjena na 3.
Brisanje određenog proizvoda iz baze
Da bi se obrisao jedan proizvod sa određenim id-om potrebno je poslati DELETE zahtev:
https://localhost:5001/products/Delete/1013
Pozvaće se metoda čiji atribut [HttpDelete] govori o tome da je u pitanju metoda koja odgovara na DELETE zahtev. Metoda je prikazana na sledećoj slici:
CRUD operacije primeri
1.Create (POST)
[HttpPost]
public IActionResult Create([FromBody] Product product)
{
if (ModelState.IsValid)
{
_context.Products.Add(product);
_context.SaveChanges();
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
return BadRequest(ModelState);
}
public IActionResult Create([FromBody] Product product)
{
if (ModelState.IsValid)
{
_context.Products.Add(product);
_context.SaveChanges();
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
return BadRequest(ModelState);
}
Ova metoda kreira novi proizvod. Ako su podaci ispravni, dodaje proizvod u bazu podataka i vraća 201 Created status.
2. Read (GET)
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
return Ok(product);
}
public IActionResult GetById(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
return Ok(product);
}
Ova metoda kreira novi proizvod. Ako su podaci ispravni, dodaje proizvod u bazu podataka i vraća 201 Created status.
3. Update (PUT)
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody] Product updatedProduct)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
product.Name = updatedProduct.Name;
product.Price = updatedProduct.Price;
_context.SaveChanges();
return NoContent();
}
public IActionResult Update(int id, [FromBody] Product updatedProduct)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
product.Name = updatedProduct.Name;
product.Price = updatedProduct.Price;
_context.SaveChanges();
return NoContent();
}
Ažurira postojeći proizvod. Ako ne postoji, vraća 404 Not Found. U suprotnom, vrši ažuriranje i vraća 204 No Content.
4. Delete (DELETE)
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
_context.Products.Remove(product);
_context.SaveChanges();
return NoContent();
}
public IActionResult Delete(int id)
{
var product = _context.Products.Find(id);
if (product == null)
return NotFound();
_context.Products.Remove(product);
_context.SaveChanges();
return NoContent();
}
Briše proizvod prema ID-u. Ako nije pronađen, vraća 404 Not Found, a ako je uspešno obrisan, vraća 204 No Content.
Validacija modela u ASP.NET Core koristeći atribute kao što su [Required], [StringLength], i druge:
Primer Modela sa Validacijom:
public class Product
{
[Required(ErrorMessage = "Naziv proizvoda je obavezan.")]
[StringLength(100, ErrorMessage = "Naziv ne može biti duži od 100 karaktera.")]
public string Name { get; set; }
[Range(0.01, 10000, ErrorMessage = "Cena mora biti između 0.01 i 10,000.")]
public decimal Price { get; set; }
}
{
[Required(ErrorMessage = "Naziv proizvoda je obavezan.")]
[StringLength(100, ErrorMessage = "Naziv ne može biti duži od 100 karaktera.")]
public string Name { get; set; }
[Range(0.01, 10000, ErrorMessage = "Cena mora biti između 0.01 i 10,000.")]
public decimal Price { get; set; }
}
- [Required]: Ovaj atribut osigurava da polje ne bude prazno.
- [StringLength]: Ograničava dužinu stringa.
- [Range]: Ograničava vrednost brojeva u zadatom opsegu.
Ova validacija automatski se primenjuje pri unosu podataka u kontroler, a ASP.NET Core generiše odgovarajuće poruke o grešci ako uslovi nisu ispunjeni.
Autentifikacija i autorizacija u Web API-u
U ASP.NET Core, jednostavna autentifikacija i autorizacija može se postići korišćenjem atributa [Authorize]. Na primer:
[Authorize]
[HttpGet("{id}")]
public IActionResult GetSecureData(int id)
{
var data = _context.Data.Find(id);
if (data == null)
return NotFound();
return Ok(data);
}
[HttpGet("{id}")]
public IActionResult GetSecureData(int id)
{
var data = _context.Data.Find(id);
if (data == null)
return NotFound();
return Ok(data);
}
Ovaj atribut osigurava da samo autentifikovani korisnici mogu pristupiti metodi. Takođe možete koristiti [AllowAnonymous] za izuzimanje određenih akcija iz autentifikacije.
Vraćanje HTTP statusnih kodova
HTTP statusni kodovi pomažu u komunikaciji između servera i klijenta. U ASP.NET Core Web API-ju, lako se koriste u akcijama kontrolera. Primeri:
- 201 Created: Kada se resurs uspešno kreira, koristi se CreatedAtAction:
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
- 404 Not Found: Kada resurs nije pronađen, koristi se NotFound():
return NotFound();
- 204 No Content: Kada se operacija uspešno izvrši bez sadržaja za vraćanje:
return NoContent();
Sledeće
Komunikacija Javascript web aplikacije sa API serverom >| |