28 Şubat 2009

FileUpload ile Yüklenen Dosyaları Veritabanında Saklamak

FileUpload kontrolünün temel olarak istemciden aldığımız dosyaları sunucunun fiziksel bir konumuna kaydetmek için kullanırız. Fakat bazı durumlarda istemciden alınan bir dosyanın sunucuda güvenli şekilde saklanması için veritabanında saklama yoluna da gidebiliriz. Bu yazımda ASP.NET sunucu kontrollerinden olan FileUpload ile istemciden aldığımız bir dosyayı sunucudaki SQL Server gibi bir veritabanında nasıl saklayabileceğimizi inceleyeceğiz.

İlk olarak dosya bilgilerini saklayacağımız bir tablo oluşturuyoruz.

Tablomuzda resmin adını, binary formatta dosya içeriğini ve dosyanın MIME type bilgisini saklayacağız. FileUpload kontrolünün üç farklı özelliği bize dosyanın bu bilgilerini getirecektir. Bu özelikler ve açıklamaları aşağıdadır:

FileName: Yüklenen dosyanın adı
FileBytes: Dosyanın binary formatta içeriği (byte dizisi olarak getirilir)
PostedFile.ContentType: Dosyanın MIME type bilgisi (MIME dosyanın formatını belirleyen bir isim standartıdır)

Artık sayfamızı tasarlayıp, gerekli kodlarımızı oluşturabiliriz.

<form id="form1" runat="server">

    Yüklenecek dosyayı seçiniz:<br />

    <asp:FileUpload ID="FileUpload1" runat="server" /> &nbsp;<asp:Button

        ID="Button1" runat="server" Text="Dosyayı Yükle" onclick="Button1_Click" />

    <br />

    <br />

    <asp:Label ID="lblMesaj" runat="server" ForeColor="Red"></asp:Label>

</form>


Default.aspx.cs

public partial class _Default : System.Web.UI.Page

{

    protected void Button1_Click(object sender, EventArgs e)

    {

        if(FileUpload1.FileContent != null)

        {

            string dosyaAdi = FileUpload1.FileName; //Dosyanın adı

            byte[] dosyaIcerik = FileUpload1.FileBytes; //Dosyanın bilgilerini binary formatta getirir

            string dosyaTipi = FileUpload1.PostedFile.ContentType; //Dosyanın MIME Type bilgisini getirir

 

            SqlConnection con = new SqlConnection("data source=localhost; initial catalog=Test; integrated security=true");

            SqlCommand cmd = new SqlCommand("Insert Into Dosyalar Values(@dosya_isim, @dosya_icerik, @dosya_tip)", con);

            cmd.Parameters.AddWithValue("@dosya_isim", dosyaAdi);

            cmd.Parameters.AddWithValue("@dosya_icerik", dosyaIcerik);

            cmd.Parameters.AddWithValue("@dosya_tip", dosyaTipi);

            con.Open();

            if (cmd.ExecuteNonQuery() > 0)

                lblMesaj.Text = "Dosya başarıyla yüklendi";

            con.Close();

        }

    }

}

Görüldüğü gibi SQL Server'da hazırladığımız Dosyalar adındaki tablo için yazılan bir INSERT cümlesine parametre olarak eklenen dosya bilgileri bu şekilde tablomuza eklenebiliyor. Birkaç kayıt ekledikten sonra tablomuzun içeriğini Management Studio gibi bir araçtan kontrol edecek olursak aşağıdaki gibi bir görüntüyle karşılaşırız.

Resimleri başarıyla kaydettik, peki okuma işlemi nasıl gerçekleşecek? Okuma işlemi için ise tablomuzdaki kayıtları SELECT sorgusu ile okumamız gerekecek. Eğer Windows uygulamasında çalışıyor olsaydık DosyaIcerik kolonundan okunan kaydı System.Drawing.Image tipine çevirip Image gibi bir kontrolde görüntüleyebiliriz. Ancak web uygulamalarında bir resmi istemci tarafına taşımamızın yolu biraz daha farklı olacaktır. Resmin içeriği ancak istemciye yollanan cevabın(Response) içerisine yazdırılarak gönderilebilir. Dosyayı istemciye gönderirken dikkat edilmesi gereken hususlardan birisi dosyanın tarayıcıda görüntülenip görüntülenmeyeceğidir. Zira jpg, gif, xml, txt gibi dokumanlar web tarayıcısında görüntülenebilir dosyalarken, zip, exe, dll gibi dosyalar ise tarayıcıda görüntülenemez, ancak yüklenebilir dosyalardır. Aşağıdaki kod parçasında tasarladığımız bir sayfanın kullanıcıya veritabanındaki bir dosyanın nasıl iletilebileceği görülmektedir.

Bu arada, dosyaya yapılan talep QueryString üzerinden resmin DosyaId kolonundaki değer ile iletilmektedir. Yine talebin daha hızlı cevaplanması için Web Form(.aspx) dosyası yerine Generic Handler(.ashx) dosyası kullanmak daha faydalı olacaktır.

ResimGoruntule.ashx

...

using System.Data.SqlClient;

 

public class ResimGoruntule : IHttpHandler {

 

    public void ProcessRequest (HttpContext context) {

        string id = context.Request.QueryString["id"];

        byte[] dosyaIcerik = null;

        string dosyaTipi = String.Empty;

 

        SqlConnection con = new SqlConnection("data source=localhost; initial catalog=Test; integrated security=true");

        SqlCommand cmd = new SqlCommand("Select * From Dosyalar Where DosyaId=@id", con);

        cmd.Parameters.AddWithValue("@id", id);

        con.Open();

        SqlDataReader dr = cmd.ExecuteReader();

        if (dr.Read())

        {

            dosyaIcerik = (byte[])dr["DosyaIcerik"];

            dosyaTipi = dr["DosyaTip"].ToString();

        }

        con.Close();

 

        //context.Response.AddHeader("content-disposition", "attachment; filename=" + dosyaAdi + ";"); //Download edilecek dosyanın adı belirleniyor. Bu satırın yorum durumu kaldırılırsa tüm dosyalar download işlemine zorlanacaktır.

        context.Response.ContentType = dosyaTipi; //Gönderilen dosyanın tipi belirtiliyor

        context.Response.BinaryWrite(dosyaIcerik); //Gönderilen cevabın içeriği dosyanın binary formattaki bilgileri olacaktır

    }

 

    public bool IsReusable {

        get {

            return false;

        }

    }

}

Görüldüğü gibi Response nesnesinin BinaryWrite metodu byte dizisi olarak saklanan dosya içeriğini istemciye göndermektedir. Yine dosyanın tarayıcı tarafından tanınmasını ve işlemin sağlıklı şekilde tamamlanması için ContentType özelliğini de resmin MIME type değeri olarak belirliyoruz. Eğer resmin istemci tarafından download edilmesini istiyorsak kod içerisinde yorum satırı olarak bulunan ve AddHeader metodu ile sayfaya eklenen başlık bilgilerinin bulunduğu satırı normal hale getirmek gerekecektir.

24 Şubat 2009

Bilkent Üniversitesi Yazılım Teknolojileri Seminerleri Ardından

Geçtiğimiz hafta sonu Ankara’da Bilkent Üniversitesi’ndeydim. Daron Yöndem ile beraber Bilkentli teknolojistlerle dolu dolu iki günde .NET teknolojileriyle ilgili bilgi ve tecrübelerimizi paylaşmaya çalıştık. Ben Cumartesi günü C# 3.0 ve LINQ, Pazar günü ise ASP.NET 3.5 ve SP1 ile Gelen Yenilikler sunumlarımla bu güzel etkinliğe katkıda bulunurken, Daron’da Silverlight, WPF ve WCF sunumlarını gerçekleştirdi. Karlı ve soğuk bir Ankara havasında salonu tıka basa dolduran öğrenci arkadaşlarla birlikte oldukça keyifli sunumlar gerçekleştirdik. Uzun bir aradan sonra tekrar Ankara’da olmak, Ankara’daki arkadaşlarımla zaman geçirmek bu hafta sonunun anılarımda daha da güzel bir şekilde yer almasını sağladı :)

