Sayfalar

18 Mart 2013 Pazartesi

ASP.NET MVC DERSLERİ ( 5.1 ) FORM KULLANIMI

Bu beşinci derste formları ve html-helpers elamanlarını incelemeye çalışacağız. Html-helpers adından da anlaşıldığı gibi HTML kodları ile çalışırken bize yardımcı olacaktır.Html-helper elemanlarını kullanarak HTML elemanlarını daha kolay yazabiliriz. HTML kodlarını yazarken neden yardıma ihtiyacımız olabilir ki, zaten kolay bir etiket yapısı var diyebiliriz.

Aslında HTML elemanları ile alakalı zorlanacağımız kısımlar, link verirken acaba doğru yazdık mı, form elemanları model-binding için doğru isimlere ve değerlere sahip mi, model-binding sırasında hatalar oluşunca hata mesajları vermek gibi konularda gerçekten çok fazla yardıma ihtiyacımız olacak ki, html-helper lar tam da bu noktada çok faydalı olacaktır.

Bütün bu parçaları birleştirmek için HTML etiketlerinden daha fazlasına ihtiyacımız olacaktır. Yani view sayfaları ve çalışma zamanı (run-time) arasında bir koordinasyon gerektirir.

Bu derste bu koordinasyonun nasıl daha kolay yapılacağını anlatmaya çalışacağız. Html-helpers elemanlarını kullanmadan önce form elemanının iyi anlaşılması gereklidir. Form elemanları uygulama içerisinde bizi en çok zorlayacak olan kısım olacağından, en çok bu kısımda html-helpers elemanlarına ihtiyacımız olacaktır.

FORM KULLANIMI

Aklımıza şu gelebilir, altı üstü bir form elemanı ne var bunda bu kadar üzerinde duracak, neden bu konu üzerinde zaman harcayalım, çok mu zor bir konu?

İki sebep var:
  • Form etiketi çok güçlüdür: Eğer form elemanı olmazsa, internet sadece salt okunur (read-only) bir depo olurdu. İnternette arama yapamaz, birşeyler satın alamaz, üye olamazdık... Eğer çok zeki ve kötü niyetli biri dünyadaki tüm web sitelerindeki form elemanlarını çalsa, ertesi gün, internet ile yapılan tüm işlemler çöker...
  • Asp.Net WebForms kullanan bir çok geliştiricinin Mvc framework ü tercih etmesinin sebedir: WebForms framework kullanarak form elemanının tüm gücünü kullanmayı engelleyebilir. WebForms form elemanını kendi amacı için kullanır. Birçok webforms geliştirici form elemanının yeteneğini unutur, ( HTTP GET isteği oluşturmak gibi ) ...
Action ve Method

Form elemanı içerisinde input, checkbox, button, vb gibi elemanları içerisinde bulundurur. Form içerisindeki girdi elemanları, kullanıcılardan bir takım verileri alır ve bu verileri sunucuya postalar. Peki bu postalama işlemi hangi sunucuya nasıl gönderilecek? Bu iki sorunun cevabı form elemanının action ve method nitelikleridir. 

Action niteliği formun nereye postalanacağını belirtir. Bundan dolayıda bu nitelik bir yol (URL) içerir. Bu yol göreceli (relative) veya kesin (absolute) bir yol olabilir. Aşağıdaki örnekte name özelliği q olan bir input elemanı ile google'a bir anahtar kelime yollayarak arama yapmak için kullanılan bir form;
<form action="https://www.google.com.tr/search">
    <input name="q" type="text" />
    <input type="submit" value="Bul" />
</form>

Yukarıda yazdığımız kod içerisinde formun method özelliğini tanımlamadık. Method özelliği formun HTTP POST ile mi yoksa HTTP GET ile mi yollanacağını belirtiyor. Method özelliğini belirlemediğimiz zaman varsayılan olarak HTTP GET ile gönderilir.

Formu HTTP GET ile yollarken tarayıcı isimleri ve değerleri bir sorgu cümlesi (query string) oluşturarak verileri gönderir. Yukarıda kodun tarayıcıdaki görüntüsü: (diyelimki girdiğimiz kelime aliriza adiyahsi)


http://www.google.com.tr/search?q=aliriza+adiyahsi

GET metodu ile mi yoksa POST metodu ile mi?

