Makale Özeti

Bu yazımızda ASP.NET MVC uygulamalarında kendi yardımcı HTML metotlarını nasıl oluşturabileceğimizi ve View nesneleri içerisinden bu metotları nasıl kullanabileceğimizi inceleyeceğiz. Basit bir HTML Helper metodunu nasıl oluşturacağımızı göreceğimiz gibi, karmaşık yapıdaki bir listenin nasıl html table elementine dönüştürüleceğine de makalenin sonunda göz atacağız.

Makale

Önceki yazılarımızda da belirttiğimiz gibi ASP.NET MVC uygulamalarında WebForm'larındaki sunucu kontrollerini kullanamıyoruz. Bu modelde kod yazımı klasik ASP uygulamalarında olduğu gibi HTML kodun içerisine yazılan sunucu taraflı çalışan kod parçalarından oluşmaktadır. İşimizi kolaylaştırmak adına HTML Helper adını verdiğimiz yardımcı metotlar HTML içerisinde ihtiyacımız olan kodların basit şekilde oluşturulmasını sağlar. ASP.NET MVC - Html Helper Metotlarının Kullanımı başlıklı yazımda MVC uygulamaları için halihazırda gelen yardımcı metotları nasıl kullanabileceğimizi incelemiştik. Bu yazımıda da kendi özel HTML Helper metotlarımızı nasıl yazabileceğimize ve nasıl kullanabileceğimize göz atacağız.

HTML Helper metotları View nesneleri içerisinden erişilebilen Html adındaki bir nesne üzerinden çağrılabilen metotlardır. Örneğin <%=Html.TextBox("txtIsim", "Adınızı girin...") %> şeklindeki bir metot çağrımı sayfamızda txtIsim adında bir metin kutusu (text input elemanı) oluşturulmasını ve içerisinde Adınızı girin... metninin eklenmesini sağlar. Bu işlemi aslında biz de manuel olarak html elementleri yazarak oluşturabiliriz ancak bu kontrollerin içeriklerini dinamik şekilde oluşturmak için HTML Helper metotları işlerimizi basitleştirecektir. Bu doğrultuda eğer kendi yardımcı HTML metotlarımızı geliştirecek olursak farklı farklı projelerde kullanma ve geliştirme sürecini kısaltma şansımız da olacaktır.

Aslında burada oluşturacağımız metot hemen hemen her projede yazdığımız tarzda metotlardan biri olacaktır. Basit olarak geriye HTML kodları döndüren bir metot oluşturmak, görevimiz bu! Tabi ki WebForm'larda bu tarz ihtiyaçlarımız olmadığı için biraz bu tip metotları yazmaya uzak kaldığımızı söyleyebiliriz. Bir de oluşturulması oldukça karmaşık olan veri kontrollerinin HTML çıktılarını ayarlamak, gerekli iş mantığını bu metotlar içerisinde kodlamak oldukça zahmetli bir işlem olacaktır. Biz yazımızda öncelikli olarak basit bir HTML helper metodunu nasıl oluşturabileceğimizi, ardından da veri saklayan bir nesneyi html table elementi olarak çıktıya nasıl dönüştürebileceğimizi göreceğiz.

HTML helper metotlarını doğrudan kendi yazdığımız özel bir sınıf içerisinde oluşturabiliriz. Burada nesneyi örnekleme ihtiyacımız olmayacağı için static bir metot oluşturmak daha doğru bir pratik olacaktır. Aşağıda html span elementi oluşturan bir yardımcı html metodu yer alıyor. Projemize HtmlHelperKutuphanem.cs adında bir class dosyası ekliyoruz.

HtmlHelperKutuphanem.cs

public class HtmlHelperKutuphanem

{

    public static string Metin(string text, string renk)

    {

        return string.Format("<span style=\"color:{0}\">{1}</span>", renk, text);

    }

}

NOT: ASP.NET MVC uygulama template'i bir Web Application olduğu için oluşturulan class'lar namespace altında yer alır. View nesnelerinden yardımcı metotlarınızı çağırırken NamespaceAdi.ClassAdi.MetotAdi şeklinde uzunca bir söz dizimi kullanmak istemiyorsanız, oluşturduğunuz class'ın dışındaki namespace tanımlamasını kaldırabilirsiniz. Ben bu örnekteki tüm class'lar için bu şekilde ilerleyeceğim!

Görüldüğü gibi son derece basit bir metot. Kendisine gönderilen text parametresinin içeriğini, renk parametresinde belirtilen renk kodu ile bir span elementi içerisinde görüntüleyecektir. Metodu View nesnelerimizden çağırma işlemi de aşağıda görüldüğü gibi olacaktır.

Views/Home/Index.aspx

<%=HtmlHelperKutuphanem.Metin("Merhaba Dünya", "#FF0000") %>

Sayfanın çıktısına baktığımızda ise;

<span style="color:#FF0000">Merhaba Dünya</span>

şeklinde olacağını göreceğiz. Bunu zaten bizde normal HTML kodlarını yazarak yapabiliriz dediğinizi duyar gibiyim, ama işin şu kısmını unutmamak lazım; kod içerisinde dinamik işlem yapmak istediğiniz durumlarda for-foreach gibi döngülerin içinde HTML kodunu string olarak yazmaktansa, bir programlama öğesi olan metotları kullanmak daha hızlı, daha basit ve  etkili olacaktır. Dikkat ettiyseniz burada yazdığımız yardımcı HTML metodumuz kendi özel class'ımız içerisinde olduğu için, metodu çağırırken de bu class adını kullanmak zorunda kaldık. Ancak ASP.NET MVC'deki tüm HTML Helper metotlara Html adındaki bir özellik(property) üzerinden erişilebilir. Bu özellik aslında o anki context üzerinden HtmlHelper tipinden bir nesne döndürmektedir.  O zaman yazacağımız özel metotlarımızı HtmlHelper class'ının  bir üyesi olarak getirmek işi standartlaştırmak adına faydalı olacaktır. Ancak varolan bir class'ın içerisine kendi yazdığımız metodu nasıl ekleyeceğiz? Eğer C# 3.0(veya VB.NET 9.0) ile gelen yenilikleri henüz inceleme şansınız olmadıysa bu işlemi yapmanın mümkün olmadığını düşünebilirsiniz.

C# 3.0 ile gelen yeniliklerden olan Extension Method özelliği sayesinde varolan sınıflara kendi yazdığımız metotların uzantı olarak eklenmesini sağlayabiliyoruz. Bu yazımızın konusu değil ama Extension Method konusunda daha detaylı bilgi almak isterseniz bu linkteki yazıyı inceleyebilirsiniz. Eğer oluşturacağımız yardımcı HTML metodu HtmlHelper class'ı içerisine uzantı olarak ekleyebilirsek Html.Metin şeklinde metodumuzu çağırabiliriz. Bu da yardımcı metotların bütün olarak tek bir nesne altında saklanması açısından kullanışlı ve standartlara uygun olacaktır. Aşağıdaki kod parçasında az önce yazdığımız Metin adındaki metodun nasıl HtmlHelper class'ına uzantı bir metot olarak eklendiği görülmektedir. Burada dikkat edilmesi gereken hususlar; class'ın static olması, metodun static olması ve metodun ilk parametresinin this anahtar kelimesi ile HtmlHelper class'ını işaret etmesidir. Projemize HtmlHelperExtensions.cs adında bir class dosyası ekliyoruz.

HtmlHelperExtensions.cs

using System.Web.Mvc;

 

public static class HtmlHelperExtensions

{

    public static string Metin(this HtmlHelper htmlHelper, string text, string renk)

    {

        return string.Format("<span style=\"color:{0}\">{1}</span>", renk, text);

    }

}

Böylece artık Html özelliği üzerinden Metin adındaki yardımcı HTML metodumuzu çağırabileceğiz.

Bu basit metotla nasıl kendi HTML Helper metotlarımızı oluşturup kullanabileceğimizi gördük. Peki biraz daha karmaşık yapısı olan bir HTML çıktıları nasıl oluşturabiliriz? Aklımız hemen WebForm'lardaki GridView vb. kontrollerde olduğu gibi HTML çıktıları oluşturmaya gidiyor olabilir ama bu o kadar da kolay olmayacaktır. O zaman bizde elimizde bulunan bir liste koleksiyonun içeriğini table elementi olarak oluşturan bir yardımcı metodu nasıl oluşturabileceğimize bakalım. Dilerseniz ilk olarak basit bir table oluşturmayı deneyip, ardından daha karmaşık yapıdaki nesneleri nasıl table içerisinde listeletebiliriz bunun yollarını arayalım. İlk senaryomuz string dizisi içerisinde saklanan bilgileri tek hücreli bir tabloya yazdırmak olsun. Aşağıda bu işlemi gerçekleştiren SimpleTable adındaki extension method'umuz yer almaktadır.

HtmlHelperExtensions.cs

using System.Web.Mvc;

using System.Text;

 

public static class HtmlHelperExtensions

{

    public static string Metin(this HtmlHelper htmlHelper, string text, string renk)

    {

        return string.Format("<span style=\"color:{0}\">{1}</span>", renk, text);

    }

 

    public static string SimpleTable(this HtmlHelper htmlHelper, string[] list)

    {

        StringBuilder tablo = new StringBuilder();

        tablo.AppendLine("<table>");

 

        //Dizi içerisindeki tüm elemanları tek tek okuyarak bir satır ve sütun olarak oluşturuyoruz

        foreach (string item in list)

        {

            tablo.Append("<tr><td>");

            tablo.Append(item);

            tablo.AppendLine("</td></tr>");

        }

        tablo.Append("</table>");

 

        return tablo.ToString();//Oluşan HTML kodları geri döndürüyoruz

    }

}

SimpleTable metodu çok basit bir şekilde kendisine gönderilen list adındaki string dizisi içerisindeki elemanları bir döngü içerisinde tek tek okuyarak tabloya eklenen satır ve hücreler içerisine ekliyor. Oluşan tablonun HTML kodlarını da geriye döndürüyor. İş mantığı normal uygulamalarda yazdığımız gibi, olayın sadeliği ise bu metodu artık Html nesnesi üzerinden tekrar tekrar farklı View nesneleri içerisinde kullanabilmemizden geliyor.

Peki HTML çıktıyı biraz daha karmaşık hale getirelim. Senaryomuz şu olsun; elimizde içerisinde aynı tipten nesneler saklayan generic bir liste koleksiyonumuz olsun, ve biz de bu koleksiyondaki tüm nesnelerin özelliklerini table elementi içerisine birer hücre olarak yazdıralım. Örneğin kendi oluşturduğumuz Product tipindeki nesneleri saklayan generic List koleksiyonumuzun içeriğindeki tüm ürünleri ve ürünlerin detaylarını(yani property değerlerini) tablo içerisinde görüntülemek istiyoruz. Tahmin edeceğiniz üzere oluşturacağımız metot Product gibi bir tipe bağımlı kalmayacak, bazen Customer, bazen Order gibi farklı nesneleri de görüntülemek isteyecektir. Bu doğrultuda metodun içerisinde çalışma zamanında(runtime) liste içerisindeki tipin yapısını çözümlemek ve property değerlerine göre tablo hücrelerini oluşturmamız gerekecektir. Yani burada reflection(yansıma) tiplerine ihtiyaç duyacağız. Geliştireceğimiz metot aşağıdaki gibi olacaktır. Yapılan işlemlerle ilgili kısa açıklamalar kod içerisindeki yorum satırlarında yer alıyor.

