Aracılığıyla paylaş


ViewData Kullanma ve ViewModel Sınıfları Uygulama

Microsoft tarafından

PDF’yi İndir

Bu, ASP.NET MVC 1 kullanarak küçük ama eksiksiz bir web uygulaması oluşturmayı gösteren ücretsiz bir "NerdDinner" uygulama öğreticisinin 6. adımıdır.

6. Adım, daha zengin form düzenleme senaryoları için desteğin nasıl etkinleştirildiğini gösterir ve ayrıca denetleyicilerden görünümlere veri geçirmek için kullanılabilecek iki yaklaşımı ele alır: ViewData ve ViewModel.

ASP.NET MVC 3 kullanıyorsanız , MVC 3 ile Çalışmaya Başlama veya MVC Müzik Deposu öğreticilerini izlemenizi öneririz.

NerdDinner 6. Adım: ViewData ve ViewModel

Çeşitli form sonrası senaryolarını ele aldık ve oluşturma, güncelleştirme ve silme (CRUD) desteğinin nasıl uygulanacağını ele aldık. Şimdi DinnersController uygulamamızı daha ileriye götüreceğiz ve daha zengin form düzenleme senaryoları için destek sağlayacağız. Bunu yaparken, denetleyicilerden görünümlere veri geçirmek için kullanılabilecek iki yaklaşımı ele alacağız: ViewData ve ViewModel.

Denetleyicilerden View-Templates'a Veri Geçirme

MVC düzeninin belirleyici özelliklerinden biri, uygulamanın farklı bileşenleri arasında zorlamaya yardımcı olduğu katı "endişelerin ayrılması"dır. Modellerin, Denetleyicilerin ve Görünümlerin her biri iyi tanımlanmış rollere ve sorumluluklara sahiptir ve birbirleriyle iyi tanımlanmış yollarla iletişim kurar. Bu, test edilebilirliğin ve kodun yeniden kullanılmasının desteklenmesine yardımcı olur.

Denetleyici sınıfı bir HTML yanıtını istemciye geri işlemeye karar verirse, yanıtı işlemek için gereken tüm verilerin açıkça görünüm şablonuna geçirilmesinden sorumludur. Görünüm şablonları hiçbir zaman veri alma veya uygulama mantığı gerçekleştirmemelidir ve bunun yerine kendilerini yalnızca modelden/veriden yönlendirilen işleme kodunun denetleyici tarafından geçirilmesiyle sınırlandırmalıdır.

Şu anda DinnersController sınıfımız tarafından görünüm şablonlarımıza iletilen model verileri basit ve düz bir işlemdir; Index() durumunda Dinner nesnelerinin listesi ve Details(), Edit(), Create() ve Delete() durumunda tek bir Dinner nesnesi. Uygulamamıza daha fazla kullanıcı arabirimi özelliği ekledikçe, görüntüleme şablonlarımız içinde HTML yanıtlarını işlemek için genellikle bu verilerden daha fazlasını geçirmemiz gerekecek. Örneğin, Düzenleme ve Oluşturma görünümlerimizin içindeki "Ülke" alanını HTML metin kutusu yerine açılan liste olarak değiştirmek isteyebiliriz. Görünüm şablonundaki ülke ve bölge adlarının açılan listesini sabit olarak kodlamak yerine, dinamik olarak dolduracağımız desteklenen ülkeler ve bölgeler listesinden oluşturmak isteyebiliriz. Hem Dinner nesnesini hem de desteklenen ülke ve bölge listesini denetleyicimizden görünüm şablonlarımıza geçirmek için bir yönteme ihtiyacımız olacak.

Bunu başarmanın iki yolunu inceleyelim.

ViewData Sözlüğü'nü kullanma

Denetleyici temel sınıfı, Denetleyicilerden Görünümler'e ek veri öğeleri geçirmek için kullanılabilecek bir "ViewData" sözlük özelliği sunar.

Örneğin, Düzenleme görünümümüzdeki "Ülke" metin kutusunu HTML metin kutusu yerine açılan liste olarak değiştirmek istediğimiz senaryoyu desteklemek için Edit() eylem yöntemimizi bir "Ülkeler" açılan listesinin modeli olarak kullanılabilecek bir SelectList nesnesi geçirecek şekilde güncelleştirebiliriz (Akşam Yemeği nesnesine ek olarak).

//
// GET: /Dinners/Edit/5

[Authorize]
public ActionResult Edit(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    ViewData["Countries"] = new SelectList(PhoneValidator.AllCountries, dinner.Country);

    return View(dinner);
}

Yukarıdaki SelectList'in oluşturucusunun, açılan listenin doldurulacak ülke ve bölgelerin listesini ve seçili durumdaki değeri kabul ediyor.

