Asp.NET MVC – Tek Form’da Birden Fazla Buton Durumları

Asp.NET MVC mimarisinin, Asp.NET Web Forms mimarisinden daha performanslı ve daha dinamik bir yapı olduğunu hepimiz biliyoruz.Lakin bazı durumlar vardır ki, iki mimari arasındaki doğrusal farkları negatifleyebilir ve Asp.NET Web Forms mimarisindeki kolaylıkları arayabiliriz.Bu yazımızın içeriği bu tarz bir durumdan kaynaklanmaktadır.Bir Asp.NET MVC mimarisiyle oluşturulan projede tek bir formda birden fazla buton varsa eğer nasıl bir kontrol yapabiliriz? sorusunu sormam bana bu içeriği oluşturtmuştur.

Evet, biliyorum.Bazı okurlarımız daha yazıyı tam teşekküllü okumadan; “bunda ne var ki”, “tetikleyen buton isimlerini kontrol edersin olur biter” gibisinden yorumda bulunacaktır.Lakin bu yazımda, tek form içinde bulunan birden fazla butondan hangisinin hangi Action’ı tetikleyeceğini nasıl belirtebileceğimizi göstereceğim.Evet, bunuda farklı algoritmik işlemler neticesinde gerçekleştirebiliriz.Ama ben daha programatik ve profesyonel bir teknik göstereceğim.Tabi ki de, siz okurlarımın başta düşündüğünü varsaydığım basit yapı hakkında da örneklendirmeler yapacağım.Evet şimdi konumuza başlayalım.

Şimdi aşağıdaki iki türlü form yapısını inceleyiniz.

@using (Html.BeginForm("", "", FormMethod.Post))
{
    <input type="submit" value="Buton A" />
    <br />
    <input type="submit" value="Buton B" />
}
Asp.NET MVC - Tek Form'da Birden Fazla Buton Durumları

Kaynak Görüntüsü

@using (Html.BeginForm("OrnekAction", "Home", FormMethod.Post))
{
    <input type="submit" value="Buton A" />
    <br />
    <input type="submit" value="Buton B" />
}
Asp.NET MVC - Tek Form'da Birden Fazla Buton Durumları - 2

Kaynak Görüntüsü

Yukarıda iki farklı form yapısı belirttim ve ikisinin de tarayıcıdaki kaynak çıklatılarının görüntüsünüde paylaştım.Dikkat ederseniz her iki form yapısında iki adet buton bulunmaktadır.Lakin iki form arasındaki fark, birinin action yolu belirtilmemişken, diğerine /Home/OrnekAction adresi belirtilmiştir.

Eğer action yolu belirtilmeyen form yapısında ki her hangi bir butona tıklanırsa eğer boş bir Post – Back işlemi gerçekleşecektir.Action yolu /Home/OrnekAction olarak belirtilen formdaki her hangi bir butona tıklarsak eğer “Home(Controller).cs” isimli Controller sınıfımızdaki “OrnekAction” isimli metodumuz tetiklenecektir.Peki ben bu iki form örneğinde olduğu gibi hangi butonun hangi Action’ı tetikleyeceğini nasıl kontrol edebilirim?İşte bu yazımızda bu iki form örneğine uygun açıklama yapacağız.

Bu işlem bir çok algoritmik teknikle yapılabileceği gibi temelde iki pratik teknik ile gerçekleştirilmektedir.Öncelikle ben yazımızın ana içeriğini oluşturacak olan teknikten yani Attribute oluşturarak çözüm bulmaktan başlamayı istiyorum.

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class CokluButonAttribute : ActionNameSelectorAttribute
    {
        public string Name { get; set; }
        public string Argument { get; set; }

        public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
        {
            var isValidName = false;
            var keyValue = string.Format("{0}:{1}", Name, Argument);
            var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

            if (value != null)
            {
                controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
                isValidName = true;
            }

            return isValidName;
        }
    }

Yukarıdaki “CokluButonAttribute” isimli bir Attribute tanımlamış olduk.Bu Attribute’u kullanabilmek için formumuzun buton nesnelerinde aşağıdaki değişikliği yapmamız gerekmektedir.

@using (Html.BeginForm("", "", FormMethod.Post))
{
    <input type="submit" value="Buton A" name="action:btnA" />
    <br />
    <input type="submit" value="Buton B" name="action:btnB"/>
}

Şimdi buraya kadar ne yaptık, ne ettik bahsetmekte fayda var.Yukarıda yazmış olduğumuz Attribute, bir post işleminde ilgili tetiklemeyi yapan buton nesnesini tanımlamamıza yardımcı olacaktır.Bu tanımlamada kullanacağımız iki Property Attribute’ta mevcuttur.Bunlar kodlarda gördüğünüz gibi Name ve Argument propertyleridir.Formumuzdaki butonlarda yaptığımız güncellemeye bakarsanız eğer, butonların name özelliğine verilen (örn)”action:btnA” komutları, Attribute’umuz da ki Name ve Argument özelliklerini karşılamaktadır.Bu sistem şöyle çalışacaktır.Eğer bir tetikleme işlemi gerçekleşirse Attribute’umuzu devreye sokacağız ve Attribute’ta tanımladığımız buton tetikleme yaptıysa istediğimiz Action’ı çalıştıracağız.

Gelin şimdi bu mantığı pratikte uygulayalım.
“Home(Controller).cs” isimli Controller sınıfımıza aşağıdaki iki Action metodu ekliyorum.

        [HttpPost]
        public ActionResult AAction()
        {
            return View();
        }

        [HttpPost]
        public ActionResult BAction()
        {
            return View();
        }