bilkent_ilkgun2 bilkent_ilkgun1
Etkinliğin ilk gününden iki kare

Vee katılımcı arkadaşlara söz verdiğim gibi etkinlik dosyalarını paylaşıyorum. Oturumlarda kullandığım sunumları ve kod örneklerini aşağıdaki linklerden indirebilirsiniz. Etkinlikte emeği geçen başta MSP arkadaşlarım Ali Uğur Çakmak ve Alper Özçetin olmak üzere tüm arkadaşlara teşekkürlerimi buradan da iletiyorum.

C# 3.0 ve LINQ Sunumu
C# 3.0 ve LINQ Demolar
ASP.NET 3.5 ve SP1 Sunumu
ASP.NET 3.5 ve SP1 Demolar

15 Şubat 2009

ASP.NET 4.0 ve Vadettikleri

Geçtiğimiz aylarda gerçekleştirilen PDC etkinliğinde önümüzdeki 1-2 yıl içerisinde .NET dünyasında bizleri bekleyen yenilikler anlatıldı. Bu yeniliklerden biri de ASP.NET 4.0'dı. .NET Framework 4.0 ile 4 numaralı versiyonuna erişecek ASP.NET'te bizleri gerçekten önemli yenilikler bekliyor. Zaten bunun ilk uyarılarını .NET Framework SP1 ve ASP.NET MVC ile alıyoruz. ASP.NET’in 1.1 sürümünden 2.0 sürümüne geçiş kadar derin yenilikler olmasa da, 2.0’dan 3.5’e geçişteki yeniliklerden çok daha fazlası yeni sürümde bizleri bekliyor. Henüz ne zaman doğacağı bile kesin olmayan bir teknoloji hakkında birşeyler yazmak normal şartlarda zordur. Ancak Microsoft sağolsun, daha şimdiden bize öyle ipuçları, öyle araçlar sunuyor ki birkaç sene sonraki yenilikleri şimdiden okuyabilme, inceleyebilme, hatta test edebilme şansını yakalayabiliyoruz. İşte bu izlenimlerim sonucunda sizlerle paylaşmak istediklerim:

Gelecek olan yeniliklere baktığımızda mimariye eklenen köklü değişikliklerin yanı sıra, varolan yapıda aksaklılara neden olan ve çoğu ASP.NET programcısının şikayetlerinin ciddi anlamda giderilmeye çalışıldığı görülüyor. MVC Framework, Routing, Dynamic Data, Chart kontrolleri, Ajax tarafındaki yeni eklentiler ve kontroller aslında 4.0 sürümünde bizleri bekleyen en ciddi yenilikler olarak göze çarpıyor. Diğer yandan şu an varolan ViewState ile ilgili sorunlar, Master-Content Page, User Control’ler ile veri kontrollerinin template’lerindeki kontrollerin istemci tarafına taşındığında ID bilgilerinin değişmesi ve ele alınmasının zorlaşması, kontrol çıktılarının <table> elementi olarak üretilmesi gibi sorunların giderilmesine yönelik yeniliklerin daha şimdiden geldiğini görebilmek, hatta test edebilmek mümkün(CTP sürümünde bu özelliklerin çoğunu test edebiliyoruz). Yine Visual Studio 2010’da 2.0 sürümünden 4.0 sürümüne kadar multi-targetting özelliğinin olması, JQuery desteğinin gelmesi bizi bekleyen olumlu gelişmeler. Bunların dışında yine ufak tefek, ancak etkileyici yenilikler de önümüzdeki Beta sürümlerde eklenerek, nihai sürümde karşımıza yepyeni bir ASP.NET geliştirme ortamı çıkacak gibi görünüyor.

11 Şubat 2009

Birden Fazla Tabloyu CacheDependency Yapısında Önbelleklemek

