Asp.net MVC Razor Hepler ile Durum Çubuğu Yapmak

15 Eyl

Bu yazıda tamamen kendi emeklerimizle, jquery veya başka hazır kütüphane yardımı almadan bir ilerleme çubuğu(progres bar) yapmaya çalışacağız.

Yeni bir ASP.NET MVC projesi yaratarak işe başlıyoruz.

Projelerde genellikle ingilizce değişken adları kullanmaya çalışıyorum ki yazının ingilizcesini hazırlarsam çalışan örnek projeyi değiştimeye gerek kalmasın.

Örnek projede içiçe iki div etiketleri kullanıyoruz. Dıştaki div kapsül, içteki div ise durumu göstermeye yarayacak.

Çalışan uygulama görüntüsünü şu şeklide verelim ki daha fazla merak uyandırmadan düşünce geliştirmeye geçelim.

Yukarda görüldüğü gibi iç içe iki div etiketi içersinde son duruma ait yüzdelik gösterim yapılmış durumda.

İlk olarak css dosyamız içerisinde durum göstergesi için gerekli ayarlamalar şu şekilde belirliyoruz.

#progressBar{
   border:1px solid #4771a5;
   height:15px;
}

#progressInner{
   background-color:#96b1d2;
   height:15px;
}

Daha sonra razor view ortamında bir helper kodluyoruz. Helper ise aşağıdaki şekilde olacaktır.

@helper  ProgressBar(double BarWidth, double InnerWidth){

   BarWidth = BarWidth < 0 ? 100 : BarWidth;
   InnerWidth = InnerWidth < 0 ? 100 : InnerWidth;
   BarWidth = BarWidth > 400 ? 400 : BarWidth;

   InnerWidth = InnerWidth > BarWidth ? InnerWidth = BarWidth : InnerWidth;

   string barWidth = BarWidth.ToString() + "px";
   string innerWidth = InnerWidth.ToString() + "px";
   string persantage = ((int)(InnerWidth / BarWidth * 100)).ToString()+"%";

   <div id="progressBar"  style="width:@barWidth">
       <div id="progressInner" style="width:@innerWidth"></div>
   </div>
   <label>@persantage</label>

}

Yukarda ProgressBar adında bir helper oluşturulmuş durumda. Helper içerisinde kullanıcının abuk değerler verip gösterge çubuğunu sapıtmaması için bir dizi önlemler alıyoruz. Bar ve Inner değerinin sıfırdan küçük veremesin, dolan mavi kısım Bar değerini geçemesin v.s gibi. Duruma göre daha fazla önlem alınabilir.

Burada dikkat edilmesi gereken husus şudur ki, html etiketlerinin css özellikleri dinamik olarak değişmektedir.

Geriye kaldı ki bu helper nasıl kullanılacak. O da şu şekilde.


<h2>Razor Helper Progress Bar</h2>

@ProgressBar(300, 120)

Evet sadece bu kadar. ProgressBar helper’ı artık farklı denemelerle kullanılabilir duruma getirdik.

Nerelerde kullanılabilir?

Veritabanından çekilen değerleri göstermek için ideal bir yöntem olabilir. Örneğin bugün en çok satış yapan çalışanın yaptığı satış bugün yapılan toplam satışların yüzde kaçına tekabül ediyor.

Neden bununla uğraşalım?

Çünkü koda tamamen hakimiz. Yukardaki örnekte Bar yüksekliğini css içerisinde sabitledim. İstersek dışarı çıkarıp Width özelliği gibi dinamik hale getirebiliriz.

Soru: Sizce ProgressBar metodunda double parametreler string dönüşümü yapılmadan style içersine nasıl yerleştirilir?

Uygulamanın çalışan kodları buradadır.

Umarım faydalı olmuştur herkese iyi çalışmalar.

Silverlight Client Access Policy ve Cross-Domain sorunu

8 Eyl

Bu yazımızda silverlight uygulamasına başka bir site veya projedeki servisi referans verdiğimizde karşılaşılan sorunlardan ve çözümlerinden bahediyor olacağız.

Sorun: Tarayıcıların çalıştıkları domain dışından veri alma ve gönderme sorunu. Bu demek oluyor ki silverligth uygulamsından, dışardaki bir uygulamaya ulaşmak istediğimizde cross-domain problemi ile karşılaşacağız.