“btnA” isimli buton tetiklendiğinde “AAction”, “btnB” isimli buton tetiklendiğinde ise “BAction” metodlarımızı tetikleyeceğiz.

        [HttpPost]
        [CokluButon(Argument = "btnA", Name = "action")]
        public ActionResult AAction()
        {
            return RedirectToAction("Index");
        }

        [HttpPost]
        [CokluButon(Argument = "btnB", Name = "action")]
        public ActionResult BAction()
        {
            return RedirectToAction("Index");
        }

Gördüğünüz gibi sistemde bir tetiklenme işlemi olduğu esnada tetiklemeyi yapan buton “CokluButonAttribute” isimli Attribute ile kontrol edilecek ve name özelliğindeki uyan parametrelere göre ilgili Action metod çalıştırılacaktır.

Şimdi bu yapıyı aşağıdaki videodan görsel bir şekilde nasıl çalıştığını görebilirsiniz.

Videoda da gördüğünüz gibi Attribute’umuz cillop gibi çalışmaktadır 🙂

Peki bu Attribute başka Controller’da işlev görür mü? diye sorarsanız eğer bu şekilde pek mümkün değildir.Üzerinde değişiklikler yapmalı ve gerekli Controller’a yönlendirmeyi sağlamalısınız.Bu işlev yazımızın içeriğinden bağımsız olduğu için ödev olarak sizlere bırakıyorum 🙂

Şuana kadar incelediğimiz durum, yazımızın yukarılarında verdiğim form örnekleri için geçerlidir.Yani form başka bir Action yoluna action bildirisi yapmış olsada siz gene istediğiniz butonda istediğiniz Action’ı tetikletebilirsiniz.Ama burada çok dikkatli olmanız gereken bir husus vardır.Eğer formunuzun action’ında bir adres varsa eğer, o adres neticesinde tetiklenecek olan Action metodu da ilgili Attribute ile işaretleyip, hangi buton ile çalışacağını bildirmelisiniz.Aksi taktirde, formunuz Action edildiğinde ilgili Action metod çalışacaktır lakin, diğer actionları çalıştıracak butonlar tetiklendiğinde, Action metodların tetiklenme esnasında çakışması yüzünden hatayla karşılaşacaksınız.

Bu durumu aşağıdaki gibi görselleştirmekte fayda var.

@using (Html.BeginForm("OrnekAction", "Home", FormMethod.Post))
{
    <input type="submit" value="Buton A"  name="action:btnA"/>
    <br />
    <input type="submit" value="Buton B" name="action:btnB" />
}

Gördüğünüz gibi action belirtilmiş bir form oluşturduk.

        [HttpPost]
        [CokluButon(Argument = "btnA", Name = "action")]
        public ActionResult OrnekAction(FormCollection frm)
        {
            return View();
        }

        [HttpPost]
        [CokluButon(Argument = "btnB", Name = "action")]
        public ActionResult BAction()
        {
            return View();
        }

Yukarıda bahsetmek istediğim düzen bu şekilde kurulmalıdır.Formu gönderdiğiniz Action metodu da Attribute ile işaretlemeyi unutmayınız…

Şimdi yazımızın başlarında belirttiğim, siz kullanıcılarımızın olası düşüncesi olan basit işlemimize göz atalım.

@using (Html.BeginForm("OrnekAction", "Home", FormMethod.Post))
{
    <input type="submit" value="Buton A" name="btnA"/>
    <br />
    <input type="submit" value="Buton B" name="btnB" />
}

Gördüğünüz gibi bir formumuz olsun.

        [HttpPost]
        public ActionResult OrnekAction(string btnA, string btnB)
        { 
            if (btnA != null)
            {
                //btnA tetiklendiyse bunları yap...
            }
            else if (btnB != null)
            {
                //btnB tetiklendiyse şunları yap...
            }
            return View();
        }

Tetikleme esnasında Action metodumuza verdiğimiz buton isimleriyle birebir benzer parametrelerle hangi butonun tetiklendiğini kontrol edebiliriz.Tetiklenen buton value değerini dönecektir.Diğeri ise null dönecektir.

Bu şekilde de tek bir Action içinde kontrol yaparak farklı işlemleri gerçekleştirebilirsiniz.Tabi ki ben farklı işlemleri farklı Actionlarda tavsiye ediyorum.

Bir yazımızında sonuna gelmiş bulunmaktayız.
Umarım bol bol faydalanırsınız.
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar diliyorum.

Kaynak : http://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mvc-framework

Bunlar da hoşunuza gidebilir...

3 Cevaplar

  1. Ayhan dedi ki:

    Çalışıyor ancak sayfa geri döndüğünde yani post olduğunda, formun action özniteliğindeki adresi bulamadığı için hata veriyor. Hata çalışmaya engel değil ve ekranda da görünmüyor, geri dönen sayfanın kaynak kodunda görünüyor.

    • Gençay dedi ki:

      Sizden ricam örnek görsel paylaşır mısınız?
      Paylaşımınıza dair en kısa zamanda sebep ve çözüm odaklı bir çalışma gerçekleştirebilirim.

      Sevgiler.

  2. Özge dedi ki:

    Merhaba;

    Öncelikle çok faydalı bir yazı olmuş. Özellikle mvc ye yeni başlayanlar için. Ben sizin anlattığınız gibi oluşturdum ama “controllerContext.Controller.ValueProvider.GetValue(keyValue)” bu değer null geliyor. Bunun nedeni ne olabilir?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*