ASP.NET 5 Tag Helpers - Etiket Yardımcıları

28. Ekim 2015

ASP.NET MVC ile Razor View Engine ilk çıktığında HTML helpers ile tanıştık ve MVC projelerinde yoğun olarak HTML Helper metodlarını kullandık, kullanımı kolaylaştırmak için kendi yardımcı metodlarımızı yazdık. ASP.NET MVC ile alakalı pek çok soru ve takıldığımız pek çok nokta HTML Helper kullanımı ile alakalı oldu. HTML'nin basitliğinden ve yıllardır tecrübe ettiğimiz etiketler ile attributelerden uzaklaştık. Yerine HTML Helper metodlarına geçilen parametrelerle boğuşmaya başladık. Şahsen hala ASP.NET MVC'de HTML Helper ile oluşturacağım bir linke class attribute'u verirken zorlanmıyor değilim.

İşte bu noktada Tag Helpers - etiket yardımcıları ile biz geliştiricilerin yardımına biraz geçte olsa yetişilmiş oldu. Tag Helpers temelde bize kullanım kolaylığından başka yeni bir şey sunmuyor. Razor HTML yardımcıları ile yazabildiğimiz kodu, tag helpers ile daha markup diline yakın olarak yazabiliyoruz, View'larımız daha okunabilir oluyor. Dolayısıyla anlaması ve geliştirmesi daha kolay hale geliyor. ASP.NET 5 ile gelen etiket yardımcılarına ek olarak istersek kendi etiket yardımcılarımızı geliştirebiliyoruz, ki bu kısım bence konunun en heyecan veren yeri.

Bu yazıda öncelikle ASP.NET 5 ile gelen varsayılan etiket yardımcılarına değinip, sonrasında kendi etiket yardımcımızı nasıl yazacağımız ve kullanacağımız üzerinde durmaya çalışacağım.

 

ASP.NET 5 Varsayılan Etiket Yardımcıları

Aşağıdaki kod bloğunda etiket yardımcıları olmadan HTML yardımcıları yardımı ile basit bir view örneği görüyoruz. Buradaki HTML yardımcıları ile oluşturduğumuz üç elemana dikkat edelim. Bir textbox, bir checkbox ve bir link elemanı oluşturuyoruz.

 

@model ASP_NET_5_TagHelpers.Models.ToDoListItem

<label>Açıklama : </label>
@Html.TextBoxFor(m => m.Text)
<br />

<label>Tamamlandı mı ? : </label>
@Html.CheckBoxFor(m => m.IsCompleted, new { id = "todolistitem" + Model.ItemId })
<br />

@Html.ActionLink("Tag Helper Kullanılmış Sayfaya Git", "WithTagHelper", "Home")

 

 Şimdi aynı örneği ASP.NET 5 ile gelen varsayılan etiket yardımcıları ile yapalım. ASP.NET 5 ile gelen varsayılan etiket yardımcılarını kullanmak için yapmamız gereken tek şey @addTagHelper emri ile etiket yardımcılarının bulunduğu assembly'i referans göstermek. Böylece aşina olduğumuz HTML etiketlerine etiket yardımcıları ile gelen ek attibute'ları kullanarak view'ımızı hazırlayabiliyoruz. 

 

@model ASP_NET_5_TagHelpers.Models.ToDoListItem
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
    
<label>Açıklama : </label>
<input type="text" asp-for="Text" /><br>

<label>Tamamlandı mı ? : </label>
<input type="checkbox" asp-for="IsCompleted" id="@String.Format("todolistitem{0}", Model.ItemId)" /><br />

<a asp-controller="Home" asp-action="WithoutTagHelper">Tag Helper Kullanılmamış Sayfaya Git</a>

 Örnekte bulunan input elemanlarına tanımladığımız asp-for attributelarına dikkat edelim. Bunlar elemanın, modelin hangi özelliği ile eşleşeceğini belirtiyor. Link elemanına gelen asp-controller ve asp-action attributelarına dikkat edelim, bunlar da link elemanının hangi controller'ın hangi aksiyonu çalışacağını belirtiyoruz. İşler oldukça basitleşmiş ve okunabilir hale gelmiş değil mi ? 

