OWIN; Statik Dosyaların Sunulması

File-Server

File-Server   Şimdiye kadar ki makalelerimde OWIN katmanlarını kullanarak nasıl dinamik web uygulamaları geliştirebileceğimizi sizlerle paylaştım; ama gerçek hayatta web uygulamalarının dinamik içerik kadar statik içeriğe de sahip olduğunu unutmamalıyız. Bu makalemde sizlere Katana kütüphanelerini kullanarak statik kaynakları nasıl sunabileceğinizi paylaşacağım.

   Aslına bakarsanız statik içeriği sunabilmek adına Katana kütüphanelerine ihtiyacımız yok. Bu işi kendi yazacağımız katmanlarla da yapabilmemiz pek tabi ki mümkün. Diğer yandan bu iş için hazır kütüphaneleri kullanarak Amerika’yı yeniden keşfetmemiş oluruz…

   Şimdiye kadar ki makalelerden tahmin edebileceğiz gibi statik dosyaları sunmak için de atmamız gereken çok fazla adım bulunmuyor. Bunu için ilgili OWIN katamanını kullanıp statik dosyalara ait bazı yapılandırma işlemlerini takip etmemiz yeterli. İşe her zaman olduğu gibi ilgili NuGet paketini kurmakla başlıyoruz. Bu sefer gerekli olan paket Microsoft.Owin.StaticFiles. Bu makaleyi yazarken paket  0.20-alpha-20220-88 sürüm numarasında olduğu için aşağıdaki şekilde paketi kurmalıyız;

Install-Package Microsoft.Owin.StaticFiles -Version 0.20-alpha-20220-88 -Pre

   İlerleyen zamanlarda paket sürümünün güncellenmesi bu konutu geçersiz kılabilir; güncel hali için paket sayfasını takip etmenizi öneririm.

  Sıfırdan başlamak yerine makalemin devamında “Kendi Uygulamamızda OWIN” başlıklı makalemde detaylarını paylaştığım örnek konsol uygulaması üzerinden gideceğim. Bu sebeple henüz okumadıysanız, bu makaleme hızlıca göz atmanızı öneririm.

   Projemize Microsoft.Owin.StaticFiles NuGet paketini kurduktan sonra tek yapmamız gereken aslında yapılandırma sırasında hangi url’nin hangi klasörle eşleştiği bilgisini vermek olacak. Geri kalanı zaten OWIN katmanı kendisi hallediyor. Yapılandırma için Startup sınfı içerisindeki Configuration fonksiyonumuzun içeriği aşağıdaki şekilde olmalı;

using Owin;

namespace Enterprisecoding.OWINKonsolUygulamasi {
    internal class Startup {
        public void Configuration(IAppBuilder app) {
            app.UseFileServer(options => options.WithRequestPath("/Dosyalarim")
                                                .WithPhysicalPath("StatikIcerik")
                                                .WithDirectoryBrowsing());
        }
    }
}

   Burada UseFileServer genişletme metodu tüm yapılandırma işini yapmamıza olanak sunmakta. Yukarıdaki örnek için; /Dosyalarim adresine gelen tüm isteklerde uygulamanın çalıştığı klasörde yer alan StatikIcerik klasörü içerisindeki dosyalar sunulmakta. WithDirectoryBrowsing fonksiyon çağrısı dizinin dolaşılabilmesine izin verildiğini belirtmekte. Bu basit kodlama ardından konsol uygulamamızı başlatarak bir tarayıcıdan http://localhost:8080/Dosyalarim adresine gittiğinizde aşağıdakine benzer bir çıktı ile karşılaşacaksınız;

Statik sunulan dosyalarım klasörü

 

   Ekran görüntüsünde de görebileceğiniz gibi projem içerisinde StaticIcerik adı altında bir klasör oluşturup altında OrnekDosya.txt adıyla bir dosya oluşturdum. Özellikler penceresinden her derlemede bu dosyanın çıktı klasörüne kopyalanması için ayarlama yaptım. Bu sayede yukarıdaki linke tıkladığımda ek bir işlem yapmama gerek kalmaksızın dosya sunulmakta;

Sunulan statik dosya içeriği

   İlk resimde gördüğünüz gibi kullanıcıların klasör içerisinde dolaşmasına izin vermek istemiyorsanız tek yapmanız gereken kod içerisinden WithDirectoryBrowsing fonksiyon çağrısını kaldırmak olacak.

   Eğer verdiğiniz klasörde bir dosya adı verilmediğinde açılacak varsayılan dokümanları belirtmek isterseniz WithDefaultFileNames fonksiyonunu kullanabilirsiniz. String dizisi kabul eden bu fonksiyona geçilen parametreye denk gelen bir dosyanın klasör içerisinde bulunması durumunda klasör listesi yerine bu dosya sunulacaktır. Varsayılan olarak index.html’in kabul edildiği bu liste eklenme sırasına göre işlem görecektir.

