Asp.Net MVC Gzip/Deflate Sıkıştırılmış (Compressed) içerik

15 May

Web sayfalarımızın içeriği genişledikçe, sunucu tarafından oluşturulan cevapların(response) boyutu artmaktadır. Bu boyutu küçültmenin yolu içeriği sıkıştırmaktır.

Bu işlemi incelemek için senaryomuzda, içeriği binlerce kelimeden oluşan bir sunucu cevabı (response) oluşturup,  kullanıcı(client) tarafına sunalım. Bu işlemi önce normal bir şekilde, ardından da sıkıştırılmış bir şekilde gerçekleştirelim ve farkı görelim.

ASP.NET MVC ortamında çalıştığımız için önce bir action metod oluşturup içeriğini doldurarak sunalım ve boyutuna bakalım.


public ActionResult Zip()
{
     StringBuilder result = new StringBuilder();

     for (int i = 0; i < 42000; i++)
     {
          result.Append("word");
     }

     return Content(result.ToString());
}

Yukarıdaki action metod ile 42000 kelimeyi içeren bir içeriği kullanıcıya sunuyoruz. Bu içeriğin boyutuna Firefox tarayıcısında Firebug eklentisiyle bakalım.

Sıkıştırılmamış içerik

Evet içerin 164.1KB boyutunda oluşturulmuş durumda.

Şimdi bu işlemi, içeriği sıkıştırarak yapmayı deneyelim. Önce sıkıştırılacak action metod veya controller sınıfını sıkıştırmaya yarayan bir attribute oluşturalım. Daha sonra sıkıştırmak istediğimiz metodu bu attribute ile imzalayabiliriz.

public class CompressAttribute: ActionFilterAttribute
{
      public override void OnActionExecuting(ActionExecutingContext filterContext)
      {
          var encodingAccept = filterContext.HttpContext.Request.Headers["Accept-Encoding"];

          if (string.IsNullOrEmpty(encodingAccept))
              return;

          encodingAccept = encodingAccept.ToLowerInvariant();

          var response = filterContext.HttpContext.Response;

          if (encodingAccept.Contains("gzip"))
          {
              response.AddHeader("Content-encoding", "gzip");
              response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
          }
          else if (encodingAccept.Contains("deflate"))
          {
              response.AddHeader("Content-encoding", "deflate");
              response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
          }

      }

}

Şimdi oluşturduğumuz bu attribute ile metodumuzu imzalayıp tekrar içerik boyutuna bakalım.

[Compress]
public ActionResult Zip()
{
      StringBuilder result = new StringBuilder();

      for (int i = 0; i < 42000; i++)
      {
           result.Append("word");
      }

      return Content(result.ToString());
}

Gzip sıkıştırılmış içerik

İçerik 1.9KB boyutuna düştü. Sıkıştırma işleminden önceki içerik 164.1KB idi. Bence bu müthiş birşey.

Tekrar görüşmek ümidiyle…

ASP.NET MVC ile Dosya okuma ve yazma işlemleri

14 May

Web ortamında bazı durumlarda dosyalarla işlem gerektiren durumlar olabilmektedir. Örneğin bir HTML sayfa, CSS dosyası, Text dosya veya şu anda aklıma gelmeyen bir çeşit dosyanın içeriğinin online olarak değiştirilmesi gibi.

Bu işlemi, ASP.NET MVC ortamında nasıl gerçekleştirebileceğimizi inceleyelim. Bu işlem için dosyalarımızın bulunduğu bir dizini belirleyip içindeki dosyaları kullanıcının önüne döküp, istediği gibi düzenlemesini sağlamaya çalışalım.

Dizin içindeki dosyaları kullanıcıya veren bir model sınıfı oluşturalım.


public class PersonelFiles
{
      public string FileName { get; set; }
}

Bu model sınıfından üretilen bir view oluşturmak için File controller içerisine Files adında bir action metod oluşturalım.


public class FileController : Controller
{
      public ActionResult Files()
      {
         DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Files"));

         var personelFiles = new List<PersonelFiles>();

         foreach (var item in directory.GetFiles("*.txt"))
         {
             personelFiles.Add(new PersonelFiles { FileName = item.Name });
         }

         return View(personelFiles);
     }
}

Files dizinindeki *.txt uzantılı dosyalarımızı listeleyecek bir view artık bu action metod üzerinden oluşturulabilir. Files() action metoduna sağ tıklayıp create view diyerek ilerleyebiliriz.

Şimdi de dosyaların içeriğini editleme işlemini gerçekleştirmek için, düzenle linkine tıklandığında dosya içeriğini bir kutu içerisinde bize sunacak action metodu yazalım.

Metod adı Edit şeklinde olacaktır.


public ActionResult Edit(string id)
{
     if (!string.IsNullOrEmpty(id))
     {
         StreamReader reader = new StreamReader(Server.MapPath("~/Files/") + id, System.Text.Encoding.Default);

         var content = new FileEditFormView()
         {
             FileContent = reader.ReadToEnd(),
             FileName = id
         };

         reader.Close();
         reader.Dispose();

         return PartialView("_Edit", content);
     }

     return View("FileNotFound");

}

Edit modtodu, düzenle linkine tıkladığımızda linkteki id parametresiyle dosya adını Edit metoduna verecektir. dosya içeriği okundukran sonra  FileEditFormView şeklinde karşımıza gelecektir.

Kaydet butonuna bastığımızda da POST metodu ile gönderdiğimizde de yazma işlemini gerçekleştireceğiz.


[HttpPost]
public ActionResult Edit(FileEditFormView form)
{
      StreamWriter writer = new StreamWriter(Server.MapPath("~/Files/") + form.FileName, false, System.Text.Encoding.Default);

      writer.Write(form.FileContent);
      writer.Close();
      writer.Dispose();

      return RedirectToAction("Files");
}

Bu şekilde işlem tamamlanmış olacaktır.

Düzenleme Geçmişi:

Başlık düzenlendi 25.09.2013
İçerik düzenlendi 25.09.2013

C# Conditional ve Ternary Operatorler

14 May

Yazılım geliştiriciler olarak bazen kod ekonomisine başvurmak istediğimiz durumlar olabilmektedir. Özellikle de if şartlarını oluştururken parantez açıp kapatmak yerine sınama işlemini tek satırda yapabilmekteyiz.

if(){}else{} kodu yerine kısaca ?: operatörlerinin kullanımına bakalım.

Senaryomuz, mantıksal bir durum kontrolünün sınamasına göre string değer döndürecek bir iş akışının hazırlanması şeklinde olabilir.


     bool durumu = getDurum();

     string sonuc="";

     if (durumu)
     {
        sonuc = "Onaylanmış";
     }
     else
     {
        sonuc = "Beklemede";
     }

     Console.WriteLine(sonuc);

Yukarıda basitçe, durum değişkeninin true ve false olup olmadığı kontrol edilmektedir.

Bu işlemi kısaca ?: operatörüyle yaparsak şu şekilde olacaktır.

     bool durumu = getDurum();

     string sonuc = durumu ? "Onaylanmış" : "Beklemede";

     Console.WriteLine(sonuc);

Bu şekilde if ve else yapısı iptal edilerek tek satırda işlem tamamlanmaktadır. Bir başka yazım şekli ise şu şekildedir:

     string sonuc = durumu == true ? "Onaylanmış" : "Beklemede";

Yapı şu şekildedir:

     string sonuc = <mantıksal kontrol> ? <true ise dönen değer> : <false ise dönen değer>;

Tekrar görüşmek ümidiyle…

C# Extension Metod Tanımlama ve Kullanma

11 May

Programlama dillerinde varsayılan olarak gelen tiplere yapılan eklemelere, bir başka deyişle yamalara extension metod diyebiliriz. Bu yazıda, c# ile extension methodların nasıl tanımlandığını, nasıl uygulandığını  ve hangi mantıkla çalıştığını incelemeye çalışacağız.

C# dilinin temel tipleri olan int, string, double ve sayamadığım birçok tip, object tipinden türemiştir ve object tipinin özelliklerini taşımaktadır. Biz de bu özelliklerin yanında gerekli olan metodları bu tiplere ekleyebiliriz.

Örneğin şöyle bir senaryomuz olsun: string türündeki içerikler eğer belli bir karakterden uzunsa (…) şeklinde kısaltılsın.

Bunun için extension metodumuzu hazırlayalım. Extension metodun ulaşılabilmesi için bir static class içerisinde, static bir metod olarak tanımlanması gerekir.


public static class ExtensionString
{
     public static string Kisaltma(this string text, int maxSize)
     {
          return text.Length > maxSize ? text.Substring(0, maxSize).Insert(maxSize, "...") : text;
     }
}

Yukarıda görüldüğü üzere, ExtensionString adında static bir sınıf ve Kisaltma adında static bir metod oluşturuldu. Kisaltma metodu this string şeklinde bir parametre almaktadır. Bu demek oluyor ki Kisaltma metodu, string tipindeki değişkenlere eklenecek. Yani artık her string değişkeni, Kisaltma adında bir metoda sahip.

Burada dikkat edilmesi gereken, extension metodu barındıran sınıfın kullanılmak istenen yerden görünüyor olması gerekir. Yani gerekirse using ile sınıf içerisinde tanımlanmalıdır.


class Program
{
      static void Main(string[] args)
      {
         string baslik = "Bu yazının içeriği ne kadar uzunmuş böyle.";

         Console.WriteLine(baslik.Kisaltma(10));
      }

}

Ekran çıktısı

Kisaltma metoduile 10 karakterden sonra “…” şeklinde devam edilmektedir. Artık istediğimiz yerde bu metodu kullanabiliriz.

Esri Silverlight Api Query SpatialReference Problemi

11 May

Esri silverlight API kullananların yaşadıkları sorunlar dizisinden birisiyle daha karşı karşıya kalabilirsiniz. Bu sorun, harita üzerindeki bir yere sorgu yapmak istediğinizde karşımıza çıkıyor. Daha açık bir ifadeyle bir Query sonucunda sorgulanan bir yere harita züerinde çizim yapmak istediğimizde karşı karşıya kalabilmekteyiz. Örneğin bir şehir seçildiğinde o şehri harita üzerinde maviye boyamak istediğimizde sonuç alamayabiliriz.

Ben bu sorunu Esri Silverlight V2.4 dll ve Arcgis 10 Service yayınlarında yaşadım. Sorunun kaynağında yatan ise Query yapılan Layer ile Map Layer arasındaki SpatialReference farkıydı.

Sorgu:


private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
      QueryTask queryTask = new QueryTask("http://domain/ArcGIS/rest/services/sehirler/MapServer/0");

      queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;

      ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
      query.Where = "ILADI=" + "'Sample'";
      query.ReturnGeometry = true;
      query.OutFields.Add("*");
      queryTask.ExecuteAsync(query);

}

Map SpatialReference
Query SpatialReference

iki şekilde görüldüğü üzere sorgu yapılan Layer ve Map Layer arasında SpatialReference Farkı var. Bu farkı gidermek için sorguda kiük bir değişiklik yaparak SpatialReference farklılığını gideriyoruz.

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

       QueryTask queryTask = new QueryTask("http://domain/ArcGIS/rest/services/sehirler/MapServer/0");

       queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;

       ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
       query.Where = "ILADI=" + "'Sample'";
       query.ReturnGeometry = true;
       query.OutFields.Add("*");
       query.OutSpatialReference = MyMap.SpatialReference;
       queryTask.ExecuteAsync(query);

}

Bu işlemin ardından iki Spatial referans eşitlenir ve sorun ortadan kalkar. Map üzerindeki GraphicsLayer zerinde yapılmak istenen çizim işlemi de gerçekleşir.

GraphicsLayer

Eğer SpatialReference eşitlemesi yapılmasaydı, koordnat sistemi farkları yüzünden bu çizim işlemi başarısız olacaktı.

ASP.NET MVC Reset Password

7 May

Bir çok web sitesinin klasik bölümüdür şifremi unuttum bölümü. Kullanıcı adınızı veya email adresinizi girersiniz ve mail adresinize postalanır yeni şifreniz. Peki bu senaryo ASP.NET  MVC ile Membership yapısı kullanılarak nasıl yapılır? Yani kullanıcı şifresi resetlenir (reset password) ve yeni şifre mail olarak gönderilir.

Bu işlem için önce sistemimizin konfigurasyonunu mail gönderebilecek şekilde hazırlamamız gerekmektedir.


<system.net>
    <mailSettings>
       <smtp deliveryMethod="Network">
         <network host="mailhostadresiniz" (örneğin smtp.gmail.com)
                  port="587"
                  userName="emailadresiniz"
                  password="sifreniz"
                  enableSsl="true"/> (SSL gerektiren mail sunucu kullanıyorsanız)

       </smtp>
    </mailSettings>
</system.net>

Sistemimiz mail gönderemeye hazır bir vaziyete gelmiş durumda.

ASP.NET MVC projemizde Models dizinindeki Account model içerisine yeni bir model tanımlamalıyız. Bu modelin adı LostPasswordModel olacak.


public class LostPasswordModel
{
     [Required(ErrorMessage = "Kullanıcı adınızı giriniz.")]
     [Display(Name="Kullanıcı Adı")]
     public string Username { get; set; }
}

Bu model ile kullanıcıdan kullanıcı adını talep ederek mail adresine yeni şifresini göndereceğiz.

Bu modelden gelen kullanıcı adını alarak o kullanıcının şifresini sıfırlayıp, yeni mail adresine postalamalıyız. Bu işlemi yapmak için aşağıdaki metodu tanımlayabiliriz.

public void ResetPassword(string username)
{

     MembershipUser user = Membership.GetUser(username);

     string confirmationGuid = user.ProviderUserKey.ToString();
     string newPassword = user.ResetPassword();
     string bodyMessage = string.Format("Yeni Şifreniz {0}",newPassword);

     var message = new System.Net.Mail.MailMessage("kimden@mail.com", user.Email)
     {
         Subject = "Yeni şifre oluşturma isteği.",
         Body = bodyMessage
     };

     var client = new System.Net.Mail.SmtpClient();
         client.Send(message);
}

Bu metod sayesinde kullanıcının mail adresine yeni şifresini postalamış olduk.

ASP.NET MVC Email Doğrulama (Verification)

6 May

ASP.NET üyelik sistemlerinde bir gelenek olan üyelerin email adreslerini doğrulama işleminden bahsedelim birazda. Sistemimize üye olanları email adresleri aracılığıyla gerçek kullanıcı olup olmadıklarını anlayabiliriz bu sayede. Bu işlem için sistemin konfigurasyonlarının mail gönderebilecek hale getirilmesi gerek. Yani mail ayarları yapılmalıdır.


<system.net>
   <mailSettings>
      <smtp deliveryMethod="Network">
           <network host="mailhostadresiniz" (örneğin smtp.gmail.com)
                    port="587"
                    userName="emailadresiniz"
                    password="sifreniz"
                    enableSsl="true"/> (SSL gerektiren mail sunucu kullanıyorsanız)
      </smtp>
   </mailSettings>
</system.net>

Bu ayarlar yapıldıktan sonra üyelerin kayıtlarının yapıldığı sırada bir doğrulama postasının otomatik olarak gönderilmesi gerekir. Bu işlemi yapan metodu hazırlamalıyız.


public void SendConfirmationEmail(string username)
{

      MembershipUser user = Membership.GetUser(username);

      string confirmationGuid = user.ProviderUserKey.ToString();
      string verifyUrl = System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) +
                         "/Account/Verify?Id=" +
                         confirmationGuid;

      string bodyMessage = string.Format("üyeliğiniz başarıyla oluşturulmuştur. Aşağıdaki linke tıkladığınızda hesabınızın aktif olacaktır.\n");
             bodyMessage += verifyUrl;

      var message = new System.Net.Mail.MailMessage(Models.Configuration.SystemMail, user.Email)
      {
          Subject = "Üyeliğinizi doğrulayın.",
          Body = bodyMessage
      };

     var client = new System.Net.Mail.SmtpClient();
         client.Send(message);

}

Mail gönderen metodumuz da artık hazır olduğuna göre bu metodu kayıt işlemi sırasında kullanabiliriz.


[HttpPost]
public ActionResult Register(RegisterModel model)
{

   if (ModelState.IsValid)
   {
       MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Password, model.Email, false);

       if (createStatus == MembershipCreateStatus.Success)
       {
            SendConfirmationEmail(model.UserName);

            return RedirectToAction("Confirmation","Account");
       }
       else
       {
            ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
       }

    }

    return View(model);

}

Artık kayıt olan üyelere otomatik olarak mail gönderiliyor.

Bu linke tıklandığında, üye Account controller içindeki Verify action metoduna yönlendirilecektir.


public ActionResult Verify(string Id)
{
     MembershipUser user = Membership.GetUser(new Guid(Id));

     user.IsApproved = true;
     Membership.UpdateUser(user);

     return RedirectToAction("Welcome");
}

Bu action metod sayesinde linke tıklayan üyenin üyeliği aktif hale getirilmiş oldu.