Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Microsoft tarafından
Bu, ASP.NET MVC 1 kullanarak küçük ama eksiksiz bir web uygulaması oluşturmayı gösteren ücretsiz bir "NerdDinner" uygulaması öğreticisinin 5. adımıdır.
5. Adım, DinnersController sınıfımızı düzenleme, oluşturma ve silme desteği sağlayarak nasıl daha ileriye götüreceğinizi gösterir.
ASP.NET MVC 3 kullanıyorsanız , MVC 3 veya MVC Music Store ile Çalışmaya Başlama öğreticilerini izlemenizi öneririz.
NerdDinner 5. Adım: Form Senaryoları Oluşturma, Güncelleştirme, Silme
Denetleyiciler ve görünümler sağladık ve bu denetleyicilerin sitedeki Akşam Yemekleri için listeleme/ayrıntı deneyimi uygulamak için nasıl kullanılacağını ele aldık. Bir sonraki adımımız DinnersController sınıfımızı daha ileriye götürmek ve onunla birlikte Akşam Yemekleri düzenleme, oluşturma ve silme desteği sağlamak olacak.
DinnersController tarafından işlenen URL'ler
Daha önce DinnersController'a iki URL için destek uygulayan eylem yöntemleri eklemiştik: /Dinners ve /Dinners/Details/[id].
URL | FİİL | Amaç |
---|---|---|
/Akşam yemek -leri/ | GET | Yaklaşan akşam yemeklerinin HTML listesini görüntüleyin. |
/Dinners/Details/[id] | GET | Belirli bir akşam yemeği hakkındaki ayrıntıları görüntüleyin. |
Şimdi üç ek URL uygulamak için eylem yöntemleri ekleyeceğiz: /Dinners/Edit/[id], /Dinners/Create ve /Dinners/Delete/[id]. Bu URL'ler mevcut Akşam Yemeklerini düzenleme, yeni Akşam Yemekleri oluşturma ve Akşam Yemekleri'ni silme desteği sağlar.
Bu yeni URL'lerle hem HTTP GET hem de HTTP POST fiil etkileşimlerini destekleyeceğiz. Bu URL'lere yönelik HTTP GET istekleri, verilerin ilk HTML görünümünü ("düzenleme" durumunda Akşam Yemeği verileriyle doldurulmuş bir form, "oluşturma" durumunda boş bir form ve "silme" durumunda bir silme onay ekranı) görüntüler. Bu URL'lere yönelik HTTP POST istekleri DinnerRepository'imizdeki (ve oradan veritabanına) Akşam Yemeği verilerini kaydeder/güncelleştirir/siler.
URL | FİİL | Amaç |
---|---|---|
/Dinners/Edit/[id] | GET | Akşam yemeği verileriyle doldurulmuş düzenlenebilir bir HTML formu görüntüleyin. |
POST | Belirli bir Akşam Yemeği için form değişikliklerini veritabanına kaydedin. | |
/Dinners/Create | GET | Kullanıcıların yeni Akşam Yemekleri tanımlamasına olanak tanıyan boş bir HTML formu görüntüleyin. |
POST | Yeni bir Akşam Yemeği oluşturun ve bunu veritabanına kaydedin. | |
/Dinners/Delete/[id] | GET | Silme onayı ekranını görüntüleyin. |
POST | Belirtilen akşam yemeğini veritabanından siler. |
Desteği Düzenle
"Düzenle" senaryoyu uygulayarak başlayalım.
HTTP-GET Düzenleme Eylemi Yöntemi
İlk olarak düzenleme eylemi yöntemimizin HTTP "GET" davranışını uygulayacağız. /Dinners/Edit/[id] URL'si istendiğinde bu yöntem çağrılır. Uygulamamız şöyle görünür:
//
// GET: /Dinners/Edit/2
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
return View(dinner);
}
Yukarıdaki kod dinner nesnesini almak için DinnerRepository kullanır. Ardından Dinner nesnesini kullanarak bir Görünüm şablonu işler. View() yardımcı yöntemine açıkça bir şablon adı iletmediğimizden, görünüm şablonunu çözümlemek için kural tabanlı varsayılan yolu kullanır: /Views/Dinners/Edit.aspx.
Şimdi bu görünüm şablonunu oluşturalım. Bunu, Düzenle yöntemine sağ tıklayıp "Görünüm Ekle" bağlam menüsü komutunu seçerek yapacağız:
"Görünüm Ekle" iletişim kutusunda, bir Dinner nesnesini görünüm şablonumuza modeli olarak geçirebileceğimizi belirtecek ve bir "Düzenle" şablonunu otomatik olarak iskelelemeyi seçeceğiz:
"Ekle" düğmesine tıkladığımızda Visual Studio, "\Views\Dinners" dizininde bizim için yeni bir "Edit.aspx" görünüm şablonu dosyası ekleyecektir. Ayrıca kod düzenleyicisinde yeni "Edit.aspx" görünüm şablonunu açar ve aşağıdaki gibi ilk "Düzenle" yapı iskelesi uygulamasıyla doldurulur:
Oluşturulan varsayılan "düzenleme" yapı iskelesinde birkaç değişiklik yapalım ve düzenleme görünümü şablonunu aşağıdaki içeriğe sahip olacak şekilde güncelleştirelim (bu da kullanıma açmak istemediğimiz özelliklerden birkaçını kaldırır):
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Edit: <%=Html.Encode(Model.Title)%>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit Dinner</h2>
<%=Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) { %>
<fieldset>
<p>
<label for="Title">Dinner Title:</label>
<%=Html.TextBox("Title") %>
<%=Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="EventDate">EventDate:</label>
<%=Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate))%>
<%=Html.ValidationMessage("EventDate", "*") %>
</p>
<p>
<label for="Description">Description:</label>
<%=Html.TextArea("Description") %>
<%=Html.ValidationMessage("Description", "*")%>
</p>
<p>
<label for="Address">Address:</label>
<%=Html.TextBox("Address") %>
<%=Html.ValidationMessage("Address", "*") %>
</p>
<p>
<label for="Country">Country:</label>
<%=Html.TextBox("Country") %>
<%=Html.ValidationMessage("Country", "*") %>
</p>
<p>
<label for="ContactPhone">ContactPhone #:</label>
<%=Html.TextBox("ContactPhone") %>
<%=Html.ValidationMessage("ContactPhone", "*") %>
</p>
<p>
<label for="Latitude">Latitude:</label>
<%=Html.TextBox("Latitude") %>
<%=Html.ValidationMessage("Latitude", "*") %>
</p>
<p>
<label for="Longitude">Longitude:</label>
<%=Html.TextBox("Longitude") %>
<%=Html.ValidationMessage("Longitude", "*") %>
</p>
<p>
<input type="submit" value="Save"/>
</p>
</fieldset>
<% } %>
</asp:Content>
Uygulamayı çalıştırdığımızda ve "/Dinners/Edit/1" URL'sini istediğimizde aşağıdaki sayfayı göreceğiz:
Görünümümüz tarafından oluşturulan HTML işaretlemesi aşağıdaki gibi görünür. "Kaydet" <giriş türü="submit"/> düğmesi gönderildiğinde /Dinners/Edit/1 URL'sine HTTP POST gerçekleştiren bir form> öğesiyle <standart HTML'dir. Düzenlenebilir her özellik için bir HTML <giriş type="text"/> öğesi çıktısı alındı:
Html.BeginForm() ve Html.TextBox() Html Yardımcısı Yöntemleri
"Edit.aspx" görünüm şablonumuz birkaç "Html Yardımcısı" yöntemi kullanıyor: Html.ValidationSummary(), Html.BeginForm(), Html.TextBox() ve Html.ValidationMessage(). Bu yardımcı yöntemler, bizim için HTML işaretlemesi oluşturmaya ek olarak yerleşik hata işleme ve doğrulama desteği sağlar.
Html.BeginForm() yardımcı yöntemi
Html.BeginForm() yardımcı yöntemi, işaretlememizdeki HTML <form> öğesinin çıkışını oluşturan yöntemdir. Edit.aspx görünüm şablonumuzda bu yöntemi kullanırken bir C# "using" deyimi uyguladığımızı fark edeceksiniz. Açık küme ayracı form> içeriğinin <başlangıcını, kapanış küme ayracı ise /form> öğesinin <sonunu gösterir:
<% using (Html.BeginForm()) { %>
<fieldset>
<!-- Fields Omitted for Brevity -->
<p>
<input type="submit" value="Save"/>
</p>
</fieldset>
<% } %>
Alternatif olarak, böyle bir senaryo için "using" deyimi yaklaşımını doğal bulmazsanız, Html.BeginForm() ve Html.EndForm() bileşimini (aynı şeyi yapar) kullanabilirsiniz:
<% Html.BeginForm(); %>
<fieldset>
<!-- Fields Omitted for Brevity -->
<p>
<input type="submit" value="Save"/>
</p>
</fieldset>
<% Html.EndForm(); %>
Html.BeginForm() öğesini parametre olmadan çağırmak, geçerli isteğin URL'sine HTTP-POST yapan bir form öğesi çıkışı vermesine neden olur. Bu nedenle Düzenleme görünümümüz bir <form action="/Dinners/Edit/1" method="post"> öğesi oluşturur. Farklı bir URL'ye göndermek isteseydik alternatif olarak Html.BeginForm() öğesine açık parametreler geçirmiş olabilirdik.
Html.TextBox() yardımcı yöntemi
Edit.aspx görünümümüz, giriş type="text"/> öğelerini çıkarmak <için Html.TextBox() yardımcı yöntemini kullanır:
<%= Html.TextBox("Title") %>
Yukarıdaki Html.TextBox() yöntemi tek bir parametre alır. Bu, çıkış için input type="text"/> öğesinin <id/name özniteliklerinin yanı sıra metin kutusu değerini dolduracak model özelliğini belirtmek için kullanılır. Örneğin, Düzenleme görünümüne geçirdiğimiz Dinner nesnesinin "Title" özellik değeri ".NET Futures" oldu ve bu nedenle Html.TextBox("Title") yöntem çağrı çıkışımız: <input id="Title" name="Title" type="text" value=".NET Futures" />.
Alternatif olarak, öğenin kimliğini/adını belirtmek için ilk Html.TextBox() parametresini kullanabilir ve ardından ikinci parametre olarak kullanılacak değeri açıkça geçirebiliriz:
<%= Html.TextBox("Title", Model.Title)%>
Genellikle çıktı olan değer üzerinde özel biçimlendirme gerçekleştirmek isteriz. Yerleşik .NET'in String.Format() statik yöntemi bu senaryolar için yararlıdır. Edit.aspx görünüm şablonumuz, EventDate değerini (DateTime türündedir) biçimlendirmek için bunu kullanarak saniyeleri göstermiyor:
<%= Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate)) %>
Html.TextBox() için üçüncü bir parametre isteğe bağlı olarak ek HTML öznitelikleri çıktısı almak için kullanılabilir. Aşağıdaki kod parçacığında, input type="text"/> öğesinde ek bir size="30" özniteliğinin ve class="mycssclass" özniteliğinin <nasıl işlenmeleri gösterilmektedir. "sınıf" C# dilinde ayrılmış bir anahtar sözcük olduğundan, "@" karakteri kullanarak sınıf özniteliğinin adından nasıl kaçtığımızı unutmayın:
<%= Html.TextBox("Title", Model.Title, new { size=30, @class="myclass" } )%>
HTTP-POST Düzenleme Eylem Yöntemini Uygulama
Artık Düzenleme eylem yöntemimizin HTTP-GET sürümü uygulandı. Bir kullanıcı /Dinners/Edit/1 URL'sini istediğinde aşağıdakine benzer bir HTML sayfası alır:
"Kaydet" düğmesine basıldığında /Dinners/Edit/1 URL'sine bir form gönderisi gönderilir ve HTTP POST fiilini kullanarak HTML <giriş> formu değerleri gönderilir. Şimdi akşam yemeğini kaydetmeyi işleyecek düzenleme eylemi yöntemimizin HTTP POST davranışını uygulayalım.
DinnersController'ımıza HTTP POST senaryolarını işlediğini belirten "AcceptVerbs" özniteliğine sahip aşırı yüklenmiş bir "Düzenle" eylem yöntemi ekleyerek başlayacağız:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
...
}
Aşırı yüklenmiş eylem yöntemlerine [AcceptVerbs] özniteliği uygulandığında, ASP.NET MVC gelen HTTP fiiline bağlı olarak istekleri uygun eylem yöntemine göndermeyi otomatik olarak işler.
/Dinners/Edit/[id] URL'lerine HTTP POST istekleri yukarıdaki Düzenleme yöntemine, /Dinners/Edit/[id] URL'lerine yönelik diğer tüm HTTP fiili istekleri ise uyguladığımız ilk Düzenleme yöntemine gider (özniteliği yoktu[AcceptVerbs]
).
Yan Konu: HTTP fiilleri aracılığıyla neden ayırt edilebilir? |
---|
Şu soruyu sorabilirsiniz: Neden tek bir URL kullanıyor ve davranışını HTTP fiili aracılığıyla farklılıyoruz? Düzenleme değişikliklerini yüklemek ve kaydetmek için neden yalnızca iki ayrı URL'niz yok? Örneğin: İlk formu görüntülemek için /Dinners/Edit/[id] ve kaydetmek için form gönderisini işlemek için /Dinners/Save/[id] ? İki ayrı URL yayımlamanın dezavantajı, /Dinners/Save/2'ye gönderi yaptığımız ve giriş hatası nedeniyle HTML formunu yeniden görüntülemek zorunda kaldığımız durumlarda, son kullanıcının tarayıcının adres çubuğunda /Dinners/Save/2 URL'si olmasıdır (formun gönderildiği URL olduğundan). Son kullanıcı bu yeniden dağıtılan sayfayı tarayıcı sık kullanılanlar listesine yer işareti eklerse veya URL'yi kopyalayıp yapıştırır ve bir arkadaşınıza e-posta ile gönderirse, gelecekte çalışmayacak bir URL kaydeder (çünkü bu URL posta değerlerine bağlıdır). Tek bir URL'yi (örneğin: /Dinners/Edit/[id]) kullanıma sunarak ve HTTP fiiline göre işlenmesini farklı hale getirmek, son kullanıcıların düzenleme sayfasına yer işareti eklemesi ve/veya URL'yi başkalarına göndermesi güvenlidir. |
Form Deftere Nakl. Değerleri Alınıyor
GÖNDERILEN form parametrelerine HTTP POST "Düzenle" yöntemimiz içinde çeşitli yollarla erişebiliriz. Basit bir yaklaşım, form koleksiyonuna erişmek ve gönderilen değerleri doğrudan almak için Yalnızca Denetleyici temel sınıfındaki Request özelliğini kullanmaktır:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
// Retrieve existing dinner
Dinner dinner = dinnerRepository.GetDinner(id);
// Update dinner with form posted values
dinner.Title = Request.Form["Title"];
dinner.Description = Request.Form["Description"];
dinner.EventDate = DateTime.Parse(Request.Form["EventDate"]);
dinner.Address = Request.Form["Address"];
dinner.Country = Request.Form["Country"];
dinner.ContactPhone = Request.Form["ContactPhone"];
// Persist changes back to database
dinnerRepository.Save();
// Perform HTTP redirect to details page for the saved Dinner
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
Ancak, özellikle hata işleme mantığı ekledikten sonra yukarıdaki yaklaşım biraz ayrıntılıdır.
Bu senaryo için daha iyi bir yaklaşım, Denetleyici temel sınıfındaki yerleşik UpdateModel() yardımcı yönteminden yararlanmaktır. Gelen form parametrelerini kullanarak geçirdiğimiz bir nesnenin özelliklerini güncelleştirmeyi destekler. Nesnedeki özellik adlarını belirlemek için yansımayı kullanır ve ardından istemci tarafından gönderilen giriş değerlerine göre değerleri otomatik olarak dönüştürür ve bunlara atar.
Şu kodu kullanarak HTTP-POST Düzenleme Eylemimizi basitleştirmek için UpdateModel() yöntemini kullanabiliriz:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
Artık /Dinners/Edit/1 URL'sini ziyaret edebilir ve Akşam Yemeğimizin başlığını değiştirebiliriz:
"Kaydet" düğmesine tıkladığımızda Düzenle eylemimize bir form gönderisi gerçekleştiririz ve güncelleştirilmiş değerler veritabanında kalıcı hale gelir. Daha sonra Akşam Yemeği için Ayrıntılar URL'sine yönlendiriliriz (yeni kaydedilen değerleri görüntüler):
Düzenleme Hatalarını İşleme
Geçerli HTTP-POST uygulamamız, hatalar olduğu durumlar dışında düzgün çalışır.
Bir kullanıcı formu düzenlerken hata yaptığında, formun düzeltilmesi için ona yol gösteren bilgilendirici bir hata iletisiyle yeniden dağıtıldığından emin olmamız gerekir. Buna, son kullanıcının yanlış giriş (örneğin, hatalı biçimlendirilmiş tarih dizesi) gönderdiği durumlar ve giriş biçiminin geçerli olduğu ancak bir iş kuralı ihlali olduğu durumlar dahildir. Hatalar oluştuğunda form, kullanıcının başlangıçta girdiği giriş verilerini koruyarak değişikliklerini el ile doldurmasına gerek yoktur. Form başarıyla tamamlanana kadar bu işlem gerektiği kadar tekrarlanmalıdır.
ASP.NET MVC, hata işleme ve form yeniden dağıtımını kolaylaştıran bazı güzel yerleşik özellikler içerir. Bu özelliklerin nasıl çalıştığını görmek için Düzenle eylem yöntemimizi aşağıdaki kodla güncelleştirelim:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(dinner);
}
}
Yukarıdaki kod önceki uygulamamıza benzer; ancak artık çalışmamızın çevresinde bir try/catch hata işleme bloğunu sarmalıyoruz. UpdateModel() çağrılırken bir özel durum oluşursa veya DinnerRepository'u kaydetmeyi denediğimizde (kaydetmeye çalıştığımız Dinner nesnesi modelimiz içindeki bir kural ihlali nedeniyle geçersizse bir özel durum oluşturur), yakalama hata işleme bloğumuz yürütülür. Bunun içinde Dinner nesnesinde var olan tüm kural ihlallerini döngüye alır ve bunları bir ModelState nesnesine ekleriz (kısa süre içinde ele alacağız). Ardından görünümü yeniden görüntüleyeceğiz.
Bu çalışmayı görmek için uygulamayı yeniden çalıştıralım, akşam yemeğini düzenleyelim ve boş bir Title, eventDate /"BOGUS" olacak şekilde değiştirelim ve ABD ülke/bölge değerine sahip bir Birleşik Krallık telefon numarası kullanalım. "Kaydet" düğmesine bastığımızda HTTP POST Düzenleme yöntemimiz Akşam Yemeğini kaydedemeyecek (hatalar olduğundan) ve formu yeniden görüntüleyecek:
Uygulamamız düzgün bir hata deneyimine sahip. Geçersiz girişi olan metin öğeleri kırmızı renkle vurgulanır ve son kullanıcıya bunlar hakkında doğrulama hata iletileri görüntülenir. Form ayrıca kullanıcının ilk girdiği giriş verilerini de korur ve böylece hiçbir şeyi yeniden doldurması gerekmez.
Bu nasıl oldu diye sorabilirsiniz? Title, EventDate ve ContactPhone metin kutuları kendilerini kırmızı renkle nasıl vurguladı ve başlangıçta girilen kullanıcı değerlerinin çıkışını nasıl bildi? En üstteki listede hata iletileri nasıl görüntülendi? bunun sihir tarafından gerçekleşmemiş olması iyi bir haberdir. Bunun nedeni giriş doğrulama ve hata işleme senaryolarını kolaylaştıran yerleşik ASP.NET MVC özelliklerinden bazılarını kullanmamızdır.
ModelState'i ve Doğrulama HTML Yardımcı Yöntemlerini Anlama
Denetleyici sınıfları, bir Görünüme geçirilen model nesnesiyle hataların mevcut olduğunu göstermek için bir yol sağlayan bir "ModelState" özellik koleksiyonuna sahiptir. ModelState koleksiyonundaki hata girdileri, sorunla birlikte model özelliğinin adını (örneğin: "Title", "EventDate" veya "ContactPhone") tanımlar ve insan dostu bir hata iletisi belirtilmesine izin verir (örneğin: "Başlık gereklidir").
UpdateModel() yardımcı yöntemi model nesnesinde özelliklere form değerleri atamaya çalışırken hatalarla karşılaştığında ModelState koleksiyonunu otomatik olarak doldurur. Örneğin, Dinner nesnemizin EventDate özelliği DateTime türündedir. UpdateModel() yöntemi yukarıdaki senaryoda "BOGUS" dize değerini ona atayamadığında, UpdateModel() yöntemi ModelState koleksiyonuna bu özellikte bir atama hatası oluştuğunu belirten bir girdi ekledi.
Geliştiriciler ayrıca, ModelState koleksiyonuna aşağıda yaptığımız gibi, "catch" hata işleme bloğumuzda yaptığımız gibi, ModelState koleksiyonunu Dinner nesnesindeki etkin Kural İhlallerini temel alan girdilerle dolduran açıkça hata girdileri eklemek için kod yazabilir:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(dinner);
}
}
ModelState ile Html Yardımcısı Tümleştirmesi
Html.TextBox() gibi HTML yardımcı yöntemleri, çıkışı işlerken ModelState koleksiyonunu denetleyin. Öğe için bir hata varsa, kullanıcı tarafından girilen değeri ve CSS hata sınıfını işler.
Örneğin, "Düzenle" görünümünde, Dinner nesnemizin EventDate değerini işlemek için Html.TextBox() yardımcı yöntemini kullanıyoruz:
<%= Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate)) %>
Görünüm hata senaryosunda işlendiğinde Html.TextBox() yöntemi, Dinner nesnemizin "EventDate" özelliğiyle ilişkili hatalar olup olmadığını görmek için ModelState koleksiyonunu denetledi. Bir hata olduğunu belirlediğinde, gönderilen kullanıcı girişini ("BOGUS") değer olarak işledi ve oluşturduğu input type="textbox"/> işaretlemesine <bir css hata sınıfı ekledi:
<input class="input-validation-error"id="EventDate" name="EventDate" type="text" value="BOGUS"/>
css hata sınıfının görünümünü istediğiniz gibi görünecek şekilde özelleştirebilirsiniz. Varsayılan CSS hata sınıfı – "input-validation-error" – \content\site.css stil sayfasında tanımlanır ve aşağıdaki gibi görünür:
.input-validation-error
{
border: 1px solid #ff0000;
background-color: #ffeeee;
}
Geçersiz giriş öğelerimizin aşağıdaki gibi vurgulanması bu CSS kuralına neden oldu:
Html.ValidationMessage() Yardımcı Yöntemi
Html.ValidationMessage() yardımcı yöntemi, belirli bir model özelliğiyle ilişkili ModelState hata iletisinin çıkışını almak için kullanılabilir:
<%= Html.ValidationMessage("EventDate")%>
Yukarıdaki kod çıkışları: <span class="field-validation-error"> 'BOGUS' değeri geçersiz</span>
Html.ValidationMessage() yardımcı yöntemi, geliştiricilerin görüntülenen hata metin iletisini geçersiz kılmasını sağlayan ikinci bir parametreyi de destekler:
<%= Html.ValidationMessage("EventDate","*") %>
Yukarıdaki kod çıkışları: EventDate özelliği için bir hata olduğunda varsayılan hata metni yerine span class="field-validation-error">*</span>.<
Html.ValidationSummary() Yardımcı Yöntemi
Html.ValidationSummary() yardımcı yöntemi, ModelState koleksiyonundaki tüm ayrıntılı hata iletilerinin ul li//><ul> listesiyle birlikte özet <><hata iletisini işlemek için kullanılabilir:
Html.ValidationSummary() yardımcı yöntemi, ayrıntılı hatalar listesinin üstünde görüntülenecek bir özet hata iletisi tanımlayan isteğe bağlı bir dize parametresi alır:
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
hata listesinin görünümünü geçersiz kılmak için isteğe bağlı olarak CSS kullanabilirsiniz.
AddRuleViolations Yardımcı Yöntemi Kullanma
İlk HTTP-POST Düzenleme uygulamamız, Dinner nesnesinin Kural İhlalleri üzerinde döngü yapmak ve bunları denetleyicinin ModelState koleksiyonuna eklemek için catch bloğu içinde bir foreach deyimi kullandı:
catch {
foreach (var issue in dinner.GetRuleViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(dinner);
}
NerdDinner projesine bir "ControllerHelpers" sınıfı ekleyerek ve içinde ASP.NET MVC ModelStateDictionary sınıfına yardımcı yöntem ekleyen bir "AddRuleViolations" uzantısı yöntemi uygulayarak bu kodu biraz daha temiz hale getirebiliriz. Bu uzantı yöntemi, ModelStateDictionary'i RuleViolation hatalarının listesiyle doldurmak için gereken mantığı kapsülleyebilir:
public static class ControllerHelpers {
public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors) {
foreach (RuleViolation issue in errors) {
modelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
}
}
Ardından, ModelState koleksiyonunu Akşam Yemeği Kuralı İhlallerimizle doldurmak için bu uzantı yöntemini kullanmak üzere HTTP-POST Düzenleme eylem yöntemimizi güncelleştirebiliriz.
Eylem Yöntemini Düzenleme Uygulamalarını Tamamlama
Aşağıdaki kod, Düzenleme senaryomuz için gerekli olan tüm denetleyici mantığını uygular:
//
// GET: /Dinners/Edit/2
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
return View(dinner);
}
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
return View(dinner);
}
}
Düzenleme uygulamamızın en güzel özelliği, Ne Denetleyici sınıfımızın ne de Görünüm şablonumuzun Akşam Yemeği modelimiz tarafından uygulanan belirli doğrulama veya iş kuralları hakkında bir şey bilmesi gerekmeyen olmasıdır. Gelecekte modelimize ek kurallar ekleyebiliriz ve bunların desteklenmesi için denetleyicimizde veya görünümümüzde herhangi bir kod değişikliği yapmak zorunda değiliz. Bu, uygulama gereksinimlerimizi gelecekte en az kod değişikliğiyle kolayca geliştirme esnekliği sağlar.
Destek Oluştur
DinnersController sınıfımızın "Düzenle" davranışını uygulamayı tamamladık. Şimdi üzerinde kullanıcıların yeni Akşam Yemekleri eklemesine olanak tanıyan "Oluştur" desteğini uygulamaya geçelim.
HTTP-GET Oluşturma Eylem Yöntemi
İlk olarak oluşturma eylem yöntemimizin HTTP "GET" davranışını uygulayacağız. Birisi /Dinners/Create URL'sini ziyaret ettiğinde bu yöntem çağrılır. Uygulamamız şöyle görünür:
//
// GET: /Dinners/Create
public ActionResult Create() {
Dinner dinner = new Dinner() {
EventDate = DateTime.Now.AddDays(7)
};
return View(dinner);
}
Yukarıdaki kod yeni bir Dinner nesnesi oluşturur ve EventDate özelliğini gelecekte bir hafta olacak şekilde atar. Ardından yeni Dinner nesnesini temel alan bir Görünüm oluşturur. View() yardımcı yöntemine açıkça bir ad iletmediğimizden, görünüm şablonunu çözümlemek için kural tabanlı varsayılan yolu kullanır: /Views/Dinners/Create.aspx.
Şimdi bu görünüm şablonunu oluşturalım. Bunu yapmak için Eylem oluştur yöntemine sağ tıklayıp "Görünüm Ekle" bağlam menüsü komutunu seçebiliriz. "Görünüm Ekle" iletişim kutusunda, görünüm şablonuna bir Dinner nesnesi geçireceğimizi belirtecek ve bir "Oluştur" şablonunun iskelesini otomatik olarak oluşturmayı seçeceğiz:
"Ekle" düğmesine tıkladığımızda Visual Studio yeni bir yapı iskelesi tabanlı "Create.aspx" görünümünü "\Views\Dinners" dizinine kaydeder ve IDE içinde açar:
Şimdi bizim için oluşturulan varsayılan "create" yapı iskelesi dosyasında birkaç değişiklik yapalım ve aşağıdakine benzer şekilde değiştirelim:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Host a Dinner
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Host a Dinner</h2>
<%=Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<p>
<label for="Title">Title:</label>
<%= Html.TextBox("Title") %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="EventDate">EventDate:</label>
<%=Html.TextBox("EventDate") %>
<%=Html.ValidationMessage("EventDate", "*") %>
</p>
<p>
<label for="Description">Description:</label>
<%=Html.TextArea("Description") %>
<%=Html.ValidationMessage("Description", "*") %>
</p>
<p>
<label for="Address">Address:</label>
<%=Html.TextBox("Address") %>
<%=Html.ValidationMessage("Address", "*") %>
</p>
<p>
<label for="Country">Country:</label>
<%=Html.TextBox("Country") %>
<%=Html.ValidationMessage("Country", "*") %>
</p>
<p>
<label for="ContactPhone">ContactPhone:</label>
<%=Html.TextBox("ContactPhone") %>
<%=Html.ValidationMessage("ContactPhone", "*") %>
</p>
<p>
<label for="Latitude">Latitude:</label>
<%=Html.TextBox("Latitude") %>
<%=Html.ValidationMessage("Latitude", "*") %>
</p>
<p>
<label for="Longitude">Longitude:</label>
<%=Html.TextBox("Longitude") %>
<%=Html.ValidationMessage("Longitude", "*") %>
</p>
<p>
<input type="submit" value="Save"/>
</p>
</fieldset>
<% }
%>
</asp:Content>
Şimdi de uygulamamızı çalıştırdığımızda ve tarayıcıdaki "/Dinners/Create" URL'sine eriştiğimizde Oluştur eylem uygulamamızdan aşağıdaki gibi kullanıcı arabirimini işleyecek:
HTTP-POST Oluşturma Eylem Yöntemini Uygulama
Create eylem yöntemimizin HTTP-GET sürümü uygulandı. Kullanıcı "Kaydet" düğmesine tıkladığında /Dinners/Create URL'sine bir form gönderisi gerçekleştirir ve HTTP POST fiilini kullanarak HTML <giriş> formu değerlerini gönderir.
Şimdi oluşturma eylem yöntemimizin HTTP POST davranışını uygulayalım. DinnersController'ımıza HTTP POST senaryolarını işlediğini belirten "AcceptVerbs" özniteliğine sahip aşırı yüklenmiş bir "Create" eylem yöntemi ekleyerek başlayacağız:
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create() {
...
}
HTTP-POST özellikli "Oluştur" yöntemimizin içinde, gönderilen form parametrelerine erişmenin çeşitli yolları vardır.
Yaklaşımlardan biri, yeni bir Dinner nesnesi oluşturmak ve ardından UpdateModel() yardımcı yöntemini (Düzenle eyleminde yaptığımız gibi) kullanarak bunu gönderilen form değerleriyle doldurmaktır. Ardından bunu DinnerRepository depomuza ekleyebilir, veritabanında kalıcı hale ekleyebilir ve kullanıcıyı Ayrıntılar eylemimize yönlendirerek aşağıdaki kodu kullanarak yeni oluşturulan Akşam Yemeğini gösterebiliriz:
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create() {
Dinner dinner = new Dinner();
try {
UpdateModel(dinner);
dinnerRepository.Add(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new {id=dinner.DinnerID});
}
catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
return View(dinner);
}
}
Alternatif olarak, Create() eylem yöntemimizin bir Dinner nesnesini yöntem parametresi olarak aldığı bir yaklaşımı kullanabiliriz. ASP.NET MVC bizim için otomatik olarak yeni bir Dinner nesnesi oluşturur, form girişlerini kullanarak özelliklerini doldurur ve eylem yöntemimize geçirir:
//
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Dinner dinner) {
if (ModelState.IsValid) {
try {
dinner.HostedBy = "SomeUser";
dinnerRepository.Add(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new {id = dinner.DinnerID });
}
catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
}
}
return View(dinner);
}
Yukarıdaki eylem yöntemimiz, ModelState.IsValid özelliğini denetleyerek Dinner nesnesinin form posta değerleriyle başarıyla doldurulduğunu doğrular. Giriş dönüştürme sorunları varsa (örneğin: EventDate özelliği için bir "BOGUS" dizesi) ve herhangi bir sorun varsa eylem yöntemimiz formu yeniden görüntülerse false döndürür.
Giriş değerleri geçerliyse, eylem yöntemi yeni Akşam Yemeğini DinnerRepository'e eklemeyi ve kaydetmeyi dener. Bu işi bir try/catch bloğu içinde sarmalar ve iş kuralı ihlalleri varsa formu yeniden görüntüler (bu da dinnerRepository.Save() yönteminin özel durum oluşturmasına neden olur).
Bu hata işleme davranışını çalışırken görmek için /Dinners/Create URL'sini isteyebilir ve yeni bir Akşam Yemeği hakkındaki ayrıntıları doldurabiliriz. Yanlış giriş veya değerler oluşturma formunun aşağıdaki gibi vurgulanan hatalarla yeniden dağıtılmasına neden olur:
Oluşturma formumuzun Düzenleme formumuzla tam olarak aynı doğrulama ve iş kurallarına uy olduğuna dikkat edin. Bunun nedeni doğrulama ve iş kurallarımızın modelde tanımlanmış olması ve uygulamanın kullanıcı arabirimine veya denetleyicisine katıştırılmamasıdır. Bu, doğrulama veya iş kurallarımızı daha sonra tek bir yerde değiştirebileceğimiz/geliştirebileceğimiz ve uygulamamız genelinde uygulanabilecekleri anlamına gelir. Yeni kuralları veya mevcut kurallarda yapılan değişiklikleri otomatik olarak uygulamak için Düzenle veya Oluştur eylem yöntemlerimizdeki hiçbir kodu değiştirmemiz gerekmez.
Giriş değerlerini düzelttiğimizde ve "Kaydet" düğmesine yeniden tıkladığımızda DinnerRepository eklememiz başarılı olur ve veritabanına yeni bir Akşam Yemeği eklenir. Ardından /Dinners/Details/[id] URL'sine yönlendirilecek ve burada yeni oluşturulan Akşam Yemeği hakkında ayrıntılı bilgi sunacağız:
Desteği Sil
Şimdi DinnersController'a "Sil" desteği ekleyelim.
HTTP-GET Silme Eylem Yöntemi
İlk olarak silme eylemi yöntemimizin HTTP GET davranışını uygulayacağız. Birisi /Dinners/Delete/[id] URL'sini ziyaret ettiğinde bu yöntem çağrılır. Uygulama aşağıdadır:
//
// HTTP GET: /Dinners/Delete/1
public ActionResult Delete(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
else
return View(dinner);
}
Eylem yöntemi silinecek Akşam Yemeğini almaya çalışır. Akşam Yemeği varsa, Dinner nesnesini temel alan bir Görünüm oluşturur. Nesne yoksa (veya zaten silinmişse), "Ayrıntılar" eylem yöntemimiz için daha önce oluşturduğumuz "NotFound" görünüm şablonunu işleyen bir Görünüm döndürür.
Sil eylem yönteminin içine sağ tıklayıp "Görünüm Ekle" bağlam menüsü komutunu seçerek "Sil" görünüm şablonunu oluşturabiliriz. "Görünüm Ekle" iletişim kutusunda, görünüm şablonumuza modeli olarak bir Dinner nesnesi geçirip boş bir şablon oluşturmayı seçtiğimizi belirteceğiz:
"Ekle" düğmesine tıkladığımızda Visual Studio, "\Views\Dinners" dizinimizde bizim için yeni bir "Delete.aspx" görünüm şablonu dosyası ekleyecektir. Aşağıdaki gibi bir silme onay ekranı uygulamak için şablona biraz HTML ve kod ekleyeceğiz:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Delete Confirmation: <%=Html.Encode(Model.Title) %>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Delete Confirmation
</h2>
<div>
<p>Please confirm you want to cancel the dinner titled:
<i> <%=Html.Encode(Model.Title) %>? </i>
</p>
</div>
<% using (Html.BeginForm()) { %>
<input name="confirmButton" type="submit" value="Delete" />
<% } %>
</asp:Content>
Yukarıdaki kod silinecek Akşam Yemeğinin başlığını görüntüler ve son kullanıcı içindeki "Sil" düğmesine tıklarsa /Dinners/Delete/[id] URL'sine POST işlemi gerçekleştiren bir <form> öğesi verir.
Uygulamamızı çalıştırdığımızda ve geçerli bir Dinner nesnesinin "/Dinners/Delete/[id]" URL'sine eriştiğimizde aşağıdaki gibi kullanıcı arabirimini işler:
Yan Konu: Neden POST yapıyoruz? |
---|
Şunu sorabilirsiniz: Silme onay ekranımızda neden form <> oluşturma çabasını sarf ettik? Gerçek silme işleminin gerçekleştirildiği bir eylem yöntemine bağlanmak için neden yalnızca standart bir köprü kullanılmıyor? Bunun nedeni, url'lerimizi keşfeden ve yanlışlıkla bağlantıları takip eden verilerin silinmesine neden olan web gezginlerini ve arama motorlarını korumaya dikkat etmek istememizdir. HTTP-GET tabanlı URL'ler erişim/gezinme için "güvenli" olarak kabul edilir ve HTTP-POST'ları izlememeleri gerekir. İyi bir kural, HTTP-POST isteklerinin arkasına her zaman yıkıcı veya veri değiştirme işlemleri koyduğuduğunuzdan emin olmaktır. |
HTTP-POST Silme Eylem Yöntemini Uygulama
Silme onay ekranını görüntüleyen Delete eylem yöntemimizin HTTP-GET sürümü artık uygulandı. Son kullanıcı "Sil" düğmesine tıkladığında /Dinners/Dinner/[id] URL'sine bir form gönderisi gerçekleştirir.
Şimdi aşağıdaki kodu kullanarak silme eylemi yönteminin HTTP "POST" davranışını uygulayalım:
//
// HTTP POST: /Dinners/Delete/1
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id, string confirmButton) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
dinnerRepository.Delete(dinner);
dinnerRepository.Save();
return View("Deleted");
}
Delete eylem yöntemimizin HTTP-POST sürümü, silinecek akşam yemeği nesnesini almaya çalışır. Bulamıyorsa (zaten silinmiş olduğundan) "NotFound" şablonumuzu işler. Akşam Yemeği'ni bulursa, DinnerRepository'den siler. Ardından bir "Silinmiş" şablonu işler.
"Silinmiş" şablonunu uygulamak için eylem yöntemine sağ tıklayıp "Görünüm Ekle" bağlam menüsünü seçeceğiz. Görünümümüzü "Silindi" olarak adlandıracağız ve bunun boş bir şablon olmasını sağlayacağız (kesin olarak belirlenmiş bir model nesnesi almayacağız). Ardından buna bazı HTML içeriği ekleyeceğiz:
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Dinner Deleted
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Dinner Deleted</h2>
<div>
<p>Your dinner was successfully deleted.</p>
</div>
<div>
<p><a href="/dinners">Click for Upcoming Dinners</a></p>
</div>
</asp:Content>
Ve şimdi uygulamamızı çalıştırıp geçerli bir Dinner nesnesinin "/Dinners/Delete/[id]" URL'sine eriştiğimizde, aşağıdaki gibi Akşam Yemeği silme onay ekranımızı işleyecek:
"Sil" düğmesine tıkladığımızda ,/Dinners/Delete/[id] URL'sine bir HTTP-POST gerçekleştirir. Bu url, Akşam Yemeğini veritabanımızdan siler ve "Silinmiş" görünüm şablonumuzu görüntüler:
Model Bağlama Güvenliği
ASP.NET MVC'nin yerleşik model bağlama özelliklerini kullanmanın iki farklı yolunu ele aldık. Birincisi mevcut model nesnesindeki özellikleri güncelleştirmek için UpdateModel() yöntemini, ikincisi ise MVC'nin model nesnelerini eylem yöntemi parametreleri olarak geçirme desteğini kullanarak ASP.NET. Bu tekniklerin ikisi de çok güçlü ve son derece kullanışlıdır.
Bu güç aynı zamanda sorumluluğu da beraberinde getirir. Herhangi bir kullanıcı girişini kabul ederken güvenlik konusunda her zaman paranoyak olmak önemlidir ve bu durum nesneleri form girişine bağlarken de geçerlidir. HTML ve JavaScript ekleme saldırılarını önlemek için kullanıcı tarafından girilen değerleri her zaman HTML ile kodlamaya ve SQL ekleme saldırılarına karşı dikkatli olmanız gerekir (not: Uygulamamız için bu tür saldırıları önlemek için parametreleri otomatik olarak kodlayan LINQ to SQL kullanıyoruz). Hiçbir zaman tek başına istemci tarafı doğrulamaya güvenmemeli ve her zaman size sahte değerler göndermeye çalışan korsanlara karşı koruma sağlamak için sunucu tarafı doğrulamayı kullanmanız gerekir.
ASP.NET MVC'nin bağlama özelliklerini kullanırken düşündüğünüzden emin olmak için ek bir güvenlik öğesi, bağladığınız nesnelerin kapsamıdır. Özellikle, bağlanmasına izin vermekte olduğunuz özelliklerin güvenlik etkilerini anladığınızdan emin olmak ve yalnızca son kullanıcı tarafından güncelleştirilebilir olması gereken özelliklere izin vermek istiyorsunuz.
Varsayılan olarak, UpdateModel() yöntemi model nesnesindeki gelen form parametre değerleriyle eşleşen tüm özellikleri güncelleştirmeyi dener. Benzer şekilde, eylem yöntemi parametreleri olarak geçirilen nesnelerin de varsayılan olarak tüm özellikleri form parametreleri aracılığıyla ayarlanabilir.
Bağlamayı kullanım başına temelinde kilitleme
Güncelleştirilebilecek özelliklerin açık bir "dahil etme listesi" sağlayarak bağlama ilkesini kullanım başına temelinde kilitleyebilirsiniz. Bu, aşağıdaki gibi UpdateModel() yöntemine fazladan bir dize dizisi parametresi geçirilerek yapılabilir:
string[] allowedProperties = new[]{ "Title","Description",
"ContactPhone", "Address",
"EventDate", "Latitude",
"Longitude"};
UpdateModel(dinner, allowedProperties);
Eylem yöntemi parametreleri olarak geçirilen nesneler, aşağıdaki gibi izin verilen özelliklerin "ekleme listesini" etkinleştiren bir [Bind] özniteliğini de destekler:
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create( [Bind(Include="Title,Address")] Dinner dinner ) {
...
}
Bağlamayı tür temelinde kilitleme
Bağlama kurallarını tür temelinde de kilitleyebilirsiniz. Bu, bağlama kurallarını bir kez belirtmenize ve ardından tüm denetleyiciler ve eylem yöntemleri arasında tüm senaryolarda (UpdateModel ve eylem yöntemi parametre senaryoları dahil) uygulanmasını sağlar.
Türe [Bind] özniteliği ekleyerek veya uygulamanın Global.asax dosyasına kaydederek (türün sahibi olmadığınız senaryolar için kullanışlıdır) tür başına bağlama kurallarını özelleştirebilirsiniz. Ardından, belirli bir sınıf veya arabirim için hangi özelliklerin bağlanabileceğini denetlemek için Bind özniteliğinin Include ve Exclude özelliklerini kullanabilirsiniz.
NerdDinner uygulamamızda Dinner sınıfı için bu tekniği kullanacağız ve buna bağlanabilir özelliklerin listesini aşağıdakilerle kısıtlayan bir [Bind] özniteliği ekleyeceğiz:
[Bind(Include="Title,Description,EventDate,Address,Country,ContactPhone,Latitude,Longitude")]
public partial class Dinner {
...
}
RSVP koleksiyonunun bağlama yoluyla yönlendirilmesine izin vermediğimize ve DinnerID veya HostedBy özelliklerinin bağlama aracılığıyla ayarlanmasına izin vermediğimize dikkat edin. Güvenlik nedenleriyle bu özellikleri yalnızca eylem yöntemlerimiz içinde açık kod kullanarak işleyeceğiz.
CRUD Wrap-Up
ASP.NET MVC, form gönderme senaryolarının uygulanmasına yardımcı olan bir dizi yerleşik özellik içerir. DinnerRepository üzerinde CRUD KULLANıCı Arabirimi desteği sağlamak için bu özelliklerin çeşitlilerini kullandık.
Uygulamamızı uygulamak için model odaklı bir yaklaşım kullanıyoruz. Bu, tüm doğrulama ve iş kuralı mantığımızın denetleyicilerimiz veya görünümlerimiz içinde değil model katmanımızda tanımlandığı anlamına gelir. Ne Denetleyici sınıfımız ne de Görünüm şablonlarımız, Dinner model sınıfımız tarafından uygulanan belirli iş kuralları hakkında hiçbir şey bilmiyor.
Bu, uygulama mimarimizi temiz tutar ve test etmemizi kolaylaştırır. Gelecekte model katmanımıza ek iş kuralları ekleyebiliriz ve bunların desteklenmesi için Denetleyicimizde veya Görünümümüzde kod değişikliği yapmak zorunda değiliz . Bu, gelecekte uygulamamızı geliştirmek ve değiştirmek için bize büyük bir çeviklik sağlayacaktır.
DinnersController artık Akşam Yemeği listelerini/ayrıntılarının yanı sıra destek oluşturma, düzenleme ve silmeyi de etkinleştirir. Sınıfın tam kodu aşağıda bulunabilir:
public class DinnersController : Controller {
DinnerRepository dinnerRepository = new DinnerRepository();
//
// GET: /Dinners/
public ActionResult Index() {
var dinners = dinnerRepository.FindUpcomingDinners().ToList();
return View(dinners);
}
//
// GET: /Dinners/Details/2
public ActionResult Details(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
else
return View(dinner);
}
//
// GET: /Dinners/Edit/2
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
return View(dinner);
}
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id= dinner.DinnerID });
}
catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
return View(dinner);
}
}
//
// GET: /Dinners/Create
public ActionResult Create() {
Dinner dinner = new Dinner() {
EventDate = DateTime.Now.AddDays(7)
};
return View(dinner);
}
//
// POST: /Dinners/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Dinner dinner) {
if (ModelState.IsValid) {
try {
dinner.HostedBy = "SomeUser";
dinnerRepository.Add(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new{id=dinner.DinnerID});
}
catch {
ModelState.AddRuleViolations(dinner.GetRuleViolations());
}
}
return View(dinner);
}
//
// HTTP GET: /Dinners/Delete/1
public ActionResult Delete(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
else
return View(dinner);
}
//
// HTTP POST: /Dinners/Delete/1
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id, string confirmButton) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (dinner == null)
return View("NotFound");
dinnerRepository.Delete(dinner);
dinnerRepository.Save();
return View("Deleted");
}
}
Sonraki Adım
Artık DinnersController sınıfımızda temel CRUD (Oluşturma, Okuma, Güncelleştirme ve Silme) desteği uygulanıyor.
Şimdi formlarımızda daha da zengin kullanıcı arabirimini etkinleştirmek için ViewData ve ViewModel sınıflarını nasıl kullanabileceğimize bakalım.