Kendi Etiket Yardımcımızı Geliştirelim

 ASP.NET 5 ile gelen varsayılan etiket yardımcılarının yanı sıra kendi etiket yardımcımızı yazabilmemizi sağlayan sınıflar da mevcut. Microsoft.AspNet.Razor.Runtime.TagHelpers isim alanı altındaki TagHelper sınıfından türeteceğimiz sınıflar vasıtasıyla kendi etiket yardımcımızı geliştirebiliyoruz. Sınıfın public özellikleri view'da kullanacağımız elemanın attibutelarına karşılık geliyor. Process metodu içerisinde ise sayfamız istemciye gönderilirken nasıl render edilmesini istiyorsak öyle HTML elemanları tanımlayarak çıktımızı üretebiliriz.

Örneğin aşağıdaki Bootstrap input group örneğini ele alalım. 

<div class="input-group">
    <input type="text" class="form-control" placeholder="Recipient's username" aria-describedby="basic-addon2">
    <span class="input-group-addon" id="basic-addon2">@@example.com</span>
</div>

 Bu kod bloğunu, tekrar kullanılabilir bir etiket yardımcısına aşağıdaki gibi çevirebiliriz. InputGroupTagHelper sınıfının Id ve Domain özelliklerine dikkat edin. Bunları daha sonra view dosyamızda attribute olarak kullanacağız.

public class InputGroupTagHelper : TagHelper
{
	public string Id { set; get; }

	public string Domain { set; get; }

	public override void Process(TagHelperContext context, TagHelperOutput output)
	{
		// Outer Tag : 
		output.TagName = "div";
		output.Attributes.Add("class", "input-group");

		// Inner Input : 
		var name = new TagBuilder("input");
		name.MergeAttribute("type", "text");
		name.MergeAttribute("class", "form-control");
		name.MergeAttribute("placeholder", "Recipient's username");
		name.MergeAttribute("aria-describedby", this.Id);

		// Span : 
		var span = new TagBuilder("span");
		span.MergeAttribute("class", "input-group-addon");
		span.MergeAttribute("id", this.Id);
		span.InnerHtml = this.Domain;
		
		output.Content.SetContent(name.ToString() + span.ToString());
	}
}

Tanımladığımız etiket yardımcısını view dosyasında aşağıdaki gibi kullanabiliriz : 

@addTagHelper "*, ASP_NET_5_TagHelpers"

<input-group id="basic-addon2" domain="@@gmail.com"></input-group>
 

 

 

Sonuç

Bu yazımda ASP.NET 5 ile gelen tag helpers - etiket yardımcılarını incelemeye çalıştık. Şuan ASP.NET 5 Beta versiyonu olduğu için kod örneklerinde eklemeler ve çıkarmalar olabilir. Hatta bazı HTML elemanlarında varsayılan etiket yardımcılarının istenen şekilde çalışmadığını gördüm. Final sürümünde daha stabil olacaktır. Yazımda bahsettiğim örneklere aşağıdaki github linkinden ulaşabilirsiniz.

ASP.NET 5 TagHelpers Örnekleri

 

asp.net , , ,

IBundleOrderer İle Bundle İçerisindeki Dosyaların Sıralanması

28. Ocak 2013

Geçtiğimiz haftalarda incelediğim Bundling ve Minification yazısında bir dizin içerisindeki kaynak dosyalarımızı joker karakterler ile bir bundle haline getirip sayfamıza ekleyebileceğimizden bahsetmiştik. Bu dizin içerisindeki tüm dosyalar alfabetik sırada bundle içerisinde işlenir ve referans olarak verilen yerlerde bu sıralamada istemciye sunulur. Çoğu zaman bu tercih edilen bir durum değildir. Bazı temel script dosyalarımızın sayfamızda öncelikli olarak referans verilmesini isteriz. Bu temel script dosyalarını kullanan diğer script dosyalarımız ise sonrasında sayfamıza eklenir. İşte bu kurduğumuz hiyerarşik yapıyı oluşturacağımız bundle'lar içerisinde de yapabilmemiz için ya dosya isimlerini alfabetik olarak yarattığımız hiyerarşiye uyacak şekilde hazırlamamız gerekir ya da IBundleOrderer kullanarak bundle içerisindeki dosyalarımızı sıralayacak bir mekanizma oluşturabiliriz. 

Bu yazımda IBundleOrderer interface'ini inceleyerek, basit bir örnek ile bundle içerisindeki script dosyalarımızın hiyerarşisini web.config dosyası içerisinde tanımlayacağımız bir parametre ile yönetmeyi deneyeceğiz.

 