Daha sonra Edit.aspx görünüm şablonumuzu, daha önce kullandığımız Html.TextBox() yardımcı yöntemi yerine Html.DropDownList() yardımcı yöntemini kullanacak şekilde güncelleştirebiliriz:

<%= Html.DropDownList("Country", ViewData["Countries"] as SelectList) %>

Yukarıdaki Html.DropDownList() yardımcı yöntemi iki parametre alır. İlki, çıkış yapılacak HTML form öğesinin adıdır. İkincisi, ViewData sözlüğü aracılığıyla geçtiğimiz "SelectList" modelidir. Sözlük içindeki türü SelectList olarak değiştirmek için C# "as" anahtar sözcüğünü kullanıyoruz.

Şimdi de uygulamamızı çalıştırıp tarayıcımızdan /Dinners/Edit/1 URL'sine eriştiğimizde düzenleme kullanıcı arabirimimizin metin kutusu yerine ülkelerin ve bölgelerin açılan listesini görüntüleyecek şekilde güncelleştirildiğini göreceğiz:

Ülke ve bölgelerin açılan listesinin kırmızı okla vurgulandığı kullanıcı arabirimini düzenleme işleminin ekran görüntüsü.

Düzenleme görünümü şablonunu HTTP-POST Düzenleme yönteminden de işlediğimizden (hataların oluştuğu senaryolarda), görünüm şablonu hata senaryolarında işlendiğinde SelectList'i ViewData'ya eklemek için bu yöntemi de güncelleştirdiğimizden emin olmak isteriz:

//
// POST: /Dinners/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    try {
    
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {
    
        ModelState.AddModelErrors(dinner.GetRuleViolations());

        ViewData["countries"] = new SelectList(PhoneValidator.AllCountries, dinner.Country);

        return View(dinner);
    }
}

Ve şimdi DinnersController düzenleme senaryomuz DropDownList'i destekliyor.

ViewModel Deseni Kullanma

ViewData sözlük yaklaşımı, oldukça hızlı ve kolay uygulanabilir olmanın avantajına sahiptir. Ancak bazı geliştiriciler dize tabanlı sözlükleri kullanmayı sevmez, çünkü yazım hataları derleme zamanında yakalanmayacak hatalara yol açabilir. Yazılmamış ViewData sözlüğü, görünüm şablonunda C# gibi kesin olarak belirlenmiş bir dil kullanırken "as" işlecini veya atamayı da gerektirir.

Kullanabileceğimiz alternatif bir yaklaşım genellikle "ViewModel" deseni olarak adlandırılır. Bu düzeni kullanırken, belirli görünüm senaryolarımız için iyileştirilmiş ve görünüm şablonlarımız için gereken dinamik değerler/içerik için özellikleri kullanıma sunan kesin türe sahip sınıflar oluştururuz. Ardından denetleyici sınıflarımız bu görünüm için iyileştirilmiş sınıfları doldurabilir ve kullanmak üzere görünüm şablonumuza geçirebilir. Bu, görünüm şablonları içinde tür güvenliği, derleme zamanı denetimi ve düzenleyici IntelliSense'i etkinleştirir.

Örneğin, akşam yemeği formu düzenleme senaryolarını etkinleştirmek için aşağıda olduğu gibi, kesin olarak belirlenmiş iki özelliği kullanıma sunan bir "DinnerFormViewModel" sınıfı oluşturabiliriz: Bir Dinner nesnesi ve "Ülkeler" açılan listesini doldurmak için gereken SelectList modeli:

public class DinnerFormViewModel {

    // Properties
    public Dinner     Dinner    { get; private set; }
    public SelectList Countries { get; private set; }

    // Constructor
    public DinnerFormViewModel(Dinner dinner) {
        Dinner = dinner;
        Countries = new SelectList(PhoneValidator.AllCountries, dinner.Country);
    }
}

Ardından, depomuzdan aldığımız Dinner nesnesini kullanarak DinnerFormViewModel oluşturmak için Edit() eylem yöntemimizi güncelleştirebilir ve ardından görünüm şablonumuza geçirebiliriz:

//
// GET: /Dinners/Edit/5

[Authorize]
public ActionResult Edit(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);
    
    return View(new DinnerFormViewModel(dinner));
}

Ardından, edit.aspx sayfasının üst kısmındaki "inherits" özniteliğini şöyle değiştirerek görünüm şablonumuzu "Dinner" nesnesi yerine "DinnerFormViewModel" olmasını bekleyecek şekilde güncelleştireceğiz:

Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerFormViewModel>

Bunu yaptıktan sonra, görünüm şablonumuzdaki "Model" özelliğinin IntelliSense değeri, geçirdiğiniz DinnerFormViewModel türünün nesne modelini yansıtacak şekilde güncelleştirilir:

Açılan listenin ve Akşam Yemeği listesi öğesinin mavi dikdörtgenle vurgulandığı kod düzenleyicisi penceresinin ekran görüntüsü.

Açılan listenin ve Adres listesi öğesinin gri noktalı dikdörtgenle vurgulandığı kod düzenleyicisi penceresinin ekran görüntüsü.

Daha sonra görünüm kodumuzu güncelleştirerek bu kodun çalışmasını sağlayabiliriz. Oluşturduğumuz giriş öğelerinin adlarını değiştirmediğimize (form öğelerinin adı hala "Başlık", "Ülke") nasıl değiştirdiğimize aşağıda dikkat edin; ancak DinnerFormViewModel sınıfını kullanarak değerleri almak için HTML Yardımcısı yöntemlerini güncelleştiriyoruz:

<p>
    <label for="Title">Dinner Title:</label>
    <%= Html.TextBox("Title", Model.Dinner.Title) %>
    <%=Html.ValidationMessage("Title", "*") %>
</p>

<p>
    <label for="Country">Country:</label>
    <%= Html.DropDownList("Country", Model.Countries) %>                
    <%=Html.ValidationMessage("Country", "*") %>
</p>

Hataları işleme sırasında DinnerFormViewModel sınıfını kullanmak için Edit post yöntemimizi de güncelleştireceğiz:

//
// POST: /Dinners/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    try {
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {
        ModelState.AddModelErrors(dinner.GetRuleViolations());

        return View(new DinnerFormViewModel(dinner));
    }
}

Ayrıca Create() eylem yöntemlerimizi güncelleştirerek aynı DinnerFormViewModel sınıfını yeniden kullanarak "Countries" DropDownList'i de bu sınıflar içinde etkinleştirebiliriz. HTTP-GET uygulaması aşağıdadır:

//
// GET: /Dinners/Create

public ActionResult Create() {

    Dinner dinner = new Dinner() {
        EventDate = DateTime.Now.AddDays(7)
    };

    return View(new DinnerFormViewModel(dinner));
}

HTTP-POST Create yönteminin uygulaması aşağıdadır:

//
// 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.AddModelErrors(dinner.GetRuleViolations());
        }
    }

    return View(new DinnerFormViewModel(dinner));
}

Şimdi hem Düzenle hem de Oluştur ekranlarımız, ülkeyi veya bölgeyi seçmek için açılan listeleri destekliyor.

Özel şekilli ViewModel sınıfları

Yukarıdaki senaryoda, DinnerFormViewModel sınıfımız dinner modeli nesnesini bir özellik olarak ve destekleyici bir SelectList model özelliği olarak doğrudan kullanıma sunar. Bu yaklaşım, görünüm şablonumuzda oluşturmak istediğimiz HTML kullanıcı arabiriminin etki alanı modeli nesnelerimize görece yakın olduğu senaryolarda düzgün çalışır.

Bu durumun söz konusu olmadığı senaryolarda kullanabileceğiniz bir seçenek, nesne modeli görünüm tarafından kullanım için daha iyileştirilmiş olan ve temel alınan etki alanı modeli nesnesinden tamamen farklı görünebilen özel şekilli bir ViewModel sınıfı oluşturmaktır. Örneğin, birden çok model nesnesinden toplanan farklı özellik adlarını ve/veya toplama özelliklerini ortaya çıkarabilir.

Özel şekilli ViewModel sınıfları, hem denetleyicilerden işlenecek görünümlere veri geçirmek hem de denetleyicinin eylem yöntemine geri gönderilen form verilerini işlemeye yardımcı olmak için kullanılabilir. Bu sonraki senaryoda, eylem yönteminin bir ViewModel nesnesini form tarafından gönderilen verilerle güncelleştirmesini ve ardından gerçek bir etki alanı modeli nesnesini eşlemek veya almak için ViewModel örneğini kullanmasını isteyebilirsiniz.

Özel şekilli ViewModel sınıfları çok fazla esneklik sağlayabilir ve görüntüleme şablonlarınızda işleme kodunu veya eylem yöntemlerinizin içindeki form gönderme kodunu her bulduğunuzda çok karmaşık hale geldiğinde araştırılması gereken bir şeydir. Bu genellikle etki alanı modellerinizin oluşturduğunuz kullanıcı arabirimine net bir şekilde karşılık gelmez ve ara özel şekilli ViewModel sınıfının yardımcı olabileceğinin bir işaretidir.

Sonraki Adım

Şimdi uygulamamız genelinde kullanıcı arabirimini yeniden kullanmak ve paylaşmak için kısmi ve ana sayfaları nasıl kullanabileceğimize bakalım.