Makale Özeti

http://sunali.com/blog/archive/2005/08/23/44.aspx adresine incelendiğinde sırasıyla "blog/archive/2005/08/23" klasörleri oluşturulmuş ve bu klasörün içerisinde de "44.aspx" isminde bir dosya olması gerektiğini düşünebilirsiniz. Fakat böyle bir zorunluluk yoktur. Asp.Net üzerinde bulunan bir interface'i kullanarak belirtilen adresin - URL kısmında kullanıcının yazdığı adres değiştirilmeden kaldığı halde - başka bir adrese yönlendirilmesini sağlayabilirsiniz.

Makale

Bazı sitelerin adreslerinin www.domain.com/[yıl]/[ay]/[gün]/[id].aspx şeklinde olduğunu görmüşsünüzdür. Örneğin http://blogs.yazgelistir.com/atakan/archive/2005/06/06/175.aspx ve ya kişisel sitem olan http://sunali.com üzerindeki bir yazının adresi olan http://sunali.com/blog/archive/2005/08/23/44.aspx birer örnek olarak gösterilebilir.

http://sunali.com/blog/archive/2005/08/23/44.aspx adresi örneği üzerinden gidersek sırasıyla "blog/archive/2005/08/23" klasörleri oluşturulmuş ve bu klasörün içerisinde de "44.aspx" isminde bir dosya olması gerektiğini düşünebilirsiniz. Fakat böyle bir zorunluluk yoktur. Asp.Net üzerinde bulunan bir interface'i kullanarak belirtilen adresin - URL kısmında kullanıcının yazdığı adres değiştirilmeden kaldığı halde - başka bir adrese yönlendirilmesini sağlayabilirsiniz.

Yine örneğimiz olan http://sunali.com/blog/archive/2005/08/23/44.aspx adresi üzerinden giderek bahsettiğim konuyu bir örnekle açıklamak gerekirse;

http://sunali.com/blog/archive/2005/08/23/44.aspx adresini giren bir kullanıcı, http://sunali.com/blog.aspx?BlogID=44 adresine gitse, bizim işimiz çok daha kolay olmaz mı? Dilerseniz kodumuzu hep birlikte yazmaya başlayalım.


Öncelikle kullanacağımız interface hakkında biraz bilgi edinelim. Kullanacağımız interface'in ismi "IHttpModule" ve "System.Web" namespace'i içerisinde bulunmakta. Bu interface ayrıntılı detaylarına buradan erişebilirsiniz. Kısaca açıklamak gerekirse; IHttpModule size bir HttpModule'ün içerisinde bulunması gereken methodları sunar. HttpModule Asp.Net içerisinde hazır şekilde gelir, gerekli işlem tiplerine göre gerekli karşılamaları sağlar ve gerekli event'leri (init, vs.) tetikler. HttpModule geliştirmek için tek ihtiyacınız olan event'leri yakalamak hakkında yeterli bilgiye sahip olmaktır çünkü HttpModule işlemlerinin tamamı "Init" methodu içerisinde yakalanan event'lerin içerisindeki işlemlerden ibarettir. Asp.Net geliştiricileri de IHttpModule interface'ini implement ederek kendilerine özel HttpModule'leri geliştirebilirler.

Şimdi kendimize özel olarak geliştireceğimiz HttpModule'ümüzü yazmaya başlayalım:


using System;
using System.Web;
using System.Web.Security;

/// <summary>
/// Summary description for SDCHttpModule
/// </summary>
public class myHttpModule : IHttpModule
{
    #region CTor

    public myHttpModule()
    {

    }

    #endregion

    #region IHttpModule Members

    public void Dispose()
    {

    }

    public void Init( HttpApplication context )
    {
        context.BeginRequest += new EventHandler ( context_BeginRequest );
    }

    #endregion

    void context_BeginRequest( object sender , EventArgs e )
    {
        HttpApplication m_App = ( HttpApplication )sender;
        HttpContext m_Context = m_App.Context;

        URLRewriter.RewriteUrl ( m_Context );

        m_Context.Response.Write ( "Current URL: " + m_Context.Request.Url );
    }
}



IHttpModule interface'i içerisinde implement edilmesi gereken yalnızca 2 method bulunmaktadır. Bunlar "Init" ve "Dispose" methodlarıdır. HttpModule'ünün sonlanması durumunda çalışan Dispose methodu içerisinde ihtiyaç duyduğunuz temizleme işlemlerini ve ya diğer özel işlemlerinizi gerçekleştirebilirsiniz. Init methodu içerisinde ise HttpApplication tipindeki objenizin yakalayacağınız event'lerini tanımlarsınız ve .Net Framework işlem sırasına göre ilgili event'lerinizi tetikler.

Biz HttpApplication tipindeki objemizin sadece "BeginRequest" işlemiyle ilgileniyoruz. Çünkü sayfamızı yönlendireceğimiz süreç tam olarak ziyaretçinin sayfayı istediği ve Request'in başladığı süreçtir.

"context_BeginRequest" methodumuz içerisinde event'imizi tetikleyen HttpApplication tipindeki nesnemize ve nesnemiz üzerinde "Context" özelliğinde taşınan HttpContext tipindeki bir diğer nesnemize erişiyoruz. İşte HttpContext tipindeki bu nesne bizim yönlendirme işlemimizi yapmamıza yardımcı olacan class'tır.

"URLRewriter" ismindeki class birazdan oluşturacağımız bir class'tır ve bu class'ın üzerinde tanımlanmış olan "RewriteUrl" static methodu da yönlendirme HttpContext nesnemizi kullanarak yönlendirme işlemini yapacak olan methoddur. Şimdi de bu class'ımızı oluşturalım:


using System;
using System.Collections;
using System.Web;
using System.Text.RegularExpressions;

/// <summary>
/// Summary description for SDCReWriteUrl
/// </summary>
public class URLRewriter
{
    #region Fields
    static Regex m_ReWriteFilter = null;
    static Regex m_UrlMatch = null;
    static ArrayList m_ReWriteUrls;
    #endregion

    #region Ctor
    public URLRewriter()
    {

    }
    #endregion

    #region Properties
    static ArrayList ReWriteUrls
    {
        get
        {
            if ( m_ReWriteUrls == null )
            {
                m_ReWriteUrls = new ArrayList ();
                m_ReWriteUrls.Add ( new ReWrittenUrl ( "blog" , @"([\w\.-]+)/(\d{4})/(\d{2})/(\d{2})/(\d{1,10})\.aspx" , "SunaliDotCom.Web/blog.aspx?id=$5".Replace ( "^" , "&" ) ) );

            }

            return m_ReWriteUrls;
        }
    }
    #endregion

    public static void RewriteUrl( HttpContext context )
    {
        string m_NewPath = null;
        bool m_IsReWritten = ShouldReWrite ( context , context.Request.Path , context.Request.Url.Query , out m_NewPath );

        if ( m_IsReWritten && m_NewPath != null )
        {
            string m_QueryString = null;
            int i = m_NewPath.IndexOf ( '?' );
            if ( i >= 0 )
            {
                m_QueryString = ( i < ( m_NewPath.Length - 1 ) ) ? m_NewPath.Substring ( i + 1 ) : String.Empty;
                m_NewPath = m_NewPath.Substring ( 0 , i );
            }
            context.RewritePath ( m_NewPath , null , m_QueryString );
        }
    }

    /// <summary>
    /// Bu URL rewrite edilebilir mi diye kontrol eder.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="path"></param>
    /// <param name="queryString"></param>
    /// <param name="newPath"></param>
    /// <returns></returns>
    private static bool ShouldReWrite( HttpContext context , string path , string queryString , out string newPath )
    {

        if ( ReWriteUrls.Count > 0 )
        {
            foreach ( ReWrittenUrl m_Url in ReWriteUrls )
            {
                m_UrlMatch = new Regex ( m_Url.Pattern , RegexOptions.IgnoreCase | RegexOptions.Compiled );

                if ( IsMatch ( path, m_UrlMatch ) )
                {
                    newPath = Convert ( path , queryString , m_Url.Path , m_Url.Pattern , m_UrlMatch );
                    return true;
                }
            }
        }

        newPath = null;
        return false;
    }

    static string Convert( string url , string queryString, string urlPath, string urlPattern, Regex urlRegex )
    {
        if ( queryString != null && queryString.StartsWith ( "?" ) )
        {
            queryString = queryString.Replace ( "?" , "&" );
        }

        return String.Format ( "{0}{1}" , m_UrlMatch.Replace ( url , urlPath ) , queryString );
    }

    static bool IsMatch( string url , Regex urlRegex )
    {
        return urlRegex.IsMatch ( url );
    }
}



Şimdi de m_ReWriteUrls ismindeki ArrayList nesnemize eklerken kullandığımız ReWrittenUrl class'ımızı oluşturalım:


using System;

/// <summary>
/// Summary description for ReWrittenUrl
/// </summary>
public class ReWrittenUrl
{
    #region Fields
    private string m_Name;
    private string m_Path;
    private string m_Pattern;
    #endregion

    #region Properties
    public string Path
    {
        get { return m_Path; }
    }
    public string Pattern
    {
        get { return m_Pattern; }
    }
    #endregion

    public ReWrittenUrl( string name , string pattern , string path )
    {
        m_Name = name;
        m_Path = path;
        m_Pattern = pattern;
    }
}



web.config dosyamızı açıp aşağıdaki bilgileri ekleyelim:


<system.web>
    <httpModules>
        <add name="myModuleName" type="myHttpModule"/>
    </httpModules>
</system.web>



web.config dosyamıza eklediğimiz bilgi içerisindeki "type" özelliği "class, assembly" şeklindedir fakat Asp.Net 2.0'da assembly kullanılma zorunluluğu olmadığından bu şekilde bırakılmıştır.


Son olarak da projemize "blog.aspx" isminde bir dosya ekleyelim. Bu dosyanın içeriğine herhangi birşey yazmanıza gerek yok. context_BeginRequest methodu içerisinde yazmış olduğumuz m_Context.Response.Write ( "Current URL: " + m_Context.Request.Url ); satırı bize çalışmakta olan son dosyanın bilgisini verecek. Örneğimizi çalıştırmaya ne dersiniz?






Şimdi bir de geçersiz bir adres girelim:




http://localhost/SunaliDotCom.Web/2005/11/25/44.aspx adresini sonuna bir adet "C" harfi ekleyerek http://localhost/SunaliDotCom.Web/2005/11/25/44C.aspx şeklinde değiştirdim. Fakat girilen adres bizim Regular Expression bilgimizi match edemediği için Rewrite derçekleştirilemedi ve IIS sayfayı gerçek bir sayfa olarak aradı, sonuç ise bulunamayan bir sayfa.



Coşkun SUNALI
http://sunali.com