Bir uygulama üzerinden gidecek olursak, bir solution üzerine CrossService adında bir WCF Service Application birde Silverlight Application ekleyerek başlayabiliriz.

CrossService projesine başka bir alan adı muamelesi yaparak FarService adında bir servis ekliyoruz. Bu servisimiz içerisinde basit olması açısından mesaj veren bir metod barınmaktadır.
IFarService interface


[ServiceContract]
public interface IFarService
{
    [OperationContract]
    string  ServiceMessage();
}

FarService sınıfı


public class FarService : IFarService
{
     public string ServiceMessage()
     {
       return String.Format("Ben Uzak servisten geliyorum. Tahih :{0}", DateTime.Now);
     }
}

Silverlight uygulamamızın barındığı web uygulamasına ise aynı domainde bulunduğunu belirtmek açsından LocalService adında bir servis ekliyoruz.

ILocalService interface

[ServiceContract]
public interface ILocalService
{
    [OperationContract]
    string  ServiceMessage();
}

LocalService sınıfı

public class LocalService : ILocalService
{
    public string ServiceMessage()
    {
         return String.Format("Ben Yakın servisten geliyorum. Tahih :{0}", DateTime.Now);
    }
}

Şu anda servislerimiz hazır ve uygulamaya dahil edilmeye hazır.
Silverlight uygulamamıza Add Service Reference… diyerek referansları ekliyouz.

Referanslar eklendiğinde aşağıdaki görüntü oluşacaktır.

Artık servis referansları yardımıyla servislerdeki ServiceMessage() metodlarını çağırabiliriz.

MainPage.xaml sayfasının tasarım kısmını şu şekilde düzenliyouz.

Kod kısmına gelecek olursak:

public partial class MainPage : UserControl
{
    FarServiceReference.FarServiceClient uzakServis
                  = new FarServiceReference.FarServiceClient();

    LocalServiceRefference.LocalServiceClient yakinServis
                  = new LocalServiceRefference.LocalServiceClient();

    public MainPage()
    {
        InitializeComponent();
    }

    private void btnUzak_Click(object sender, RoutedEventArgs e)
    {
        uzakServis.ServiceMessageAsync();
        uzakServis.ServiceMessageCompleted += (snd, ea) =>
        {
            lblUzak.Content = ea.Result;
        };
    }

    private void btnYakın_Click(object sender, RoutedEventArgs e)
    {
        yakinServis.ServiceMessageAsync();
        yakinServis.ServiceMessageCompleted += (snd, ea) =>
        {
           lblYakin.Content = ea.Result;
        };
   }
}

Görüldüğü üzere iki butondan biri uzak servisi diğeri yakın servisi çağırıyor olacak. Sonrasında servislerden gelen mesajlar  Label üzerine aktarılıyor olacaktır.

Yakın serviste bir sorun yok şu anda. Acak uzak servis için CrossService projesi içinde clientaccesspolicy.xml adında bir dosya mevcut. Silverlight uzak alan adına gittiğinde bu dosya mevcut mu diye bakar. Ki bu dosya içierisindeki ayarlara göre erişim yetkisine sahip mi değilmi anlayacak.

Xml dosya içeriği şu şekilde olacaktır:

 <?xml version="1.0" encoding="UTF-8"?>
 <access-policy>
   <cross-domain-access>
    <policy>
     <allow-from http-request-headers="*">
      <domain uri="*"/>
     </allow-from>
    <grant-to>
      <resource include-subpaths="true" path="/"/>
    </grant-to>
    </policy>
  </cross-domain-access>
 </access-policy>

Dikkat: Eğer clientaccesspolicy.xml dosyası uzak uygulamada olmasaydı şu şekilde bir sorunla karşılaşacaktık.

Hata: “An error occurred while trying to make a request to URI ‘http://localhost:1763/FarService.svc’. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.”

Uygulamanın çalışan kodunu buradan indirebilirsiniz. Umarım faydalı olmuştur. Herkese iyi çalışmalar.

Asp.net Mvc Model Binding

5 Eyl

MVC mimarisinde açıklanması gereken bir konu da Model Binding konusudur. Bu yazıda Model Binding konusunu incelemeye çalışacağız.

Tanım: Model Binding HTTP request ile gelen verilerinin ayrıştırılarak ilgili Controller’da bulunan Action metod parametrelerine ve uygun .NET tiplerine dönüştürülmesi işlemidir.

Eğer bir action metod parametre almışsa Model Binding işlemi gerçekleşmektedir.

Arka planda gerçekleşen olaylar: Şimdi aşağıdaki gibi Index adında, string türünde bir tane parametre alan bir Action metod olduğunu varsayalım.

public ActionResult Index(string name)

Index Action’ı çağırılmadan önce arka plan işlemlerini yönetecek iki önemli bileşen vardır. Bunlar ValueProviderDictionary ve DefaultModelBinder’dır.

ValueProviderDictionary: HTTP request ile gelen parametreleri çekerek string halinde depolar. Bu işlem aşağıdaki sırayla gerçekleşir.

  • Request.Form[“name”] var mı diye bakar.
  • Yoksa RouteData.Values[“name”] var mı diye bakar.
  • Yoksa Request.QueryString[“name”] var mı diye bakar.
  • Yoksa null değer döndürür.

Böylece ValueProviderDictionary  HTTP request ile gelen değerleri elde etmiş olur.

DefaultModelBinder: ValueProviderDictionary sınıfının elde ettiği değerleri uygun .NET objelerine gönüştürme görevini üstlenir. Yukardaki örnekte “name” parametresi zaten string tipindedir. Bu durumda DefaultModelBinder dönüşüm yapmak durumunda değildir. Fakat aşağıdaki gibi int veya başka türde parametre alan Action metodlar olabilir.

Durum 1

public ActionResult Index(int id, decimal rate)

Bu durumda DefaultModelBinder sınıfı parametre tip dönüşümlerini otomatik olarak yapacaktır.

Durum 2

Şu ana kadar olan kısımda HTTP request ile gelen isteklerin ayrıştırılıp uygun .NET tiplerine dönüştürüldüğünü gördük. Ancak aşağıdaki gibi özel bir tipin modele bind edilmesi gereken bir durum sözkonusu olabilir.

public ActionResult Index(Person person)

DefaultModelBinder yukarıdaki gibi özel bir .NET tipi ile (Person) karşılaştığında Reflection yardımına koşar. Reflection sayesinde özel tipe ait tüm public özellikler ValueProviderDictionary sınıfı tarafından sağlanan değerleri alır.

Binding

Model binding işlemini bu noktadan itibaren bir örnek yardımıyla incelemeye çalışalım. Örneğimizde bir Person model nesnesinin nasıl bind edildiğini inceliyor olacağız.

public class Person
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
}

Autoproperty’ler yardımıyla oluşturulmuş Person model tipimiz yukarıda basit bir şekilde oluşturulmuş durumda.

View tarafında bir form oluşturularak, oluşturulan formun Controller tarafında bir action metoda post edilmesi gerekmektedir.

@model MvcModelApp.Models.Person 

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Kişi Bİlgileri</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

Controller tarafında ise DefaultModelBinder tarafından doldurulmuş person nesnesinin kullanılması gerekmektedir.

      [HttpPost]
        public ActionResult CreatePerson(Person person)
        {
            // person nesnesi form bilgileri ile doldurulmuş durumda
            // person nesnesi artık gerekli işlem için 
            // (database, xml kaydı v.s) kullanılabilir

            return RedirectToAction("Index", "Home");
        }

Yukarıdaki action metodunun parametresi olan Person nesnesi DefaultModelBiner tarafından doldurulmuştur.  @model MvcModelApp.Models.Person ile view sayfasının modelinin belirlendiğini görüyoruz. Controller tarafında CreatePerson metoduna post edilen form bilgileri Person nesnesine doldurulmaktadır.

Bu işlem şöyle gerçekleşmektedir: DefaultModelBinder action metodun aldığı parametre tipinden (Person) bir nesne oluşturarak Property’lerini view sayfasından gelen form bilgileri ile eşleştirerek doldurmaktadır.

Umarım faydalı bir yazı olmuştur. Herkese iyi çalışmalar. Bir sonraki yazıda görüşmek üzere.