004_URL 路由 - 定製路由系統 & 使用區域

来源:http://www.cnblogs.com/KeSaga/archive/2016/06/01/5550263.html
-Advertisement-
Play Games

定製路由系統 路由系統是靈活可配置的,當然還可以通過下麵這兩種方式定製路由系統,來滿足其他需求。 1、 通過創建自定義的RouteBase實現; 2、 通過創建自定義路由處理程式實現。 創建自定義的RouteBase實現 創建自定義的RouteBase實現,需要實現一個RouteBase的派生類,而 ...


定製路由系統

   路由系統是靈活可配置的,當然還可以通過下麵這兩種方式定製路由系統,來滿足其他需求。

1、  通過創建自定義的RouteBase實現;

2、  通過創建自定義路由處理程式實現。

創建自定義的RouteBase實現

   創建自定義的RouteBase實現,需要實現一個RouteBase的派生類,而這需要實現以下兩個方法:

  • GetRouteData(HttpContextBase httpContext):這是入站URL進行匹配的工作機制。框架依次對RouteTable.Routes的每個條目調用這個方法,直到其中之一返回一個非空值。
  • GetVirtualPath(RequestContext requestContext,RouteValueDictionary values):這是出站URL生成的工作機制。框架依次對RouteTable.Routes的每一個條目調用這個方法,直到其中之一返回一個非空值。

   為了演示這種自定義方式,這裡創建了一個RouteBase的派生類。我們假設這樣的一個需求環境:需要把一個現有的應用程式遷移到MVC框架,但不論出於什麼原因,我們需要相容之前的URL,那就可以通過這種方式來實現,當然可以通過規則的路由系統來處理——這裡不對這種方式進行討論。

         首先,創建一個處理舊式路由請求的控制器,將其命名為:LegacyController,如:

using System.Web.Mvc;

namespace UrlsAndRoutes.Controllers
{
    /// <summary>
    /// 用以處理舊式 URL 請求的控制器
    /// </summary>
    public class LegacyController : Controller
    {

        public ActionResult GetLegacyURL(string legacyURL)
        {
            // 應用程式遷移到 MVC 之前,請求是針對文件的,因此,實際上是需要在這裡處理被請求的文件。但這裡
            // 只簡單說明一下自定義 RouteBase 的實現原理,所以,此處僅在視圖中顯示這個 URL。
            return View((object)legacyURL);
        }

    }
}

         上面代碼對View方法中的參數做了轉換,如果不轉換,則C#編譯器會誤認為要將參數作為要指定渲染的視圖的名稱的字元串(View方法的一個重載版本的實現)。下麵是這個動作方法的視圖GetLegacyURL.cshtml:

@model string
@{
    ViewBag.Title = "GetLegacyURL";
    Layout = null;
}

<h2>GetLegacyURL</h2>

The URL requested was:@Model

 

1、對輸入URL進行路由

在Infrastructure文件夾中創建一個LegacyRoute類,其內容如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace UrlsAndRoutes.Infrastructure
{
    public class LegacyRoute : RouteBase
    {
        private string[] urls;
        public LegacyRoute(params string[] targetUrls)
        {

        }

        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            RouteData result = null;

            string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;
            if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase))
            {
                result = new RouteData(this, new MvcRouteHandler());
                result.Values.Add("controller", "Legacy");
                result.Values.Add("action", "GetLegacyURL");
                result.Values.Add("legacyURL", "requestedURL");
            }
            return result;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return null;
        }

    }
}

   註冊一條路由,以使其使用新建的這個RouteBase派生類:

        public static void RegisterRoutes(RouteCollection routes)
        {
            // 註冊自定義的 RouteBase 實現
            routes.Add(new LegacyRoute("~/articles/Windows_3.1_Overview.html", "~/old/.NET_1.0_Class_Library"));

        }

2、生成輸出URL

         在LegacyRoute中實現GetVirtualPath方法以使其能夠支持輸出URL的生成。如: 

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData result = null;

            if (values.ContainsKey("legactURL") && urls.Contains((string)values["legacyURL"], StringComparer.OrdinalIgnoreCase))
            {
                // 如果存在一個匹配,將會創建一個 VirtualPathData 對象,在其中傳遞一個對當前對象的引用和出站 URL。由於路由系統已經預先將
                // 字元“/”附加到了這個URL,因此,必須從生成的 URL 上刪除這個前導字元。
                result = new VirtualPathData(this, new UrlHelper(requestContext).Content((string)values["legacyURL"]).Substring(1));
            }

            return null;
        }

   在ActionName.cshtml視圖中添加下麵這段代碼,以使其能禮儀自定義路由生成輸出URL:

    <div>
        @* 經由自定義路由生成一個輸出 URL *@
        This is a URL:
        @Html.ActionLink("Click me", "GetLegacyURL", new { legacyURL = "~/articles/Windows_3.1_Overview.html" })
    </div>

         上面代碼將產生一個這樣的a元素:

<a href=”/articles/Windows_3.1_Overview.html”>Click me</a>

         用legacyURL屬性創建的匿名類型被轉換到了含有同名鍵的RouteValueDictionary類中。

創建自定義路由處理程式

   路由已經依賴這個MvcRouteHandler了,因為MvcRouteHandler把路由系統連接到了MVC框架。但通過實現IRouteHandler介面,路由系統仍允許自定義自己的路由處理程式,如下麵的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;

namespace UrlsAndRoutes.Infrastructure
{
    public class CustomRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new CustomHttpHandler();
        }

    }

    public class CustomHttpHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write("Hello");
        }
    }
}

         IRouteHandler介面的目的是提供生成IHttpHandler介面的實現,且由它負責對請求進行處理。在該介面的MVC實現中,主要負責這幾項工作:查找控制器、調用動作方法、渲染視圖,並將結果寫入到響應中。當然,這裡的實現要簡單的多,此處僅將單詞“Hello”寫到客戶端,且只是文本形式。要想得到最終效果,需要在RouteConfig.cs文件中註冊這個自定義處理程式:

        public static void RegisterRoutes(RouteCollection routes)
        {
            // 註冊自定義路由處理程式
            routes.Add(new Route("SayHello", new CustomRouteHandler()));

        }

 

使用區域

   MVC框架支持將Web應用程式組織成一些區域(Area),每個區域代表應用程式的一個功能端,如管理、結算、客戶支持等等。這使得代碼的管理很有用,尤其是大型項目,如果對所有控制器、視圖和模型只使用一組文件夾,那將會是很難於管理的。

創建區域

   可以直接對項目右鍵,選擇“添加”->“區域”進行添加。還可以在當前的區域中創建其他區域。在剛剛的操作之後,項目中將會出現如下這樣的區域文件夾結構:

                       

         通過Areas/Admin文件夾,可以看出這是一個小型的MVC項目。其中有“Controllers”、“Models”和“Views”的文件夾。前兩個是空的,但“Views”文件夾含有一個“Shared”文件夾和一個Web.config視圖引擎配置文件(這裡暫不對視圖引擎進行討論)。

         另外,這裡還多了一個AdminAreaRegistration.cs文件,如:

using System.Web.Mvc;

namespace UrlsAndRoutes.Areas.Admin
{
    public class AdminAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "Admin";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Admin_default",
                "Admin/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

 

         從清單中可以看出,該類中的RegisterArea方法註冊了一個URL模式為Admin/{controller}/{action}/{id}的路由。當然,也可以在該方法中定義該區域專用的其他路由。

註意:如果要給路由賦名,必須確保這些名稱在整個應用程式而不僅僅是某一區域中是唯一的。

   由於在Global.asax的Application_Start方法中已經對路由的註冊進行過處理,因此,不需要在開發的過程中採取其他措施來確保該註冊方法會被調用: 

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

         上面代碼中對靜態方法AreaRegistration.RegisterAllAreas的調用,會導致MVC框架對應用程式的所有類進行遍歷,找出派生於AreaRegistration的所有類,並調用這些類上的RegisterArea方法。

註意:不用修改Application_Start方法中與路由相關的語句順序。如果在AreaRegistration.RegisterAllAreas之前調用RegisterRoutes,那麼會在區域路由之前定義路由。由於路由系統是按順序評估的,這意味著對區域控制器的請求有可能會用不正確的路由進行匹配。

註:AreaRegistrationContext類中的MapRoute方法會自動把註冊的路由限制到包含該區域控制器的命名空間。也就是說,當某區域創建控制器時,必須把它放在其預設的命名空間中;否則,路由系統將無法找到它。

填充區域

   在上一節“創建區域”一節中,已經知道在一個區域中可以創建控制器、視圖以及模型等。下麵,通過創建一個名為HomeController的控制器類,來演示應用程式中區域之間的分離:

   在下圖中的Controllers文件夾中右鍵添加一個空的控制器:HomeController

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace UrlsAndRoutes.Areas.Admin.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

    }
}

         為了演示,對該控制器中Index動作方法右擊,並添加相應的視圖,添加後的視圖將在:Areas/Admin/View/Home路徑中。

 

視圖內容如下:

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-with" />
    <title>Index</title>
</head>
<body>
    <div>
        <h2>Admin Area Index</h2>
    </div>
</body>
</html>

         從上面介紹可以看出,在一個區域內的工作方式與在一個MVC項目主區中工作是相當類似的。在項目中創建某個項的工作流也是相同的。其效果如下(導航路徑:Admin/Home/Index):

 

解析不明確的控制器問題

   區域可能不像它們所展示的那樣是自包含的。當一個區域被註冊時,所定義的任何路由都被限制到與這個區域關聯的命名空間之中。這也是能夠請求/Admin/Home/Index,並得到WorkingWithAreas.Admin.Controllers命名空間中HomeController類的原因。

   然而,在RouteConfig.cs的RegisterRoutes方法中定義的路由卻不受類似的限制。作為提醒,這裡給出了示例應用程式此時的路由配置: 

        public static void RegisterRoutes(RouteCollection routes)
        { 
            routes.Add(new Route("SayHello", new CustomRouteHandler()));

            routes.Add(new LegacyRoute("~/articles/Windows_3.1_Overview.html", "~/old/.NET_1.0_Class_Library"));

            routes.MapRoute("MyRoute", "{controller}/{action}");
            routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" });
        }

    名為“MyRoute”的路由把來自瀏覽器的輸入URL轉換為Home控制器上的Index動作。這時會收到一個錯誤的消息,因為沒有為這條路由設置命名空間的約束,所以MVC框架會看到兩個HomeController類。為瞭解決這一問題,需要在所有可能導致衝突的路由中,將主控制器命名空間列為優先,如:

        public static void RegisterRoutes(RouteCollection routes)
        { 
            routes.Add(new Route("SayHello", new CustomRouteHandler()));

            routes.Add(new LegacyRoute("~/articles/Windows_3.1_Overview.html", "~/old/.NET_1.0_Class_Library"));

            routes.MapRoute("MyRoute", "{controller}/{action}",null,new[] {“UrlsAndRoutes.Controllers”});
            routes.MapRoute("MyOtherRoute", "App/{action}", new { controller = "Home" }, new[] {“UrlsAndRoutes.Controllers”});
        }

         上面代碼中加粗部分將項目控制器作為了優先。當然也可以對某個區域中的控制器實現優先。

生成對區域動作的鏈接

   對與同一區域中的動作,無需採取特殊的步驟來創建指向這些動作的鏈接。MVC框架會檢測當前請求涉及的特定區域,然後出站URL生成將只在該區域定義的路由中查找一個匹配。如將下麵代碼添加到Admin區域的視圖。

@Html.ActionLink("Click me", "About")

   會生成以下HTML:

<a href=”/Admin/Home/About”>Click me</a>

         為了對不同區域中的動作或根本無區域的動作創建一條鏈接,必須創建一個名為“area”的變數,並用它指定區功能變數名稱,如:

@Html.ActionLink("Click me to go to another area", "Index", new { area = "Support" })

         因此,area被保留為片段變數名。假設創建了名為Support的區域,並有對應的標準路由定義,則將生成如HTML:

<a href=”/Support/Home”>Click me to go to another area</a>

如果想鏈接到頂級控制器(/Controllers文件夾中的一個控制器)上的一個動作,那麼應該把area指定為空字元串,如:

    @Html.ActionLink("Click me to go to another area", "Index", new {area = ""})

URL方案最佳做法