Form elemanının method özelliğini post olarak da ayarlayabiliriz. Böylece tarayıcı kullanıcı girdilerini query string içerisine koymayacaktır. Bunun yerine HTTP isteğinin gövdesi içerisine koyacaktır. Tarayıcıda adres çubuğunda veriler görünmeyecektir. HTTP Post ile de yukarıdaki örneği yapabiliriz. Ama bu tür işlemlerde HTTP Get metodu tercih edilir. Çünkü tarayıcı üzerinden direk olarak sonuç almak istenebilir. Örneğin, bütün verileri düzenlenmiş, yani sorgu cümlesi (query string) eklenmiş bir linki mail olarak gönderirken HTTP Get metodu çalışır.

Hatta, bu konuda, yani arama, detay, listeleme gibi konularda HTTP Get doğru kullanımdır. Get metodu salt okunur işlemler için kullanılır. Sunucuya sürekli tekrar eden bu tür isteklerde bu metod kullanılmalıdır. Bu işlemler için bu metodu kullanmanın hiç bir tehlikesi yoktur. Çünkü sunucuda hiç bir şeyi değiştirmez (değiştirmemeli).

HTTP Post metodu ise kullanıcı girdileri ile sunucuda birşeyler değiştirmek istendiğinde kullanılır. Kredi kartı bilgilerinin girilmesi, kullanıcı adı ve ya şifre kaydı/değiştirilmesi, vb. gibi... Post metodu tekrar etmeyen/etmemesi gereken işlemler içindir, örneğin iki kere aynı siparişi vermemek gibi. Bazı tarayıcılar, bunu engellemek için bir uyarı mesajı yayınlar. Post metodu ile gönderilen bir formun olduğu sayfada, sayfa tekrardan yenilenirse, tarayıcı bunu yapmak istediğimizi bize sorar. Aşağıdaki pencere Chrome ile ikinci kez post metodunun yenilenmesinde verilen uyarı mesajı ekranıdır.


Kısacası, web uygulamaları genelde okuma işlemleri için GET, yazma işlemeleri (yeni oluşturma, güncelleme, silme) içinse POST metodunu kullanılarlar.

Arama Örneği 1

Uygulamamızda haber başlıkları içerisinde bir arama yapacağımızı farzedelim. HomeController sınıfımız içerisinde aşağıdaki gibi bir arama metodu bulunsun;

/Home/Ara
public ActionResult Ara(string aranacak_kelime)
{
    var haberler = Db.Haberler
    .Where(h => h.Baslik.Contains(aranacak_kelime))
    .Take(10);

    return View(haberler);
}
Bu metoda arama parametresini gönderecek olan form;

Home.cshtml
<form action="/Home/Ara" method="get">
    <input type="text" name="aranacak_kelime" />
    <input type="submit" value="Bul" />
</form>
yukarıdaki kod farklı şekillerde de yazılabilir di ama biz en temel olan üzerinden örnek veriyoruz. Burada Get merodu kullandık. Mvc yapısı form içerisinden gönderilen verinin adı ile controller içerisindeki action metoda geçirilen parametre adını eşleştirir ve gönderilen değer otomatik olarak controller içerisindeki action metoda geçirilir.

Bu parametreyi alan action metod Ara adında bir view döndürecektir, bundan dolayı bir Ara.cshtml adında bir view sayfamız olmalı. Örneğin sayfamızın içeriği aşağıdaki gibi olabilir.

Ara.cshtml
@model IEnumerable<HaberPortalUygulamasi.Models.Haberler>
@{ ViewBag.Title = "Ara"; }
<h2>Sonuçlar</h2>
<table>
    <tr>
        <th>Başlık</th>
        <th>Yazar</th>
        <th>Kategori</th>
    </tr>
    @foreach (var haber in Model) {
        <tr>
            <td>@haber.Baslik</td>
            <td>@haber.Yazarlar.Ad</td>
            <td>@haber.Kategoriler.Ad</td>
        </tr>
    }
</table>

Bu şekilde kolayca arama parametresi gönderilir ve karşılığında sunucudan dönen değerler gösterilir. Ama bütün formlar bu kadar basit değildir. Bu formun gönderildiği adres (/Home/Ara) kırılgandır. Yani web uygulamasını yayınladığımız adresler farklı olduğunda, form göndermek istediği adresi bulamayabilir. Çünkü formun yolunu sabit olarak yazdık.

