Makale Özeti

Bu makalede ASP.NET kullanarak yüksek boyutlarda olan dosyalarınızı nasıl güvenli ve boyut sınırı sorunu olmadan istemcilerin indirebileceğini Response.WriteFile, Response.OutputStream.Write ve Response.TransmitFile metotlarını kullanarak anlatmak istiyorum.

Makale

ASP.NET kullanarak yapabileceğimiz web uygulamaları ve mobil uygulamalarda çoğu kez bazı dosyaların kullanıcılar tarafından indirilebilmesini isteriz. Karşılaşılan en büyük sorunların başında ise güvenlik gelmektedir, herkesin sizin dosyalarınızın adresini bilmesini istemeyebilirsiniz. Ayrıca büyük boyutlu dosyalara dosya gönderme işleminde nasıl bir çözüm bulacaksınız? İşte bu yazımda sizlere özellikle büyük boyutlu dosyaları güvenli bir şekilde ASP.NET kullanarak nasıl istemcilere gönderebileceğinizi anlatmak istiyorum.

Doğrudan Link Versek Olmaz mı?

Sanıyorum ilk aklınıza gelen çözüm bu olmuştur; "Doğrudan dosyanın kendisine link verelim, böylece dosya boyutu önemli değildir bizim için, istemci internet bağlantısına göre kendi indirir". Doğrudur, yapabilirsiniz ama bu durumda istemcilere adresi açık bir şekilde vermeniz gerekecektir. Bunun olmasını da güvenlik açısından istemiyor olabilirsiniz, örneğin bir web uygulamanız var ve sadece üyelerinizin ilgili dosyaları indirmesini istiyorsunuz, bu durumda doğrudan dosyaya link vermek yeterli bir çözüm olmayacaktır.

Response.WriteFile Kullanmak

ASP.NET'in response nesnesinin metotlarından biri olan WriteFile ile güvenli bir şekilde kullanıcılara dosyalarınızı gönderebilirsiniz. Kullanımı oldukça kolay olay bu metotu içeren örnek bir koda gelin bir göz atalım:

<%@ Page language="c#" AutoEventWireup="false" %>
<html><body>

<%
if (Request.QueryString["dosya"] != null)
Response.WriteFile (Request.QueryString["dosya"]);
%>

</body></html>

Bu örnek ASP.NET kodu içerisinde yapılan C# dilini kullanarak URL üzerinden parametre olarak dosya adını alarak bunu istemciye gönderen yapıyı görüyorsunuz. Elimizin altında bir ASP.NET dosyası olduğu için bu dosyanın erişim güvenliğini Forms ile Tanıma, Passport veya Windows ile Tanıma yöntemlerinden birini kullanarak kolayca sağlayabiliriz.

Response.WriteFile nasıl çalışır?

Response.Write metotu aslında IIS'in çalışma mantığı üzerinden yani önce request (isteme) işlemi ardından InetInfo.exe ve aspnet_wp.exe uygulamalarının çalışarak dökümanı alması ve gerisingeriye aynı uygulamalar üzerinden bir response (yanıt verme) ile çalışmaktadır. Aşağıdaki resim konuyu biraz daha görsel olarak anlamamıza yardımcı olacaktır:

Şekilde de görüldüğü gibi önce istekler InetInfo.exe'ye ulaşacaktır, sonrasında asp.net çalışma işlemi olan asp.net worker process yani aspnet_wp.exe dosyasına iletilecektir. ASP.NET wp gerekli dosyayı bulup yeniden InetInfo.exe'ye ilettiğinde bu önce belleğe alınacaktır. Ve işte tam bu noktada büyük bir problemle karşılaşabilirsiniz. Eğer web uygulamanız çok fazla hit alıyorsa ve verdiğiniz dosya çok fazla kişi tarafından indirilecekse InetInfo.exe uygulaması gönderilecek dosyayı önce belleğe yüklediği için web sunucusunda aşırı bir yüklenme oluşacaktır.

Bu soruna çözüm ise istekleri ara ara istemciye göndermektir. Büyük dosyalarda ara ara gönderme işlemini yaparak sorun çıkmasının önüne geçmiş oluruz, bu işlemi yapabilmek için kullanacağımız metotlar ise: Response.OutputStream.Write

Response.OutputStream.Write nasıl çalışır?

Dosyaları parçalı olarak göndermeye yarayan ve böylece bellekte daha az yer işgal etmesini sağlayan Response nesnesinin OutputStream.Write metotunun nasıl çalıştığına gelin bir örnek kod ile bakalım:

using( Stream s = new FileStream( fileName, FileMode.Open,

FileAccess.Read, FileShare.Read, bufferSize ) )

{
byte[] buffer = new byte[bufferSize];

int count = 0;
int offset = 0;

while( (count = s.Read( buffer, offset, buffer.Length ) ) > 0 )
{
ctx.Response.OutputStream.Write( buffer, offset, count );
}
}

Response.TransmitFile

Son olarak bahsetmek istediğim ise geçmişte kullandığımız Response.BinaryWrite'a karşılık gelebilecek olan yeni bir metot: TransmitFile. BinaryWrite'ı hatırlamayanlar için bir hatırlatma yapmış olayım, BinaryWrite ile dosyalarımızı sakladığımız yerden (dosya sistemi veya SQL Server'daki Image alanından) binary olarak okuyup istemciye gönderirken aynı zamanda content-type vererek hangi formatta olduğunu iletebiliyorduk. Eğer yapacağınız dosya işlemleri bunu içeriyorsa artık büyük dosyalarda bu sorunu çözen TransmitFile'ı kullanmanızı öneriyorum. Gelin koda bakalım:

<script runat=server language=C#>

void Page_Load() {

Response.ContentType="application/x-zip-compressed";
Response.AddHeader("Content-Disposition", "attachment;filename=cankaya.zip");
Response.TransmitFile("c:\\nuri\\cankaya.zip");

}

</script>

Bu yazımızda sizlere farklı ASP.NET metotları kullanarak nasıl dosya gönderme işlemini yapabileceğinizi, özellikle dosya büyüklüğü ve güvenlik açısından aktarmak istedim. Bilgiyi paylaştığımız yeni yazılarımızda görüşmek dileklerimle.

Mehmet Nuri ÇANKAYA
www.nuricankaya.com

Referanslar:
- http://www.microsoft.com/practices
- http://www.objectsharp.com
- http://support.microsoft.com/kb/823409/EN-US/