Şapkanın Altı

   Yukarıda örneklemeye çalıştığım işlemler aslında neredeyse her sunucunun varsayılan olarak desteklemesi gerektiğini düşündüğüm işlemler. Aslına bakarsanız owin.org sitesinde bu işlemler için tanımlanmış bir ek standart mevcut durumda; OWIN SendFile Extension. Bu makaleyi kaleme aldığım sırada 0.3.0 sürümü yayında olan bu genişleme standardı aynı OWIN gibi olabildiğine sade. Standart bir grup özellikle ve aşağıdaki şekilde bir delegate tanımından oluşmakta;

using SendFileFunc =
        Func
        <
            string, // Dosya adı ve yolu
            long, // Başlangıç dosya offset'i
            long?, // okunacak Byte miktarı, dosyanın kalanı için null
            CancellationToken, // İptal
            Task // Tamamlama
        >; 

   Herhangi bir sebeple istemciye statik dosya göndermek isteyen bir katman özellikler arasından sendfile.SendAsync anahtarı ile sunucu tarafından sunulan yukarıdaki fonksiyonu kullanabilir. Bu şekilde olabildiğine bağımsız şekilde katmanların statik dosya gönderebilmesi sağlanmıştır.

   Şimdi bu noktada aklınız biraz karışmış olabilir; sonuçta makalemin ilk bölümünde bu bilgilerle örtüşen bir kodlama söz konusu değildi. Aslına bakarsanız bu kodlama biraz daha soyutlanmış durumdaydı.

   Bu bakış açısıyla sıfırdan; dosya gönderme işlemini yapan basit bir katmana örnek vereyim. Kolay anlaşılabilmesi adına basit bir senaryo üzerinden gideceğim; amacımız diğer katmanlarca işlenmeyen herhangi bir istek için her zaman sabit bir dosya içeriğini istemciye göndermek. Aslına bakarsanız bu senaryo 404 sayfa bulunamadı senaryosu 😉

   Projeme, senaryom gereği döneceğim içeriği tutacağım yeni bir dosya ekledim. VarsayilanIcerik.txt adını verdiğim bu dosyama ise aşağıdaki içeriği ekleyip özelliklerinden her derlemede çıktı klasörüne kopyalanmasını sağladım;

"Bu sayfa başka her hangi bir katman isteği yanıtlamadığı zaman gönderilecektir.”

   Devamında bu içeriği sunacak olan SabitDosyaIcerigi adıyla yeni bir OWIN katmanı oluşturdum;

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Enterprisecoding.OWINKonsolUygulamasi {
    using AppFunc = Func<IDictionary<string, object>, Task>;
    using SendFileFunc = Func<string, long, long?, CancellationToken, Task>;

    public class SabitDosyaIcerigi {
        private AppFunc birSonrakiKatman;
        private readonly string dosya;

        public SabitDosyaIcerigi(AppFunc birSonrakiKatman, string dosya) {
            this.birSonrakiKatman = birSonrakiKatman;
            this.dosya = dosya;
        }

        public Task Invoke(IDictionary<string, object> environment) {
            var sendFile = (SendFileFunc)environment["sendfile.SendAsync"];
            return sendFile(dosya, 0, null, (CancellationToken)environment["owin.CallCancelled"]);
        }
    }
}

  Eklediğim bu yeni katman gördüğünüz gibi olabildiğine basit, hatta içerisinde sunucunun SendFile desteği olup olmadığına dair bile bir kontrol mevcut değil. Gerçek bir katman da daha fazla kontrol olacaktır. Ortam sözlüğünden aldığımız SendAsync delegate’ini kullanarak en yalın haliyle constructer’ında verilen sabit bir dosya içeriğini istemciye dönmekte. Bu OWIN katmanını az önceki örneğimiz içerisine eklemek için Configuration fonksiyonumuzu aşağıdaki şekilde güncellememiz gerekecektir;

using System.IO;
using Owin;

namespace Enterprisecoding.OWINKonsolUygulamasi {
    internal class Startup {
        public void Configuration(IAppBuilder app) {
            app.UseFileServer(options => options.WithRequestPath("/Dosyalarim")
                                                .WithPhysicalPath("StatikIcerik")
                                                .WithDirectoryBrowsing());

            var referansKonum = Path.GetDirectoryName(GetType().Assembly.Location);

            app.Use(typeof(SabitDosyaIcerigi), Path.Combine(referansKonum, @"StatikIcerik\VarsayilanIcerik.txt"));
        }
    }
}

   Bu işlem ardında, ek bir şey yapmaya gerek kalmaksızın istemci tarafından yapılan istekler karşılanmazsa SabitDosyaIcerigi katmanımız devreye girecek ve belirlediğimiz dosya içeriği istemciye gönderilecektir.

Hiç bir katman tarafından karşılanmamış bir istek olduğunda varsayılan dosya içeriği dönecektir

 

   Burada dikkat edilmesi gereken bir nokta SendFile desteğinin sunucu olarak kullandığımız Microsoft.Owin.Host.HttpListener içerisinde olmadığıdır! Bu destek aslında Microsoft.Owin.StaticFiles paketi içerisinde yer alan SendFileMiddleware ile birlikte gelmekte…

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# konusundan Microsoft tarafından dört yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz.
vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir