W poprzednim wpisie przedstawiłem jak można sobie stworzyć model w aplikacji ASP.NET MVC 2 dla przykładowej aplikacji, którą jest księga gości. W tym wpisie chciałbym opisać jak do aplikacji dodać kontroler z akcjami dla naszej przykładowej aplikacji.
Ale za nim przejdę do opisania jak to zrobić, pierw kilka słów na temat kontrolerów i akcji w ASP.NET MVC 2. Kontroler to klas, która dziedziczy po abstrakcyjnej klasie System.Web.Mvc.Controller. Natomiast każda publiczna metoda (zwracająca tym ActionResult) w klasie kontrolera jest akcją, jaka może zostać wykonana w ramach jakiegoś żądania użytkownika.
Akcje mogą być przypisane do określonego typu żądania protokołu http. I tak jedna akcja np. Create może zostać przypisana do żądania typu get (domyślny typ żądania), który spowoduje wyświetlenia formularza dodania nowego wpisu do księgi gości. Natomiast inną akcję o nazwie Create (i innej sygnaturze niż poprzednia) możemy wykonywać, gdy do serwera przyjdzie żądania typu post (wtedy, gdy np. użytkownik przesyła formularz dodania nowego wpisu w księdze gości z wypełnionym polami). Dzięki temu ASP.NET MVC jest automatycznie w stanie rozpoznać typ żądania i odpowiednio uruchomić właściwą akcję.
Tak jak napisałem domyślnym typem żądania jest żądanie get i aby obsłużyć taki typ żądania nic nie musimy robić. Natomiast, gdy chcemy aby akcja wykonała się w ramach innego typu żądania (np. post) musimy akcję oznaczyć odpowiednim atrybutem. Dostępne atrybuty to:
- HttpDelete
- HttpGet
- HttpPost
- HttpPut
które odpowiadają odpowiednim żądaniom protokołu http.
Tak jak wspomniałem w jednym z wcześniejszych wpisów, w ASP.NET MVC wykorzystuje się konwencje nazewnicze. I tak każda klasa kontrolera powinna kończyć się słowem Controller. Na szczęście Visual Studio bardzo nam w tym względzie pomaga i sam to podpowiada.
A więc jak stworzyć nowy kontroler? Nic trudnego, klikamy prawym klawiszem mysz na folder Controllers i wybieramy Add-> Controller. Pojawi się okienko, które widać poniżej:

W powyższym oknie możemy nadać nazwę kontrolerowi oraz zaznaczyć jednego checkboxa. Jak zaznaczymy go, to Visual Studio automatycznie wygeneruje nam akcje dla takich scenariuszy jak: dodanie nowego obiektu, edycja, usunięcie oraz wyświetlenie szczegółów. Jest to o tyle przydatne, gdy tworzymy akcje dla operacji typu CRUD to Visual Studio zaoszczędzi nam sporo pracy.
Po kliknięciu w przycisk Add, możemy cieszyć się naszym nowym kontrolerem.
Teraz pozostaje nam oprogramowanie poszczególnych akcji kontrolera.
Zacznijmy od akcji Index, która spowoduje wyświetlenie listę wszystkich wpisów w księdze gości. Kod akcji Index może wyglądać między innymi tak:
1: public ActionResult Index()
2: {
3: DB db = new DB();
4: return View(db.GuestBooks);
5: }
W linijce 3 tworzymy nowy obiekt klasy DB, za pomocą której będziemy wyciągać dane z bazy danych. Natomiast w kolejnej linijce jest wywoływana metoda View, który utworzy odpowiedni widok (o czym będzie w kolejnym artykule) i przekazana do niego zostanie kolekcja obiektów klasy GuestBook, w której będą wszystkie wpisy z księgi gości.
Kolejną akcją jest akcje Details, która wyświetla szczegóły dla dane wpisu (w przypadku księgi gości nie ma ona jakiegoś większego sensu, ale zwarłem go tak dla kompletnego opisu wszystkich akcji wygenerowanych przez Visual Studio).
1: public ActionResult Details(int id)
2: {
3: DB db = new DB();
4:
5: var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
6:
7: if (guestBook == null)
8: {
9: RedirectToAction("Index");
10: }
11:
12: return View(guestBook);
13: }
Co pierwsze rzuca się w oczy to, że akcja Details przyjmuje parametr typu int, który jest id wpisu, które trzeba wyświetlić szczegóły. ASP.NET MVC automatycznie zamapuje parametry żądania get na argument akcji (jak to wszystko działa zostanie opisane w późniejszym artykule).
W ciele akcji Details podobnie jak w akcji Index tworzony jest obiekt DB. Następnie z kolekcji wszystkich wpisów jest wybierany wpis o danym id (wybieranie odbywa się za pomocą metody Where i wyrażenia lambda, które mówi, że przekazany argument do metody należy porównywać z właściwością Id obiektu GuestBook). Wywołanie metody FirstOrDefault spowoduje zwrócenie do zmiennej guestBook obiektu GuestBook o danym Id, o ile znajduje się w bazie. W przeciwnym wypadku, gdy nie ma wpisu o danym id zwrócony zostanie null.
Następie w ifie sprawdzany, czy w bazie istnieje wpis o danym id (przez porównanie zmiennej guestBook z nullem). Gdy wpisu nie ma za pomocą metody RedirectToAction przechodzimy do akcji Index. Natomiast, gdy wpis o id jest w bazie tworzymy odpowiedni widok i przekazujemy obiekt guestBook do niego.
Teraz przejdźmy do dwóch akcji odpowiedzialnych za dodanie nowego wpisu w księdze gości. Czemu dwóch? Tak jak napisałem na początku ASP.NET MVC rozpoznaje typ żądania http jaki przychodzi do serwera i jest na jego podstawie wykonać różne akcje. Tutaj można to sobie fajnie wykorzystać. Jedna akcja Create (która będzie wykonywała się podczas żądania get) spowoduje wyświetlenie formularza dodania nowego wpisu do księgi gości. Natomiast druga akcja Create (przypisana do żądania post oraz przyjmująca parametr) zostanie wywołana, gdy do serwera przyjdzie żądanie post z wypełnionym formularzem przez użytkownika.
Kod obu akcji widać poniżej:
1: public ActionResult Create()
2: {
3: return View();
4: }
5:
6: [HttpPost]
7: public ActionResult Create(GuestBook guestBook)
8: {
9: if (ModelState.IsValid)
10: {
11: try
12: {
13: DB db = new DB();
14: guestBook.AddDate = DateTime.Now;
15: db.GuestBooks.InsertOnSubmit(guestBook);
16: db.SubmitChanges();
17:
18: return RedirectToAction("Index");
19: }
20: catch
21: {
22: return View("Error");
23: }
24: }
25: else
26: {
27: return View(guestBook);
28: }
29: }
Pierwsza akcja Create jest bardzo prosta. Po prostu wyświetla odpowiedni widok.
Druga jest już dużo bardziej skomplikowana. Pierwszą rzeczą jaka rzuca się w oczy to dodany atrybut HttpPost przed akcją. Co jak już wcześniej pisałem spowoduje przypisanie akcji to żądania post.
Uważny czytelnik, który na bieżąco wykonuje opisywane czynności w Visual Studio może zauważyć, że argument akcji Create w listingu powyżej jest inny, niż w tym co wygenerowało Visual Studio. Visual Studio wygenerowało taki kod:
1: public ActionResult Create(FormCollection collection)
Gdzie przekazanym argument to obiekt klasy FormCollecion, który reprezentuje wszystkie wartości przekazanego formularza. Obiekt tej jest zwykłym słownikiem i możemy się do niego odwoływać za pomocą kluczy, którymi są nazwy poszczególnych pól formularza, np:
1: string nick = collection["Nick"];
Dla nas programistów c# takie podejście jest fu. My lubimy silną kontrolę typów, a nie pracę ze słownikiem i typem object. Dodatkowo z takim podejściem nie będziemy mogli skorzystać sobie z fajnej walidacji (o której będzie w którymś z kolejnych artykułów).
Na szczęście ASP.NET MVC 2 jest fajne i potrafi na podstawie nazw pól formularza zamapować nam formularz z właściwościami jakiegoś obiektu, w naszym przypadku obiektu klasy GuestBook. Dzięki czemu w akcji Create wygenerowanej przez Visual Studio możemy sobie zamienić FormCollection collection na GuestBook guestBook.
Główny if może się wydać nam trochę dziwny (o nim będzie jeszcze trochę w dalszym ciągu serii). Ale szybko tłumacząc to sprawdza on, czy ASP.NET MVC dobrze zamapowało dane z formularza do obiektu klasy GuestBook. Jeśli nie to zostanie wyświetlony formularz dodania nowego wpisu do księgi gości z już wypełnionymi danymi, które znajdowały się wcześniej w formularzu. Do tego jeszcze wrócę dlaczego tak, gdy będę opisywał walidację.
Gdy ASP.NET dobrze zamapowało dane z formularza do obiektu GuestBook, następuje dodanie go do bazy danych. Wcześniej przed samym dodaniem następuje ustawienie dany dodania wpisu na aktualną datę. Po zapisaniu wpisu w bazie następuje przekierowanie do akcji Index.
Jeśli podczas dodania wpisu do bazy danych nastąpił jakiś błąd i został wyrzucony wyjątek, zostanie on złapany przez blok try-catch i użytkownikowi zostanie wyświetlony widok Error z informacją o błędzie.
Kolejnymi akcjami naszego kontrolera, będą akcje odpowiedzialne za edycję wpisu w księdze gości. Tutaj nie będę opisywał jak zabezpieczyć wykonanie akcji, tak aby mogli je wykonać użytkownicy o roli administratora. Opiszę to w jednym z późniejszych artykułów w serii.
Podobnie jak w przypadku dodawania nowego wpisu, tak i przy edycji wpisów będziemy mieli dwie akcje Edit, przypisane do różnych żądań http – get i post. Kod akcji znajduje się poniżej:
1: public ActionResult Edit(int id)
2: {
3: DB db = new DB();
4:
5: var guestBook = db.GuestBooks.Where(x => x.ID == id).FirstOrDefault();
6:
7: if (guestBook == null)
8: {
9: return RedirectToAction("Index");
10: }
11:
12: return View(guestBook);
13: }
14:
15: [HttpPost]
16: public ActionResult Edit(int id, FormCollection collection)
17: {
18: try
19: {
20: DB db = new DB();
21: var guestBook = db.GuestBooks.Where(x => x.ID == id).FirstOrDefault();
22:
23: if (guestBook == null)
24: {
25: return RedirectToAction("Index");
26: }
27:
28: UpdateModel(guestBook, collection.ToValueProvider());
29: db.SubmitChanges();
30:
31: return RedirectToAction("Index");
32: }
33: catch
34: {
35: return View("Error");
36: }
37: }
Pierwsza akcja Edit jest identyczna jak akcja Details, dlatego nie będę jej opisywać. Natomiast początek drugiej akcji Edit jest bardzo podobny do cała akcji Edit dla żądania get. Różnica zaczyna się, gdy już wyciągniemy obiekt z bazy danych, którego ma nastąpić edycja.
Jak można zauważyć druga akcje Edit przyjmuje podobnie jak akcje Create obiekt FormCollection. Niestety nie możemy sobie postąpić podobnie jak w akcji Create i zdać na automatyczne mapowanie ASP.NET MVC na poziomie wywoływania akcji. Spowodowane jest to tym, że nie moglibyśmy zmienić w bazie danych wpisu na podstawie tak utworzonego obiektu GuestBook, ponieważ nie jest on przypisany do żadnego obiektu DB. Na szczęście twórcy ASP.NET MVC ułatwili nam zadanie i do frameworka dodali metodę UpdateModel, która na podstawie obiektu wyciągniętego z bazy (guestBook) oraz danych z formularza automatycznie zaktualizuje obiekt naszego modelu. Następnie wystarczy tylko zapisać zmiany w bazie i przekierować użytkownika na stronę z wszystkimi wpisami w księdze.
W przypadku wystąpienia jakiegoś błędu podobnie jak w akcji Create, zostanie wyświetlony widok Error dla użytkownika z informacją o błędzie.
No i na koniec zostaje nam opisanie akcji usuwania wpisu (podobnie jak w przypadku akcji Edit zabezpieczenie akcji przed wywołaniem przez niepożądaną osobę opiszę w jednym z kolejnych wpisów). Akcja Delete przypisana do żądania get wyświetla formularz, w którym użytkownik musi potwierdzić chęć usunięcia wpisu. Natomiast akcja Delete przypisana do żądania post usuwająca wpis. Obie akcje są bardzo podobne do już wcześniejszych akcji. Wystarczy rzucić okiem na kod i wszystko jest jasne 
1: public ActionResult Delete(int id)
2: {
3: DB db = new DB();
4:
5: var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
6:
7: if (guestBook == null)
8: {
9: return RedirectToAction("Index");
10: }
11:
12: return View(guestBook);
13: }
14:
15: [HttpPost]
16: public ActionResult Delete(int id, FormCollection collection)
17: {
18: try
19: {
20: DB db = new DB();
21:
22: var guestBook = db.GuestBooks.Where(x => x.Id == id).FirstOrDefault();
23:
24: if (guestBook == null)
25: {
26: return RedirectToAction("Index");
27: }
28:
29: db.GuestBooks.DeleteOnSubmit(guestBook);
30: db.SubmitChanges();
31:
32: return RedirectToAction("Index");
33: }
34: catch
35: {
36: return View();
37: }
38: }
Podobnie jak w akcjach wcześniejszych na początku obu akcji jest wyciągany wpis z bazy o danym id. Jeśli nie ma takiego, użytkownik jest przekierowywany do akcji Index. Natomiast, gdy jest pierwsza akcja wyświetla formularz, natomiast w drugiej następuje usunięcie go z bazy danych i przekierowanie użytkownika do akcji Index. W przypadku wystąpienia błędu wyświetla się użytkownikowi stosowane informacja o błędzie.
To by było na tyle z podstaw tworzenia kontrolerów w ASP.NET MVC 2. W późniejszych artykułach opiszę trochę bardziej zaawansowane rzeczy o kontrolerach. Natomiast w następnym wpisie będzie na temat widoków w ASP.NET MVC.
Tags: asp.net mvc,
mvc,
kontroler
Categories: Techniczne
4853a972-e7d2-41ed-9b48-d7d2da129d62|4|4.5