1、  使URL整潔和人性化

   下麵摘抄一些生成友好URL的簡單的綱要:

  • 設計URL來描述它們的內容,而不是應用程式的實現細節。使用/Articles/AnnualReport,而不是使用/Website_v2/CachedContentServer/FromCache/AnnualReport。
  • 儘可能採用內容標題而不是ID號,使用/Articles/AnnualReport,而不是/Articles/2392。如果必須使用一個ID號(以區別具有同樣標題的條目或避免通過標題查找一個條目時,需要多餘的資料庫查詢步驟),那麼兩者都有(如:/Articles/2392/AnnualReport)。這需要多打一些字元,但更要意義,並會改善搜索引擎排列。
  • 不用對HTML頁面使用文件擴展名(如,.aspx或.mvc),但對特殊文件類型要用擴展名(如,.jpg、.pdf、.zip等)。如果是適當的設置了MIME類型,Web瀏覽器不會在意文件的擴展名,但人們卻希望對PDF文件用.pdf擴展名。
  • 創建一種層次感(如:/Products/Menswear/Shirts/Red),這樣,容易讓人猜出父目錄的URL。
  • 不區分大小寫。ASP.NET路由系統預設是不區分大小寫的。
  • 避免使用符合、代碼和字元序列。需要用單詞分隔符時,可以使用短橫(如:/my-great-article)。下劃線是不友好的,而URL編碼的空格是奇特的(/my+great+article)或令人討厭的(/my%20great%20article)。
  • 不用修改URL。打破鏈接等於失去商務。當確實需要修改URL時,通過永久重定向(301)儘可能長時間的繼續支持舊式的URL方案。
  • 具有一致性。在整個應用程式中採用一種URL格式。URL應簡短、易於輸入、可剪輯(人性化可剪輯),且持久穩定,而且它們應該形象化網站結構。

2、GET和POST:選用正確的一個

   一般來說,GET請求應該被用於所有隻讀信息檢索,而POST請求應該被用於各種修改應用程式狀態的操作。用標準的術語說,GET請求用於安全交互(除信息檢索外無其他影響),而POST請求用於不安全交互(作出決定或修改某些東西)。GET請求是可設定地址的——所有信息都包含在URL中,因此它可以設為書簽並鏈接到這些地址。(這些約定是由全球互聯網聯盟(W3C)在http://www.w3.org/Products/rfc2616/rfc2616-sec9.html上設定的)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Table中合併相同內容列的方法比較好辦,網上代碼也很多,參照了一些把它封裝成jquery 插件,調用起來還是蠻好用的。 這個地方稍微修改了下,有的時候td中內容雖然一樣,但是資料庫中的value卻是不一樣的,比如不同的公司,都有人事部,財務部, 公司A的財務部和公司B的財務部不能合併起來,所以我就 ...
  • .NET提供了很多序列化對象的方法,瞭解他們之間的區別才能更好地確定使用哪一種序列化方式並正確地使用。本文從下麵幾個方面對標題中的三種序列化方法進行了分析。 範圍:Property Or Field Or Both 可見性:Public or Private Or All 可訪問性:Readonly ...
  • 聲明:本系列為原創,分享本人現用框架,未經本人同意,禁止轉載!http://yuangang.cnblogs.com 希望大家好好一步一步做,所有的技術和項目,都毫無保留的提供,希望大家能自己跟著做一套,還有,請大家放心,只要大家喜歡,有人需要,絕對不會爛尾,我會堅持寫完~ 如果你感覺文章有幫助,點 ...
  • 1.參數化查詢模糊查詢 sql語句: create proc procegDataAp( @UserName nvarchar(50))asselect * from users where userName=@UserName 給參數賦值 1 <%@ Page Language="C#" Auto ...
  • 1.SQL註入:SQL註入攻擊是web應用程式的一種安全漏洞,可以將不安全的數據提交給運用程式,使應用程式在伺服器上執行不安全的sql命令。使用該攻擊可以輕鬆的登錄運用程式。 例如:該管理員賬號密碼為xiexun,該sql的正確語句應該為: 如果在沒有做任何處理的情況下,在登錄名文本框中輸入(xux ...
  • 常用快捷鍵 自動生成頭部註釋 代碼片段 NuGet Team Foundation 常用的VS快捷鍵 查看與設置快捷鍵 一般在菜單裡面我們直接就可以看到一些功能的快捷鍵。另外,可以依次通過 菜單欄-工具-選項-環境-鍵盤 中查看和設置對應功能的快捷鍵 推薦幾個我比較常用的快捷鍵 我用的是VS2015 ...
  • 1、頁面後臺代碼添加如下靜態變數: 2、在處理數據的開始,初始化total和startTime變數: 3、在處理數據過程中,不斷累加cur: 4、前端每隔200毫秒獲取進度: 5、後臺計算進度: 效果圖(文字錯了,不是“導入進度”,而是“數據處理進度:”): ...
  • 公司業務量比較大,接了很多項目,為了縮短開發周期老闆讓我牽頭搭建了一個敏捷開發框架。 我們主要的業務是做OA、CRM、ERP一類的管理系統,一個通用的後臺搭出來,再配合一些快速開發的組件開發效率能提高很多。 另外老闆一再強調要支持APP開發,一次開發能部署到安卓和IOS上。 作為開篇之作,先介紹一下 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...