SqlCacheDependency nesnesi ASP.NET uygulamalarında veritabanındaki güncellemelere göre önbellekleme yapılmasını sağlayan nesnedir. Zamana bağımlı kalmadan çok daha hızlı ve performans açısından önemli kazançlar sağlayan bu nesneyi tek bir tablodan gelen kayıtların önbelleklenmesi için kullanabiliyoruz. Fakat çoğu uygulamada JOIN'li ifadelerle birden fazla tablonun verilerini eşleştirebiliyoruz. Peki böyle bir durumda önbellekleme işlemini SqlCacheDependency nesnesi ile nasıl gerçekleştirebileceğiz? Çünkü yapısı itibariyle bu nesne tek tablo ile çalışabilir şekilde tasarlanmıştır. Sorumuzun cevabı: AggregateCacheDependency nesnesi(Yanılmıyorsam .NET Framework 2.0 ile gelen bir tiptir). AggregateCacheDependency nesnesi birden fazla CacheDependency nesnesini içerisinde saklayarak, herhangi bir nesnenin durumunun değişmesinde Cache nesnesinin bellekteki bilgilerini kaldıracak ve önbellekleme işlemini başarılı şekilde yapabilmemizi sağlayacaktır. Yapmamız gereken tek işlem herbir tablo için oluşturduğumuz SqlCacheDependency nesnelerini AggregateCacheDependency nesnesine Add metodu ile eklemek ve bu nesneyi Cache'e Insert metodu aracılığıyla eklemektir. Aşağıdaki kod parçalarında bu işlemin nasıl yapılabileceğini görebilirsiniz.

SqlCacheDependency dep1 = new SqlCacheDependency("dbCon", "Urunler");
SqlCacheDependency
dep2 = new SqlCacheDependency("dbCon", "Siparisler");

SqlCacheDependency dep3 = new SqlCacheDependency("dbCon", "Musteriller");


AggregateCacheDependency
aggDep = new AggregateCacheDependency();

aggDep.Add(dep1,dep2,dep3);


Cache.Insert("urunSiparis", dt, aggDep);

SqlCacheDependency ASP.NET uygulamalarında çok verimli şekilde önbellekleme işlemleri yapılmasını sağlar. Ancak hangi şekilde olursa olsun, önbellekleme işlemlerinde unutulmaması gereken nokta, çok büyük verileri Cache'te saklayacak olursak ve sistem kaynakları yeterli değilse bazı durumlarda OutOfMemoryException hatası alabiliriz. Yani hem hataların oluşması, hem de bellekte çok fazla yer işgal etmek uygulamanın performansı adına kötü pratikler olacaktır(bkz: Kaş yapalım derken göz çıkarmak). Bu nedenle Cache'te saklanacak verilerin boyutu bizim için önemli bir kriterdir, bu ayrıntıyı unutmamak lazım.

Bu arada yeri gelmişken ASP.NET uygulamalarında performans ipuçlarına ihtiyacınız varsa, bu Cuma akşamı gerçekleşecek olan webinerime katılımlarınızı beklerim. Bilgileri bu adresten bulabilirsiniz.

04 Şubat 2009

nedirtv?com Şubat Ayı Webinerleri

nedirtv?com webinerleri tüm hızıyla devam ediyor. Ineta Türkiye’nin de desteğiyle nedirtv?com editörleri olarak bu ay 7 farklı konuda gerçekleşecek webinerlerde yazılım geliştiricilerle beraber olacağız. ASP.NET AJAX 3.5, Expression Blend 2, ADO.NET Data Services Güvenlik , ASP.NET Uygulamalarında Performans İpuçları , Windows Workflow Foundation, MOSS 2007-InfoPath Form Services, Expression Web 2 gibi konular üzerinde yapılacak webinerler hakkında daha detaylı bilgi almak için bu linkteki haberi okuyabilir, webinerlerin duyurularını almak için de bu linkteki olayı Facebook ajandanıza kaydedebilirsiniz.