2014年11月11日 星期二

C# Function函數,程式的編程執行者

如果一個程式師,對於函數這個名稱還不夠了解的話,那真的是要砍掉重練。基本上,早期的程式,是沒有所謂的函數這個名稱的,但它的誕生,開啟了程式一個很重要的里程。

函數式編程於1958年被創造出來的LISP了,透過LISP,可以用精簡的人力。較現代的例子包括scheme、Haskell、Clean、Erlang和Miranda等。雖然λ演算並非設計來於計算機上執行,但可視為第一個函數式編程語言。1980年代末期,Haskell發佈,企圖集合很多函數式編程研究裏的想法。

Functional programming函數式編程或者函式程式設計,又稱泛函編程,是一種編程典範,它將電腦運算視為數學上的函式計算,並且避免使用程式狀態以及易變物件。函數程式語言最重要的基礎是λ演算(lambda calculus)。而且λ演算的函式可以接受函式當作輸入(引數)和輸出(傳出值)。簡單的說,以前的程式同樣的一個寫法,常因為不同的功能,就要重新再寫出一個相似的陳述句。這對於開發者而言,不僅很花時間在除錯Debug上,而且重覆使用性差。它的誕生就是為了解決這樣的問題。

C#分為靜態函數與成員函數兩類,靜態函數附屬於類別,呼叫時可以直接指定類別名稱即可。成員函數附屬於物件,呼叫時必須透過物件變數進行呼叫。

函數會接收到呼叫端傳入的參數。C# 的參數有數種傳遞方式,包含傳值參數 (call by value),傳址參數 (call by reference) 等,基本型態的參數,像是 int, double, char, … 等,也可以是void,而物件形態的參數,像是 StringBuilder,陣列等,預設則是使用傳址的方式。

下面例子是 C# 的靜態函數範例,其中的 square 就是靜態函數,其功能是將傳入的數值進行平方動作後傳回,這是一個傳值參數的範例。

class Draw
{
    public static void Main(string[] args)
    {
        int x = square(5);
        Console.WriteLine("x="+x);
    }

    public static int square(int n)
    {
        return n*n;
    }
}

陣列也可以用來作為函數的參數,陣列的傳遞採用傳址的方式,因此在函數中對陣列的修改將會是永久性的修改,離開函數後並不會恢復成原先的數值。

class Example
{
    public static void Main(string[] args)
    {
        int[,] a = {{1,2}, {3,4}};
        int[,] b = {{5,6}, {7,8}};
        int[,] c = new int[2,2];
        add(a, b, c);
        Console.WriteLine("=======a=======");
        print(a);
        Console.WriteLine("=======b=======");
        print(b);
        Console.WriteLine("=======c=======");
        print(c);
    }

    public static void add(int[,] x, int[,] y, int[,] z)
    {
        for (int i=0; i<z.GetLength(0); i++)
        for (int j=0; j<z.GetLength(1); j++)
        {
         z[i,j] = x[i,j] + y[i,j];
        }
    }

    public static void print(int[,] x)
    {
        for (int i=0; i<x.GetLength(0); i++)
        {
            for (int j=0; j<x.GetLength(1); j++)
                Console.Write(x[i,j]+" ");
            Console.WriteLine();
        }
    }
}

上面範例中的 add 函數用來將兩個二維陣列 (x,y) 相加,然後將結果放入 z 當中,print 函數則是將傳入的陣列 x 印出來。必須注意的是,對於二維陣列而言,要取得陣列的第一維元素個數 (列數),可用 GetLength(0),要取得陣列的第二維元素個數 (行數),必須使用 GetLength(1)。

函數基本上在許多的程式語言都會有,不過有一點要注意的是,在ActionScript 3上的函數,是可以當作變數使用。如果一開始接觸ActionScript 3的人再來寫C#的話,會誤以為C#的函數也可以像ActionScript 3一樣的使用。ActionScript 3如下例子:

var func:Function = new Function()
                               {
                                   trace("可以使用成變數的Function");
                               };
func();//這邊就執行了上面的函數

上面的例子,就是ActionScript 3很典型的使用方法,但是C#對於安全性的要求很嚴謹,所以不允許Funtion可以這樣的使用,所以千萬要注意。

2014年9月24日 星期三

刪除遠端桌面連線(mstsc.exe)的電腦紀錄