IBundleOrderer interface'i ve Bundle içerisindeki dosyaların sıralanması

Uygulamamız içerisinde oluşturduğumuz Bundle'ların özellikleri arasında Orderer adında bir özellik ile Bundle'ımıza dosyalarını sıralayabileceğimiz bir IBundleOrderer interface'ini uygulayan bir sınıf verebiliyoruz.

Bundle myBundle = new Bundle("~/bundles/SiteScripts", new JsMinify());
myBundle.IncludeDirectory("~/Scripts/SiteScripts", "*.js");
myBundle.Orderer = new MyBundleOrderer();
bundles.Add(myBundle);

Eğer IBundleOrderer interface'ine gözatarsak eğer OrderFiles metodu ile bundle içerisindeki dosyaları sıralayacak bir metod içeren bir interface olduğunu görüyoruz. Bundle oluşturulurken içerisindeki dosyaları parametre olarak gönderip, dönüş parametresi olarak da sıralanmış dosyaların listesini içeren bir kolleksiyon bekleniyor  : 

namespace System.Web.Optimization
{
    public interface IBundleOrderer
    {
        IEnumerable<System.IO.FileInfo> OrderFiles(BundleContext context, 
                                                IEnumerable<System.IO.FileInfo> files);
    }
}

Şimdi yukarıdaki örneğimizde kullandığımız ve IBundleOrderer interface'ini uygulayan sınıfımıza gelecek olursak : 

public class MyBundleOrderer : IBundleOrderer
    {
        public IEnumerable<System.IO.FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
        {
            if (ConfigurationManager.AppSettings["HighPriorityScripts"] != null)
            {
                string[] highPriorityScripts = ConfigurationManager.AppSettings["HighPriorityScripts"].Split(',');
                List<FileInfo> listFiles = new List<FileInfo>(files);
                List<FileInfo> orderedFiles = new List<FileInfo>();

                foreach (string highPriorityFile in highPriorityScripts)
                {
                    FileInfo nextFileInfo = listFiles.Find(delegate(FileInfo arg) 
                                    {
                                        return arg.Name == highPriorityFile;
                                    }
                                  );
                    if (nextFileInfo != null)
                    {
                        orderedFiles.Add(nextFileInfo);
                    }
                }

                foreach (FileInfo lowPriorityFile in listFiles)
                {
                    if (!orderedFiles.Contains(lowPriorityFile))
                    {
                        orderedFiles.Add(lowPriorityFile);
                    }
                }

                return orderedFiles;
            }

            return files;
        }
    }
 
<!-- Virgülle ayrılmış script dosyaları -->
<add key="HighPriorityScripts" value="Z_HighPriorityScript.js,SmallJSFile.js" />

 

MyBundleOrderer sınıfı web.config'de yukarıdaki gibi tanımlayacağımız HighPriorityScripts parametresini alıp, öncelik verilecek script dosyalarını belirleyip dönüş yapılacak listeye öncelikli olarak bu dosyaları ekliyor. Sonrasında geriye kalan dosyalar dönüş listesine ekleniyor ve oluşturulan sıralı liste dönülüyor. Böylece bundle'ımız içerisindeki dosyalarımızı web.config dosyasındaki parametremiz ile önceliklendirerek yönetebilir hale gelmiş oluyoruz.

, , ,

ASP.NET MVC 4 Bundling ve Minification

25. Aralık 2012

ASP.NET 4.5 ile yeni gelen özelliklerden biri olan Bundling and Minification temelde sunucuya gelen bir talebe (request), talep sayısını ve boyutunu düşürerek performans kazandırmayı amaçlayan bir özellik. Bu yazımda ASP.NET 4.5 ile gelen bu yeni özelliği ASP.NET MVC 4 ile incelemeye çalışacağım.

Bundling ve Minification'dan Önce

Bundling ve Minification öncesinde bir çok projemizde stil ve script dosyalarımızı sayfalarımıza aşağıdaki gibi tek tek tanımlardık : 

<script src="~/Scripts/SiteScripts/LargeJSFile.js" type="text/javascript"></script>
<script src="~/Scripts/SiteScripts/SmallJSFile.js" type="text/javascript"></script> 
<script src="~/Scripts/SiteScripts/Z_HighPriorityScript.js" type="text/javascript"></script> 

<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />

Yukarıdaki script ve stil dosyalarını referans eden bir sayfaya istemciden gelen bir talep dört yeni talep daha yaparak her bir dosyayı da sunucudan talep eder (tabii eğer dosyalar cachelenmedi ise). Sayfamızda bulunan resim, video veya animasyon dosyaları gibi harici dosyaların da ayrı birer talep olarak sunucuya geldiği de düşünülürse bir web sayfası içerisinde kaç dosyaya referans veriyor ise sunucuya her biri için birer talep gidiyor demektir. Bu da web sayfalarımızın yüklenme zamanı performansını etkileyen kriterlerden biridir. 

 

Yukarıdaki kod örneğindeki sayfamızı Google Chrome Developer Tools ile izler isek yukarıdaki gibi bir manzara ile karşılaşırız. Sayfamız ilk satırda yükleniyor, sonrasında stil ve script dosyaları (turuncu ve yeşil renkli) sunucudan talep ediliyor.

Bundlelar

 ASP.NET MVC 4 template projesini açtığınızda bu projede bundle'ların kullanıldığını farkedeceksiniz. Aşağıdaki gibi App_Start dizini altındaki BundleConfig sınıfına gözatarsak projede kullanılan script ve stil bundlelarının bu sınıf içerisinde tanımlandığını görürüz. Global.asax.cs sınıfına da gözatarsak eğer Application_Start olayında App_Start dizinindeki tüm config sınıflarının metodları çağrılarak web uygulamamızın ayarlarının yapıldığını görebiliriz. Eğer ASP.NET MVC 3 veya daha önceki versiyondan upgrade ettiğiniz bir web MVC uygulaması üzerinde çalışıyorsanız NuGet ile Microsoft.AspNet.Web.Optimization paketini almayı unutmayın.

StyleBundle ve ScriptBundle sınıflarını kullanıp yaratacağımız yeni bundleları BundleCollection'a ekleyerek uygulamamız içerisinde kullanacağımız yeni bundleları tanımlayabiliriz.

bundles.Add(new ScriptBundle("~/bundles/SiteScripts")
               .Include("~/Scripts/SiteScripts/*.js"));

Yukarıdaki örnekte joker karakterler (* wildcard karakteri) ile Scripts/SiteScripts dizini altındaki tüm javascript dosyalarını yeni tanımladığım bundle'a dahil ediyorum. Burada ufak bir kısıtımız var, joker karakterleri, dizindeki tüm dosyaları kapsayacak şekilde tanımlamama izin verilmiyor.  Yani "Scripts/SiteScripts/*" şeklinde bir tanım çalışma zamanında aşağıdaki hata ile engelleniyor : 

Yukarıdaki yarattığımız bundle'ı aşağıdaki gibi View'larımızda kullanabiliriz : 

@Scripts.Render("~/bundles/SiteScripts")
@Styles.Render("~/Content/css")

Bu durumda sunucudan talep ettiğimiz sayfamızın kaynak koduna gözatarsak eğer aşağıdaki gibi bundle'ımızı tanımladığımız dizindeki script dosyalarının alfabetik olarak sıralı biçimde sayfamıza eklendiğini görebiliriz : 

Hiyerarşik yapıda bir script veya stil dizinimiz var ve bunu bundle haline getirmek istiyorsak IncludeDirectory metodu daha çok işimize yarayacaktır. Metod bize aşağıdaki gibi alt dizinleri de yönetebileceğimiz bir esneklik sağlıyor : 

bool includeSubDirectories = true;
bundles.Add(new ScriptBundle("~/bundles/SiteScripts").IncludeDirectory(
                    "~/Scripts/SiteScripts", "*.js", includeSubDirectories));

Minification

Şimdiye kadar yaptığımız bundle örneklernini tek dosya halinde toplayıp içerisindeki gereksiz satırları (yorum satırları, boşluklar, yeni satırlar, vb. ) atıp, değişken isimlerini kısaltıp yani script veya stil dosyamızı optimize edip istemciye gönderilecek dosya boyutunu ve talep sayısını azaltan sihir aşağıdaki gibi EnableOptimization propertisi ile sağlanıyor : 

// BundleConfig.cs içerisine eklenecek.
BundleTable.EnableOptimizations = true; 

Minification'ı aktif hale getiren yukarıdaki satırı eklediğimiz zaman aşağıdaki gibi bir sonuç ile karşılaşıyoruz : 