Arama Örneği 2

Yukarıdaki örnekte form elemanının action niteliğini direk sabit olarak yazmıştık. Bu yolu hesaplayarak yazmak daha iyi bir yöntemdir. Html-helper elemanları bu işi otomatik yapar.
@using (Html.BeginForm("Ara", "Home", FormMethod.Get)) {
    <input type="text" name="aranacak_kelime" />
    <input type="submit" value="Bul" />
}

BeginForm html-helper elemanı yönlendirme motoruna Ara fonksiyonuna nasıl ulaşacağını sorar. Arka tarafta GetVirtualPath() fonksiyonu global.asax içerisinde tanımlanan ve RouteTable içerisinde tutulan yönlendirmeler içerisinde arama yaparak göreceli olan yolu bulur. Tüm bunları html-helper kullanmadan yapsaydık, aşağıdaki gibi yapmamız gerekecekti.
@{
    var context = this.ViewContext.RequestContext;
    var values = new RouteValueDictionary{
        { "controller", "home" }, { "action", "index" }
    };
    var path = RouteTable.Routes.GetVirtualPath(context, values);
}
<form action="@path.VirtualPath" method="get">
    <input type="text" name="aranacak_kelime" />
    <input type="submit" value="Bul2" />
</form>

Son yazdığımız kod ile de göreceli yolu bulmuş oluyoruz. Html-helper sayasinde çok fazla kod yazmaktan kurtulmuş oluyoruz.





14 yorum:

  1. mvc ile ilgili makaleniz gayet güzel ve akıcı.teşekkürler.devamını bekliyoruz:))

    YanıtlaSil
  2. dostum çok güzel paylaşım bir de projeleri ekleyebilir misiniz?

    YanıtlaSil
    Yanıtlar
    1. http://alirizaadiyahsi.blogspot.com/2013/03/aspnet-mvc-dersleri-42-model-guncelleme.html

      Bu yazı için de, siz mi yazdınız bilmiyorum ama, projeleri tek projede birleştirip her yazının sonunda güncel halini paylaşacağım...

      Sil
  3. home.cshtml dosyası ne oluyor. cshtml dosyaları view dosyalarıdır. view dosyaları ise, controller daki methodlara karşılık gelen dosyalardır. controller ile aynı isimde bir view olamaz.

    YanıtlaSil
    Yanıtlar
    1. yani şöyle, olmaz diye biliyorum ben :) olsa da ne işe yarayacak ki,
      hangi method onu çağıracak. controller daki metodlar ile viewlerin aynı isimde olması gerek ya hani. home.cshtml dosyasına karşılık gelen method olması gerekmez mi? yanlış anlamayın, öğrenmek için soruyorum :)

      Sil
    2. public class HomeController : Controller
      {
      public ActionResult Home()
      {
      return View();
      }
      }

      Bu ActionMethod un döndürdüğü HTML sayfası, Home.cshtml dosyası olacaktır. Browser üzerinde de www.domain.com/Home/Home olarak görünecektir.

      Sil
    3. bunda sıkıntı yok. home isminde bir metod olmadan, home isminde bir view olması kafamı karıştırdı.

      Sil
    4. Anlamadığınız, anlatamadığım ve ya yanlış yazılmış birşeyler olunca yazarsanız, düzeltmeye çalışırım... Yanlış anlaşılma olmaz, ilginiz için teşekkür ederim.

      Kolay gelsin.

      Sil
  4. Merhaba, bir view içinde controllera modeli birden fazla kez nasıl gönderebiliriz? Soru tablom ve cevap tablom var. 20 adet standart sorum var bunları tek tek sormak yerine toplu halde bir sayfada doldurtmak istiyorum. Bunu nasıl sağlayabilirim?

    Kolay gelsin.

    YanıtlaSil
    Yanıtlar
    1. soruları listeye atıp liste seklinde view e yollayabilirsiniz.

      Sil
  5. Allah razı olsun adam gibi asp.net mvc le ilgili bilgi veren başka hiçbiyer bulamadım.

    YanıtlaSil
  6. Çok başarılı bir anlatım, devamını bekleriz. Takipçisi olacağım sitenin

    YanıtlaSil