分享一個小小的技巧

刪除遠端桌面連線(mstsc.exe)程式,在「電腦(C)」旁邊的選單區塊,框框裡面自動填好最後登錄過的主機 IP

C:\Documents and Settings\(電腦的使用者名稱)\My Documents\ 資料夾下刪除 Default.rdp(這個檔案是隱藏檔,要點檔案總管上排的工具列,工具資料夾選項檢視顯示所有的檔案和資料夾才看的到隱藏檔) 

刪掉在「電腦(C)」選單區塊的下拉選單
開始執行輸入regedit
找到機碼
HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default
然後右邊視窗可以看到 MRU0MRU1 IP 紀錄,刪掉即可。


-雲遊山水為知已、逍遙一生而忘齡- 電腦神手

2014年8月16日 星期六

C# - About Multiple Inheritance 關於多重繼承

物件導向程式語言中的多重繼承(Multiple Inheritance, MI)指的是一個類別可以同時從多於一個父類繼承行為與特徵的功能。與單一繼承相對,單一繼承指一個類別只可以繼承自一個父類。在Java和C++都支援了這樣的特性,但在C#裡這樣的特性,微軟用另外的方法去演譯它。

如何才能在C#中實現多重繼承,其實這是一個很有趣的問題。因為C++支援多重繼承,允許對現實世界進行更直接的建模,Borland C++的OWL Framework大量使用多重繼承來描述視窗的關係。微軟的MFC僅使用單一繼承描述視窗,ATL使用多重繼承實現COM/ActiveX,WTL則使用多重繼承實現視窗。但是在C#中是沒有類的多重繼承這個概念.要使用多重繼承必須要通過介面Interface來完成。可是Interface實際上就是一個虛函數清單指標,內部封裝的只有函數和屬性,而且介面(Interface)因為沒有建構函數,不能實體化只能通過繼承才可以使用,這一點和抽象類別很類似,可是抽象類別本身就是個類別,有方法的實現,它所描述的物件是一個無法在現實中具現的物件。以下例子如何在C#中實現多重繼承。

namespace Intdv
{
    public abstract class myBase
    {
        public myBase()
        {
        }
    }
}

namespace Intdv
{
    class myDerive1 : Intdv.myBase
    {
        string myName;

        public myDerive1()
        {
            myName = "yarshary";
        }

        public void ShowMyName()
        {
            Console.WriteLine("my name is: " + this.myName);
        }

        public void reName(string n)
        {
            myName = n;
        }
    }

    public interface ImyDerive1
    {
        void ShowMyName();
        void reName(string n);
    }
}

namespace Intdv
{
    public class myDerive2 : Intdv.myBase
    {
        int MyAge;

        public myDerive2()
        {
            MyAge = 21;
        }

        public void ShowMyAge()
        {
            Console.WriteLine("my age is:" + MyAge);
        }

        public void reAge(int a)
        {
            this.MyAge = a;
        }

    }

    public interface ImyDerive2
    {
        void ShowMyAge();

        void reAge(int a);
    }
}

namespace Intdv
{
    public sealed class myMDerive : Intdv.myBase, Intdv.ImyDerive1, Intdv.ImyDerive2
    {
        Intdv.myDerive1 d1;
        Intdv.myDerive2 d2;

        public myMDerive()
        {
            d1 = new myDerive1();
            d2 = new myDerive2();
        }

        public void ShowMyName()
        {
            d1.ShowMyName();
        }

        public void reName(string n)
        {
            d1.reName(n);
        }


        public void ShowMyAge()
        {
            d2.ShowMyAge();
        }

        public void reAge(int a)
        {
            d2.reAge(a);
        }
    }

}

在一開始定義了一個基底類別myBase,並繼承兩個介面為myDerive1,myDerive2
這兩個介面分別定義了一組操作,myDerive1中定義了操作ShowMyName 和 reName 並通過接ImyDerive1加以描述。myDerive2中定義了操作ShowMyAge 和 reAge 並通過介面ImyDerive2來描述。這樣多重繼承中只用繼承介面也就是ImyDerive1和ImyDerive2就可以保證操作列表的繼承,操作的實現通過組合模型。在介面方法中實作繼承介面myMDerive,雖然只繼承了介面,
可是在建構函數中,卻動態分配(New)了myDerive1 和 myDerive2 兩個對象,並在操作ShowMyName 等介面繼承來的操作中實際調用了myDerive1 和 myDerive2 的操作。由於myDerive1 和 myDerive2 是在myMDerive內定義的,所以用戶端代碼並不需要管理物件的分配和釋放。

-雲遊山水為知已逍遙一生而忘齡- 電腦神手

2014年7月10日 星期四

C# - RouteHandler & IHttpHandler & PageRouteHandler & MvcRouteHandler解析和運用

ASP.Net MVC路由的運用,如何找到 IHttpHandler

在MVC中一個請求最終通過一個具體的HttpHandler進行處理,用於表示一個Web頁面的Page物件就是一個HttpHandler,被用於處理基於某個.aspx檔的請求。通過HttpHandler的動態映射來實現請求位址與物理檔路徑之間的分離。實際上ASP.NET路由系統就是採用了這樣的實現原理。ASP.NET路由系統通過一個註冊到當前應用的自訂HttpModule對所有的請求進行攔截,並通過對請求的分析為之動態匹配一個用於處理它的HttpHandler。HttpHandler對請求進行處理後將相應的結果寫入HTTP回復以實現對請求的相應,如下圖所示:



請求攔截器的HttpModule類型為UrlRoutingModule。UrlRoutingModule對請求的攔截是通過註冊表示當前應用的HttpApplication的PostResolveRequestCache事件實現的,看下面的代碼:

public class UrlRoutingModule : IHttpModule
{
    public RouteCollection RouteCollection { get; set; }
    public void Init(HttpApplication context)
    {
        context.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
       
    }
    private void OnApplicationPostResolveRequestCache(object sender,  EventArgs e);

}

UrlRoutingModule具有一個類型為RouteCollection的RouteCollection屬性,在預設的情況下引用這通過RouteTable的靜態屬性Routes表示的全域路由表。針對請求的HttpHandler的動態映射就實現在OnApplicationPostResolveRequestCache方法中,具體的實現邏輯非常簡單:通過HttpApplication獲得但前的HTTP上下文,並將其作為參數調用RouteCollection的GetRouteData方法得到一個RouteData物件。

通過RouteData的RouteHandler屬性可以得到一個IRouteHandler的路由處理器物件,而調用後者的GetHttpHandler方法直接可以取得對應的HttpHandler物件,需要Reflection(映射)到當前請求的就是這麼一個 HttpHandler。下面的程式碼呈現了定義在UrlRoutingModule的OnApplicationPostResolveRequestCache方法中的動態HttpHandler映射邏輯。

public class UrlRoutingModule : IHttpModule
{
    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
    {
        HttpContext context = ((HttpApplication)sender).Context;
        HttpContextBase contextWrapper = new HttpContextWrapper(context);
        RouteData routeData = this.RouteCollection.GetRouteData(contextWrapper);
        RequestContext requestContext = new RequestContext(contextWrapper, routeData);
        IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);
        context.RemapHandler(handler);
        }
}

PageRouteHandler & MvcRouteHandler

前面的說明對於使用RouteCollection的GetRouteData取得的RouteData物件,其RouteHandler來源於配對的Route對象。對於通過調用RouteCollection的MapPageRoute方法註冊的Route來說,它的RouteHandler是一個類型為PageRouteHandler對象。
由於調用MapPageRoute方法的目的在於實現請求http address位址與某個.aspx分頁檔之間的映射,最終還是要創建的Page物件處理相應的請求,所以PageRouteHandler的GetHttpHandler方法最終返回的就是針對映射分頁檔路徑的Page物件。此外,MapPageRoute方法中還可以控制是否對物理檔位址實施授權,而授權在返回Page物件之前進行。
定義在PageRouteHandler中的HttpHandler獲取邏輯基本上體現在如下的代碼片斷中,兩個屬性VirtualPath和CheckPhysicalUrlAccess表示分頁檔的位址和是否需要對物理檔位址實施URL授權,它們在構造函數中被初始化(Initialization),而最終的來源從調用RouteCollection的MapPageRoute方法傳入的參數。

public class PageRouteHandlerIRouteHandler
{
    public bool CheckPhysicalUrlAccess { get; private set; }
    public string VirtualPath { get; private set; }
    public PageRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)
    {
        this.VirtualPath = virtualPath;
        this.CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
    }
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        if (this.CheckPhysicalUrlAccess)
        {
            //確認URL的存取,在這可任意處理
        }
        return (IHttpHandler)BuildManger.CreateInstanceFromVirtualPath(this.VirtualPath, typeof(Page));
    }
}


ASP.NET MVC的Route物件是通過調用RouteCollection的擴展方法MapRoute方法進行註冊的,它對應的RouteHandler是一個類型為MvcRouteHandler的對象。MvcRouteHandler用於獲取處理當前請求的HttpHandler是一個MvcHandler對象。MvcHandler實現對Controller的啟動、Action方法的執行以及對請求的相應,整個MVC框架實現在MvcHandler之中,如下面的程式所示:

public class MvcRouteHandlerIRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new MvcHandler(requestContext);
    }
}

ASP.NET路由擴展

大致來說,整個路由系統是通過對HttpHandler的動態註冊的方式來實現的。具體來說,UrlRoutingModule通過對代表Web應用的HttpApplication的PostResolveRequestCache事件的註冊實現了對於請求的攔截。對於被攔截的請求,UrlRoutingModule利用註冊的路由表對其進行配對和解析,然後得到包含所有路由資訊的RouteData物件。最終藉由該物件的RouteHandler創建出相應的HttpHandler映射到當前請求。從可擴展性的角度可以用三種方式來實現路由方式:

通過集成抽象類別RouteBase創建自訂Route定義路由邏輯。
通過實現介面IRouteHandler創建自訂RouteHandler定制HttpHandler提供機制。
通過實現IHttpHandler創建自訂HttpHandler來對請求處理。

通過自訂Route對ASP.NET路由的擴展

定義在ASP.NET路由系統中預設的路由類型Route建立了定義成文本範本的URL模式與某個物理檔之間的映射,如果我們對WCF REST有一定了解的話,具體來說,WCF REST也可以借助於System.UriTemplate這個物件實現了同樣定義成某個文本範本的URI模式與目標操作之間的映射。
我們創建一個新的ASP.NET Web應用,並且添加針對程式集System.ServiceModel.dll的引用(UriTemplate定義在該程式集中),然後創建如下一個針對UriTemplate的路由類型UriTemplateRoute。

public class UriTemplateRoute:RouteBase
{
    public UriTemplate UriTemplate { get; private set; }
    public IRouteHandler RouteHandler { get; private set; }
    public RouteValueDictionary DataTokens { get; private set; }

    public UriTemplateRoute(string template, string physicalPath, object dataTokens = null)
    {
        this.UriTemplate = new UriTemplate(template);
        this.RouteHandler = new PageRouteHandler(physicalPath);
        if (null != dataTokens)
        {
            this.DataTokens = new RouteValueDictionary(dataTokens);
        }
        else
        {
            this.DataTokens = new RouteValueDictionary();
        }
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        Uri uri = httpContext.Request.Url;
        Uri baseAddress = new Uri(string.Format("{0}://{1}", uri.Scheme, uri.Authority));
        UriTemplateMatch match = this.UriTemplate.Match(baseAddress, uri);
        if (null == match)
        {
            return null;
        }

        RouteData routeData = new RouteData();
        routeData.RouteHandler = this.RouteHandler;
        routeData.Route = this;
        foreach (string name in match.BoundVariables.Keys)
        {
            routeData.Values.Add(name,match.BoundVariables[name]);
        }

        foreach (var token in this.DataTokens)
        {
            routeData.DataTokens.Add(token.Key, token.Value);
        }

        return routeData;
    }

    public override VirtualPathData GetVirtualPath(VRequestContext requestContext, RouteValueDictionary values)
    {
        Uri uri = requestContext.HttpContext.Request.Url;
        Uri baseAddress = new Uri(string.Format("{0}://{1}", uri.Scheme, uri.Authority));
        Dictionary<string, string> variables = new Dictionary<string, string>();
        foreach(var item in values)
        {
            variables.Add(item.Key, item.Value.ToString());
        }
   
        //確定路徑變數是否被提供
        foreach (var name in this.UriTemplate.PathSegmentVariableNames)
        {
            if(!this.UriTemplate.Defaults.Keys.Any(key=> string.Compare(name,key,true) == 0) &&
            !values.Keys.Any(key=> string.Compare(name,key,true) == 0))
            {
                return null;
            }
        }

        //確定查詢變數是否被提供
        foreach (var name in this.UriTemplate.QueryValueVariableNames)
        {
            if(!this.UriTemplate.Defaults.Keys.Any(key=> string.Compare(name,key,true) == 0) &&
            !values.Keys.Any(key=> string.Compare(name,key,true) == 0))
            {
                return null;
            }
        }

        Uri virtualPath = this.UriTemplate.BindByName(baseAddress, variables);
        string strVirtualPath = virtualPath.ToString().ToLower().Replace(baseAddress.ToString().ToLower(),"");
        VirtualPathData virtualPathData =  new VirtualPathData(this, strVirtualPath);
        foreach (var token in this.DataTokens)
        {
            virtualPathData.DataTokens.Add(token.Key, token.Value);
        }
            return virtualPathData;
    }
}

UriTemplateRoute具有UriTemplate、DataTokens和RouteHandler三個唯讀屬性,前兩個通過建構函數的參數進行初始化,後者則是創建PageRouteHandler物件。
用於請求進行匹配判斷的GetRouteData方法中,可以解析出基於應用的基底位址並請求位址作為參數調用UriTemplate的Match方法,如果返回的UriTemplateMatch物件不為Null,則表示URL範本的模式與請求位址配對。在配對的情況下創建並返回相應的RouteData物件,否則直接返回Null。
用於生成URL的GetVirtualPath方法中,通過定義在URL中的範本(包括變數名包含在屬性PathSegmentVariableNames的路徑段變數和包含在QueryValueVariableNames屬性的查詢變數)是否提供RouteValueDictionary欄位或者預設變數清單(通過屬性Defaults表示)來判斷URL是否與提供的變數清單配對。在配對的情況下通過調用UriTemplate的BindByName方法得到一個完整的Uri。由於該方法返回的是相對路徑,所以需要將應用基底位址剔除,最後創建並返回一個VirtualPathData物件。如果沒有配對,則直接返回Null。
在創建的Global.asax檔中採用如下的代碼對自訂的UriTemplateRoute進行註冊,基於UriTemplate的URI範本比針對Route的URL範本,我們直接將預設值定義在範本,讓它在定義預設值方法更為直接,如下面的範例所示:

public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        UriTemplateRoute route = new UriTemplateRoute("{areacode=010}/{days=2}",
        "~/Weather.aspx", new { defualtCity = "BeiJing", defaultDays = 2});
        RouteTable.Routes.Add("default", route);
    }
}

在註冊的路由對應的目標頁面Weather.aspx程式裡,定義了GenerateUrl根據指定的區號(areacode)和預報天數(days)創建一個Url,而Url的產生直接通過調用RouteTable的Routes屬性的GetVirtualPathData方法完成。生成的URL連同當前頁面的RouteData的屬性產生HTML,如下所示:




接觸MVC開發時一定會接觸到路由,那麼路由這東西的原理是如何運作呢?在web.config中有一段是這樣的:

<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

這一段就是路由負責的DLL組件。在這個dll中有一個很特殊的類別UrlRoutingModule,它裏面主要的核心代碼:

protected virtual void Init(HttpApplication application)
{
    if (application.Context.Items[_contextKey] == null)
    {
        application.Context.Items[_contextKey] = _contextKey;
        application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
    }
}

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);
    this.PostResolveRequestCache(context);
}

public virtual void PostResolveRequestCache(HttpContextBase context)
{
    RouteData routeData = this.RouteCollection.GetRouteData(context);
    if (routeData != null)
    {
        IRouteHandler routeHandler = routeData.RouteHandler;
        if (routeHandler == null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
        }
        if (!(routeHandler is StopRoutingHandler))
        {
            RequestContext requestContext = new RequestContext(context, routeData);
            context.Request.RequestContext = requestContext;
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
            if (httpHandler == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
            }
            if (httpHandler is UrlAuthFailureHandler)
            {
                if (!FormsAuthenticationModule.FormsAuthRequired)
                {
                    throw new HttpExcepion(0x191, SR.GetString("Assess_Denied_Description3"));
                }
                UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
            }
            else
            {
                context.RemapHandler(httpHandler);
            }
        }
    }

}

在IHttpModule.Init中註冊了一個PostResolveRequestCache事件,而該事件主要是調用PostResolveRequestCache這個方法:

RouteData routeData = this.RouteCollection.GetRouteData(context);
IRouteHandler routeHandler = routeData.RouteHandler;
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

context.RemapHandler(httpHandler);

分析RouteData routeData = this.RouteCollection.GetRouteData(context) ,這句可以猜測是取得路由訊息。要想理解這句代碼又得回到程式中來,在Global.asax.cs檔中的RegisterRoutes方法 中,默認有一段程式是這樣:

routes.MapRoute(
    "Default", // 路由名稱
    "{controller}/{action}/{id}", // 帶有参數的 URL
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参數默認值

);

這句代碼主要是註冊一個路由,url不能隨便寫,需要有controller和action。實現的程式碼如下:

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
    Route route = new Route(url, new MvcRouteHandler()) {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    };

    if ((namespaces != null) && (namespaces.Length > 0)) {
        route.DataTokens["Namespaces"] = namespaces;
    }
    routes.Add(name, route);
    return route;
}

各參數如下:
routeName="Default", // 路由名稱
routeUrl= "{controller}/{action}/{id}", //帶有參數的 URL
defaults=new {controller = "Home", action = "Index", id = UrlParameter.Optional} //參數默認值
constraints=null
namespaces=null


這裡建立了一個Route實例並且把它加入到RouteCollection中了。
如果項目中有特殊的需要,只要我們註冊自己的IRouteHandler了,routes.Add(new Route("{controller}/{action}/{id}",new MvcRouteHandler())); 然後在裡面GetHttpHandler實現邏輯處理,就可以創建HttpHandler。

現在又回到 RouteData routeData = this.RouteCollection.GetRouteData(context);這句代碼中來,GetRouteData的程式如下:

public RouteData GetRouteData(HttpContextBase httpContext)
{
    using (this.GetReadLock())
    {
        foreach (RouteBase base2 in this)
        {
            RouteData routeData = base2.GetRouteData(httpContext);
            if (routeData != null)
            {
                return routeData;
            }
        }
    }

    return null;
}

這裡的base2就是先前調用MapRoute是添加的Route的。而Route的GetRouteData的方法如下:

public override RouteData GetRouteData(HttpContextBase httpContext)
{
    string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
    if (values == nullreturn null;

    RouteData data = new RouteData(this, this.RouteHandler);
    if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
    return null;

    foreach (KeyValuePair<string, object> pair in values)
    {
        data.Values.Add(pair.Key, pair.Value);
    }

    if (this.DataTokens != null)
    {
        foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
        {
            data.DataTokens[pair2.Key] = pair2.Value;
        }
    }

    return data;
}


以下是程式的解析,主要是幫助對於運作的程式結構上,有明確的了解。

主要下面這段,它是路由運作的監控:
RouteData data = new RouteData(this, this.RouteHandler);

下面這段程式是取得requestContext內容:
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;


在下面程式碼中它的主要作用獲取Httphandler這個監控:
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

對於MvcRouteHandler就是是表示如何取得一個Httphandler,最後直接返回了一個MvcHandler實例,如下:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
    requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
    return new MvcHandler(requestContext);
}

下面這段context.RemapHandler(httpHandler); 在HttpContext的RemapHandler方法中this._remapHandler = handler;,在HttpContext中有取得這些屬性,如下所示:

internal IHttpHandler RemapHandlerInstance
{
    get
    {
        return this._remapHandler;
    }
}

在HttpApplication的內部類別MaterializeHandlerExecutionStep中的HttpApplication.IExecutionStep.Execute()方法調用下面的程式碼:
if (httpContext.RemapHandlerInstance != null)
{
    httpContext.Handler = httpContext.RemapHandlerInstance;
}

看到MaterializeHandlerExecutionStep這個了類別名稱,在內部類別PipelineStepManager中BuildSteps方法有HttpApplication.IExecutionStep step = new HttpApplication.MaterializeHandlerExecutionStep(app);
app.AddEventMapping("ManagedPipelineHandler", RequestNotification.MapRequestHandler, false, step);

這樣對MVC整個路由應該有個大致的理解了。

-雲遊山水為知已逍遙一生而忘齡- 電腦神手