Görüldüğü üzere üç script dosyası tek dosya halinde ve optimize edilmiş olarak 'SiteScripts?v=xyz-xyz-xyz' gibi bir dosya şeklinde istemciye gönderiliyor. Burada dikkat etmemiz gerene bir diğer nokta dosya isminin sonundaki v parametresi. Versiyon amaçlı kullanılan v parametresi sayesinde optimize ettiğimiz script dosyalarımız 1 sene boyunca istemcide cachelenmiş oluyor. Bu zaman zarfında eğer script dosyalarımız değişir ise yeni bir versiyon numarası otomatik olarak verilerek yeni bir dosya oluşturulup, istemcinin bu yeni dosyayı kullanması sağlanıyor.

Toplam boyutu 160KB olan ve 3 script dosyasından oluşan örneğimin 89KB'a ve tek dosyaya indirmemi sağlayan Bundling and Minification özelliği performans açısından getirdiği artıların yanı sıra uygulamamızda kullandığımız script ve stil dosyalarını derleyip toparlayıp ve daha okunabilir bir kod sağlıyor.

Güncelleme

16 Şubat 2014 

Eğer ASP.NET MVC 3 veya daha önceki versiyondan upgrade ettiğiniz bir web ASP.NET MVC uygulaması üzerinde çalışıyorsanız NuGet ile Microsoft.AspNet.Web.Optimization paketini almayı unutmayın. Bu sayede System.Web.Optimization isim alanına ve yazımda bahsettiğim bundling sınıflarına erişebilirsiniz.

, ,

ASP.NET MVC 3 ve Elmah İle Hata Loglama

24. Mart 2012

Elmah (Error Logging Modules and Handler) kütüphanesi ASP.NET 2.0'dan beri kullandığım, ASP.NET web uygulamaları için hata loglama ve yönetimi kütüphanesi. Geliştirdiğim web uygulamalarında sadece birkaç ayar ile hata yönetimini çalışır hale getirebiliyor olmam, beni Elmah'a hayran bırakan özelliklerinden sadece biri. ASP.NET HTTP Handlers kullanımına verilebilecek en yaratıcı örneklerden biri, hatta muhtemelen en iyisi. 

ASP.NET MVC uygulamamızda Elmah'ı çalışır hale getirmek için aşağıdaki adımları takip edebiliriz.

 

ASP.NET MVC 3 Web Uygulamasına Elmah Kurulumu

1. İlk yapmamız gereken solution'ımıza sağ tıklayıp "Manage Nuget Packages"a tıklayıp NuGet paketleri içerisinde Elmah diye aratıp Elmah MS SQL Server'ı seçmek. Başka veritabanları üzerinde loglama yapacak, veya logları dosya sisteminde XML olarak kaydedecek Elmah paketleri de göreceksiniz listede. Ben örneğimi SQL Server üzerinde geliştireceğim.

 

 

2. Elmah NuGet paketini uygulamanıza yükledikten sonra solution'ınızda references'te Elmah referansını göçrebilirsiniz. Aynı zamanda uygulamanıza App_Readme diye bir dizin eklenmiş, ve içerisinde Elmah.SqlServer.sql isminde bir dosya olmalı. İşte bu dosya Elmah'ın hata loglarken kullanacağı SQL Server tablosunun ve Stored Procedure'lerinin scriptlerini barındırıyor. Şimdi yapmamız gereken bu dosyayı uygulamamızın bağlanacağı SQL Server veritabanında çalıştırmak. 

 

 

 

3. Web uygulamamızın konfigurasyon dosyasını yani web.config'i açar isek, NuGet paketi yüklenirken konfigurasyon dosyamıza elmah diye bir bölüm tanımladığını ve içerisine Elmah'ın varsayılan ayarlarını yaptığını görebiliriz. İlk aşamada yapmamız gereken Elmah'ın veritabanına bağlanırken kullanacağı bağlantı cümleciğini (connection string) uygulamamızın kullandığı bağlantı cümleciğine eşitlemek. 

Elmah'ın kullandığı bağlantı cümleciği aşağıdaki bölümde yer almakta. 

 

<elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" />
</elmah>

 

connectionStringName değerini, webconfig dosyamızın connectionStrings bölümüne ekleyeceğimiz ve uygulamamızın kullanacağı bağlantı cümleciği ile değiştirebiliriz : 

<connectionStrings>
    <add name="connStr" connectionString="Data Source=INSTANCE;Initial Catalog=DB;Persist Security Info=True;User ID=USER_NAME;Password=SIFRE"
         providerName="System.Data.SqlClient" />
</connectionStrings>

<!-- ... -->

<elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="connStr" />
</elmah>

 

Eğer bağlantı cümleciğini doğru tanımladıysak Elmah şuan çalışır hale gelmiş olmalı. Test edebilmek için, web uygulamamızı çalıştıralım ve uygulamamızın ana dizininde elmah.axd'yi çağıralım. Yani henüz localhostta çalıştığımız için benim çağırdığım link şu şekilde : 

http://localhost:46352/elmah.axd

 

Loglanacak Hataların Filtrelenmesi

Farkedeceğiniz üzere henüz yeni bir ASP.NET MVC uygulaması açmış olmama rağmen tarayıcım favicon.ico dosyasını sunucudan talep etmiş fakat 404 yani dosya bulunamadı hatası almış, ve bu hatalar Elmah tarafından loglanmış. İyi haber, uygulamama eklediğim Elmah paketim başarıyla çalışıyor. Kötü haber tarayıcım varsayılan olarak web uygulamalarının favicon.ico dosyasını sunucudan talep ettiği için bu hata sunucuya gelen her talepte loglanıyor olacak.

Bunun önüne geçebilmek için web.config konfigurasyon dosyam içerisindeki elmah bölümünde aşağıdaki gibi filtre tanımı yapabilirim. errorFilter tag'ı ile loglamasını istemediğimiz logları filtreleyebiliriz :

<elmah>
<errorFilter>
  <test>
	<and>
	  <equal binding="HttpStatusCode" value="404" type="Int32" />
	  <regex binding="Context.Request.ServerVariables['URL']" pattern="/favicon\.ico(\z|\?)" />
	</and>
  </test>
</errorFilter>
</elmah>

 

Elmah Güvenlik Ayarları 

Web uygulamamızı geliştirip sunucuya taşıma vakti geldiğinde, elmah.axd sayfasına yetkisiz kişilerin girmesini ve hatalarımızı görmesini istemeyiz. Hata mesajları sakıncalı ve güvenlik açığı oluşturabilecek bilgiler içerebilirler. Bu yüzden, web uygulamamızı web sunucusuna taşırsak ve tarayıcımızdan elmah.axd kaynağını talep edersek HTTP 403 Erişim Engellendi hatası ile karşılaşırız. Elmah önyüzü varsayılan ayarlarda yalnızda localde çalışır. Bunu açıp, elmah.axd'yi uygulamamızın yönetim alanına almak için öncelikle yapmamız gereken, web.config içerisindeki elmah bölümü altına security tagını eklemek ve allowRemoteAccess değerini true olarak vermek : 

<elmah>
    <security allowRemoteAccess="true" />
    <errorFilter>
      <test>
        <and>
          <equal binding="HttpStatusCode" value="404" type="Int32" />
          <regex binding="Context.Request.ServerVariables['URL']" pattern="/favicon\.ico(\z|\?)" />
        </and>
      </test>
    </errorFilter>
</elmah>

Şu durumda elmah.axd sunucudan talep eden herkese açık hale geldi. Şimdi location tagı ile elmah.axd'yi sadece yetkili kullanıcılarca erişilebilir hale getirelim. Tabi bunu kullanabilmek için uygulamamızın kullanıcı yönetiminin geliştirilmiş olması gerekmektedir :

 

<location path="elmah.axd">
    <system.web>
      <authorization>
        <deny users="?" />
        <allow roles="admin" />
      </authorization>
    </system.web>
</location>

Sonuç

Bu günlük yazımı yazmaya başladığımda ilk aklıma gelen Java dünyasında geçirdiğim 9 ay oldu. Başarılı pek çok kütüphaneyi çalışır hale getirebilmek için konfigürasyon dosyaları arasında kaybolmak...

2dk sürmeyen ve sadece 3 adımda tamamladığımız Elmah kurulumu ile web uygulamamızın hata loglama işlemlerini yapabiliyor hale getirdik. Filtreleme ve güvenlik ayarlarına göz attık. Basit ve hızlı bir çözüm ile uygulamamızda hata loglamasını, kendini kanıtlamış bir kütüphaneye emanet etmiş oluyoruz.

, ,