HtmlHelperExtensions.cs
using System.Web.Mvc;

using System.Text;

using System.Collections;

using System.Reflection;

 

public static class HtmlHelperExtensions

{

    ...

 

    public static string Table(this HtmlHelper htmlHelper, IList list, bool showHeader)

    {

        //Eğer liste boş ise boş bir string döndür

        if (list.Count == 0)

            return string.Empty;

 

        StringBuilder tablo = new StringBuilder();

        tablo.AppendLine("<table>");

        //Tabloda başlık görüntülensin isteniyorsa ilk satırımız property'lerin isimleri olacaktır.

        //Bu doğrultuda koleksiyonun ilk satırındeki nesnenin property bilgilerine bakarak başlık satırı oluşturuluyor

        if (showHeader)

        {

            object firstItem = list[0];

            tablo.Append("<tr>");

            //GetType metodu bir nesnenin type bilgisini getirir.

            //Bu değer üzerinden GetProperties metodu ile nesnenin property listesine erişilebilir

            foreach (PropertyInfo property in firstItem.GetType().GetProperties())

            {

                tablo.Append("<td>");

                tablo.Append(property.Name); //Property'nin adı

                tablo.Append("</td>");

            }

            tablo.AppendLine("</tr>");

        }

 

        foreach (object item in list) //Liste içerisindeki nesnelerin özelliklerini satır satır oluştur

        {

            tablo.Append("<tr>");

            foreach (PropertyInfo property in item.GetType().GetProperties())

            {

                tablo.Append("<td>");

                tablo.Append(property.GetValue(item, null).ToString()); //GetValue metodu property'deki değeri getirir

                tablo.Append("</td>");

            }

            tablo.AppendLine("</tr>");

        }

        tablo.AppendLine("</table>");

 

        return tablo.ToString(); //Oluşan HTML kodları geri döndür

    }

}

Yardımcı HTML metodumuzu oluşturduk. Etkin şekilde kullanımını incelemek için öncelikli olarak kendimize Product adında bir class oluşturup, ardından da bir List koleksiyonu için Index.aspx adındaki View nesnemizden bu metodu çağıralım. Aşağıda Product adındaki class'ımız ve Views/Home/Index.aspx dosyasına eklediğimiz kodlar yer almaktadır.

Product.cs
public class Product

{

    //Burada C# 3.0 ile gelen auto implemented property özelliğini kullanıyoruz.

    //Yani field ve get-set bloklarının gövdelerini oluşturmadan property tanımlıyoruz.

    public int Id

    {

        get; set;

    }

    public string Name

    {

        get; set;

    }

    public double Price

    {

        get; set;

    }

}

 

 

Views/Home/Index.aspx
<%

    List<Product> urunListe = new List<Product>{

                                new Product { Id=2, Name="Kalem", Price=1.25},

                                new Product { Id=4, Name="Defter", Price=3.49},

                                new Product { Id=5, Name="Çanta", Price=19.25}

                                };

    Response.Write(Html.Table(urunListe,true));

%>

View'ı görüntülediğimizde aşağıdaki gibi bir çıktıyı görebiliriz.

Gördüğünüz gibi hazırlayacağımız yardımcı HTML metotlarını Html özelliği içerisinde saklayarak MVC projelerimizde daha kolay HTML çıktılar oluşturabilmekteyiz. Şu an için MVC uygulamalarında kullanabileceğimiz herhangi bir sunucu kontrolü bulunmamaktadır, ancak yakın gelecekte bazı temel kontrollerin bu ortama dahil edilmesi planlanmakta. Bu süreçte MVC uygulamaları için kendi HTML Helper metotlarımızı üreterek sunucu kontrollerinin olmamasından ortaya çıkan dezavantajı giderebiliriz. Bir başka makalede görüşmek dileğiyle.


Uğur UMUTLUOĞLU
Microsoft MVP(ASP.NET)
www.umutluoglu.com
www.nedirtv.com