創建本身的 MVC portal (三)

下面咱們來創建本身的Router體系:c#

這張圖清晰地講述了.net 訪問過程當中內部流程機制,固然咱們也能夠經過Global.asxm中創建相應的過程進行跟蹤,來驗證流程的真實性。咱們能夠關注其中的Routing節點部分,.net正式基於這個原理實現Router的,.net將RoutData與HttpContext合併成爲RequestContext傳遞到IRoutHandler接口,IRoutHandler接口的實現類MvcRouteHandler接口到RequestContext參數,返回一個MvcHandler對象,而且爲這個對象賦值RequestContext。緩存

這個接口的定義是在 App_Start 中的 RouteConfig.cs 定義完成的。ide

咱們先看下系統默認的Route代碼:函數

public static void RegisterRoutes(RouteCollection routes) {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute( 
        name: "Default", 
        url: "{controller}/{action}/{id}", 
        defaults: new { controller = "Home", action = "Index",  id = UrlParameter.Optional } 
    );
}

咱們要對他進行改造的目的是爲了更好的配合系統的多站點的要求,也就是說爲了知足不一樣站點使用不一樣Router的可能,咱們須要從新構建本身的Route,那麼咱們就須要構建一個可根據站點不一樣,支持不一樣方案的Route機制。
this

爲了達到這一目的,咱們須要創建一個Router的基類,經過不一樣的實現方式來實現不一樣的站點的不一樣route的方法。url

首先平臺創建一個Route用來接收系統的調用,獲得URL後首先分析這個URL指向的是哪一個站點,知道了是哪一個站點了咱們就能夠知道這個站點採用了何種方法來處理URL的轉換,這樣就能夠實現不一樣站點不一樣URL轉換的處理機制。spa

首先咱們創建一個Router基類,來解決不一樣站點不一樣Router的機制問題:.net

    /// <summary>
    /// 站點級URL解析基類
    /// </summary>
    public abstract class SiteRouteBase
    {
        /// <summary>
        /// 分解URL獲得controller和action,將分解結果寫到 RouteData 中
        /// </summary>
        /// <param name="accessURL">沒有SiteURL的訪問地址</param>
        /// <returns></returns>
        public abstract bool GetRouteData(RouteData data, string accessURL);
        /// <summary>
        /// 根據參數獲得外部訪問地址,與 GetRouteData 相對應
        /// </summary>
        /// <param name="requestContext"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public abstract VirtualPathData GetVirtualPath(VonPortalRoute route, RequestContext requestContext, RouteValueDictionary values);
    }

咱們要創建不一樣的SiteRouteBase實現方法來解決URL的實際轉換,同時站點信息將實際使用的方法進行綁定就能夠了,也就是說咱們要創建一個Site(站點)信息,同時綁定SiteRouteBase的實現類就能夠了,這裏我先給一個簡單代碼樣例,待之後具體實現:code

public class SiteInfo
{
    public string Url{get;set;}//站點的URL頭
    public SiteRouteBase Translate{get;set;}//站點指定的Route的轉換實例
}

咱們要創建這個路由首先來研究一下Route的系統代碼,系統的路由是從RouteBase繼承過來的。
orm

public abstract class RouteBase
{
    protected RouteBase();
    public bool RouteExistingFiles { get; set; }
    public abstract RouteData GetRouteData(HttpContextBase httpContext);
    public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}

RouteBase裏面主要須要實現兩個主要函數,即

    public abstract RouteData GetRouteData(HttpContextBase httpContext);

    public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);

只要咱們重構這兩個函數就能夠了,固然這是一個可行的方案,但咱們有更簡單的方法來實現這個工做,就是咱們能夠從系統默認的路由來繼承實現,Route是從RouteBase繼承過來的。

    /// <summary>
    /// 平臺Route
    /// </summary>
    public class VonPortalRoute : Route
    {
        public VonPortalRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
            : base(url, defaults, constraints, dataTokens, routeHandler)
        { }
        public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
        {
            SiteInfo site = VonPortal.Web.GlobalValues.GetSiteByUrl(httpContext.Request.Url.AbsoluteUri);   //根據 URL 獲得對應的 Site,支持二級域名搜索
            var data = new RouteData(this, new MvcRouteHandler());//聲明一個RouteData,添加相應的路由值
            if (site == null)   //若是沒有找到該域名,證實他是第一次被訪問,則進入初始化界面
            {
                data.Values.Add("controller", "Admin");
                data.Values.Add("action", "SiteEdit");
            }
            else
            {
                string accessUrl = httpContext.Request.Url.AbsoluteUri.Substring(site.SiteURL.Length);
                if (accessUrl.StartsWith("/"))
                    accessUrl = accessUrl.Remove(0, 1);
                if (!site.Translater.GetRouteData(data, accessUrl)) return null;
            }
            data.Values.Add("site", site);
            return data;
        }
        public VirtualPathData BaseVirtualPath(RequestContext requestContext, RouteValueDictionary elegantValues)
        {
            return base.GetVirtualPath(requestContext, elegantValues);
        }
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            SiteInfo site = (SiteInfo)requestContext.RouteData.Values["site"];
            if (site == null) return new VirtualPathData(this, "");
            else return site.Translater.GetVirtualPath(this, requestContext, values);
        }
        
    }

這裏咱們省略了站點信息的系統緩存部分,即VonPortal.Web.GlobalValues.GetSiteByUrl(httpContext.Request.Url.AbsoluteUri)的代碼,這段代碼的含義就是根據訪問的URL信息直接獲得系統的站點信息site,若是沒有獲得則直接進入系統的Admin/SiteEdit進行新站點初始化。

相關文章
相關標籤/搜索