[Web API] Web API 2 深入系列(1) 路由

来源:http://www.cnblogs.com/neverc/archive/2016/10/10/5946240.html
-Advertisement-
Play Games

目錄 1. ASP.NET 路由 註冊路由 動態映射HttpHandler 2. WebAPI 路由 註冊路由 調用GetRouteData 3. 2個路由系統銜接 GlobalConfiguration HostedHttpRoute 4. 補充 路由是進入Web API的第一扇門.目的用於確定C ...


目錄

  1. ASP.NET 路由

    • 註冊路由

    • 動態映射HttpHandler

  2. WebAPI 路由

    • 註冊路由

    • 調用GetRouteData

  3. 2個路由系統銜接

    • GlobalConfiguration

    • HostedHttpRoute

  4. 補充

路由是進入Web API的第一扇門.目的用於確定Controller名稱、Action名稱、路由參數.

ASP.NET 路由

註冊路由

在ASP.NET中註冊路由的方式:
RouteCollection.MapPageRoute()

添加1個完整的路由:

var defaults = new RouteValueDictionary//路由變數預設值
{
        {"code","010"},
        {"phone","1000000"},
};
var constraints = new RouteValueDictionary//路由變數約束
{
    {"code",@"0\d{2,3}" },
    {"phone",@"\d{7,9}" },
    {"httpMethod",new HttpMethodConstraint("POST") }
};
var dataTokens = new RouteValueDictionary//路由相關參數,不用於處理路由匹配功能
{
    {"defaultCode","北京" },
    {"defaultPhone","北京X電話" }
};
RouteTable.Routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);

獲取RouteCollection

一般通過RouteTable.Routes

public class RouteTable
{
    private static RouteCollection _instance = new RouteCollection();
 
    public static RouteCollection Routes { get { return RouteTable._instance; } }
}

路由:RouteBase

public abstract class RouteBase
{
  public bool RouteExistingFiles {get; set;} = true;//對現有文件進行路由
  public abstract RouteData GetRouteData(HttpContextBase httpContext);
  public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}

路由預設實現:Route

public class Route : RouteBase
{
    /// <summary>
    /// 路由約束
    /// </summary>
    public RouteValueDictionary Constraints { get; set; }
    /// <summary>
    /// 路由自定義參數(一般存儲備註說明等)
    /// </summary>
    public RouteValueDictionary DataTokens { get; set; }
    /// <summary>
    /// 路由變數預設值
    /// </summary>
    public RouteValueDictionary Defaults { get; set; }
    /// <summary>
    /// 路由對應處理程式對象
    /// </summary>
    public IRouteHandler RouteHandler { get; set; }
    /// <summary>
    /// 路由模板
    /// </summary>
    public string Url { get; set; }
}

忽略路由:
忽略路由本質是添加一個StopRoutingHandler(返回空的HttpHandler)的路由

routes.Ignore("010/1000001");(路由先註冊,先匹配)
routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);

路由約束:
在上面完整的路由添加Demo中,路由約束有2種方式

  1. 正則表達式字元串
  2. 實現IRouteConstraint介面

動態映射HttpHandler

路由是通過UrlRoutingModule這個HttpModule實現動態攔截.

public virtual void PostResolveRequestCache(HttpContextBase context)
{
    RouteData routeData = RouteTable.Routes.GetRouteData(context);
    IRouteHandler routeHandler = routeData.RouteHandler;
    IHttpHandler httpHandler = routeHandler.GetHttpHandler(new RequestContext(context, routeData));
    context.RemapHandler(httpHandler);
}

WebAPI 路由

註冊路由

在Web API中註冊路由的方式:HttpRouteCollection.MapHttpRoute(),
這裡重點看下MapHttpRoute方法內部

public static class HttpRouteCollectionExtensions
{
    public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
    {
        IHttpRoute route = routes.CreateRoute(routeTemplate, (IDictionary<string, object>)defaults, (IDictionary<string, object>)constraints, (IDictionary<string, object>)null, handler);
        routes.Add(name, route);
        return route;
    }
}

獲取HttpRouteCollection

在WebAPI中通過HttpConfiguration的Routes屬性

public class HttpConfiguration : IDisposable
{
    public Collection<DelegatingHandler> MessageHandlers { get; }
    public HttpRouteCollection Routes { get; }
    public ConcurrentDictionary<object, object> Properties { get; }
}

WebAPI路由:IHttpRoute

public interface IHttpRoute
{
  string RouteTemplate { get; }
 
  IDictionary<string, object> Defaults { get; }
 
  IDictionary<string, object> Constraints { get; }
 
  IDictionary<string, object> DataTokens { get; }
 
  HttpMessageHandler Handler { get; }
 
  IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);
 
  IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
}

WebAPI路由預設實現:HttpRoute
由於IHttpRoute設計的非常全,HttpRoute基本就是實現了IHttpRoute.
(這種設計上比RouteBase要優勢很多)

調用GetRouteData

與ASP.NET稍微不同的是

  1. 直接對所有請求進行路由 而不再判斷是否文件存在.
  2. 添加一個VirtualPathRoot的過濾
public class HttpRouteCollection
{
    public virtual IHttpRouteData GetRouteData(HttpRequestMessage request)
    {
        string virtualPathRoot = request.GetRequestContext().VirtualPathRoot;
        IHttpRouteData routeData = this._collection[index].GetRouteData(virtualPathRoot, request);
        return routeData;
    }
}

2個路由系統銜接

Web API提供了一套自身的路由系統,所以不依賴於ASP.NET.

寄宿方式有多種.如果以WebHost的方式.本質上還是走的ASP.NET路由處理.

GlobalConfiguration

WebAPI的配置在HttpConfiguration中提供.

在WebHost中,定義了GlobalConfiguration用來創建HttpConfiguration

public static class GlobalConfiguration
{
public static HttpConfiguration Configuration = GlobalConfiguration.CreateConfiguration();//創建HttpConfiguration

public static HttpMessageHandler DefaultHandler = GlobalConfiguration.CreateDefaultHandler();//創建HttpRoutingDispatcher(WebAPI管道尾部HttpMessageHandler)

public static HttpServer DefaultServer = GlobalConfiguration.CreateDefaultServer();//創建HttpServer(WebAPI管道開頭HttpMessageHandler)

public static void Configure(Action<HttpConfiguration> configurationCallback)//提供方便配置路由
{
    configurationCallback(GlobalConfiguration.Configuration);
}

private static Lazy<HttpConfiguration> CreateConfiguration()
{
    return new Lazy<HttpConfiguration>((Func<HttpConfiguration>) (() =>
    {
        //這裡用HostedHttpRouteCollection實現HttpRouteCollection
        return new HttpConfiguration((HttpRouteCollection) new HostedHttpRouteCollection(RouteTable.Routes));
    }));
}

}

HostedHttpRoute

在GlobalConfiguration中創建的HttpConfiguration對象是用HostedHttpRouteCollection作為參數
這裡我覺得有必要看下CreateRoute和Add方法

internal class HostedHttpRouteCollection : HttpRouteCollection
{
    //真正維護的路由集合
    private readonly RouteCollection _routeCollection;

    //創建路由 MapHttpRoute會調用該方法
    public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
    {
      return (IHttpRoute) new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);
    }

    public override void Add(string name, IHttpRoute route)
    {
        //只是添加到內部的routeCollection中
        //route.ToRoute() => route.OriginalRoute;
      this._routeCollection.Add(name, (RouteBase) route.ToRoute());
    }

    public override IHttpRouteData GetRouteData(HttpRequestMessage request)
    {
        //通過調用內部的Route的GetRouteData
        RouteData routeData = this._routeCollection.GetRouteData(httpContextBase);
        return (IHttpRouteData)new HostedHttpRouteData(routeData);
    }
}

而HostedHttpRoute在WebHost中
相當於用HttpRoute的身 卻提供了真正的Route

internal class HostedHttpRoute : IHttpRoute
{
    //ASP.NET Route
    internal Route OriginalRoute { get; private set; }

    public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
    {
        //內部的OriginalRoute實際為HttpWebRoute
      this.OriginalRoute = (Route) new HttpWebRoute(uriTemplate, defaults1, constraints1, dataTokens1, <strong>(IRouteHandler) HttpControllerRouteHandler.Instance</strong>, (IHttpRoute) this);
      this.Handler = handler;
    }
}

從HostedHttpRoute構造函數中 我們看到了真正的Route為HttpWebRoute 且RouteHandler為HttpControllerRouteHandler.Instance

public class HttpControllerRouteHandler : IRouteHandler
{
    public static HttpControllerRouteHandler Instance{ get { return new HttpControllerRouteHandler(); } }
 
    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return (IHttpHandler) new HttpControllerHandler(requestContext.RouteData);
    }
}

補充

冗餘的設計:

  • HttpRoute中Handler的HttpMessageHandler,未發現有任何地方使用到.

  • HttpRoute和Route中DataTokens,建議直接取消.

備註:

  • 文章中的代碼並非完整,一般是經過自己精簡後的.

  • 本篇內容使用MarkDown語法編輯

首發地址:http://neverc.cnblogs.com/p/5933752.html


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

-Advertisement-
Play Games
更多相關文章
  • 首先需要添加的命名空間 using System.Web.UI.WebControls;using System.Drawing.Drawing2D;using System.Drawing.Imaging; 編寫一個生成隨機數的方法,此方法很簡單,返回的是一個字元串也就是需要顯示到驗證碼中的字元串 ...
  • 當運行一個 Asp.Net Core 應用的時候, WebHostBuilder 根據環境變數來判斷當前運行的是哪個環境,可能是 Development,Staging或者Production.你也可以設置成隨便的一個字元串. 這個鏈接將會告訴你 如何在各種平臺各種環境中設置環境變數.但如果你使用 ...
  • 修飾符 訪問許可權 public 關鍵字是類型和類型成員的訪問修飾符。 公共訪問是允許的最高訪問級別。 對訪問公共成員沒有限制 private 私有訪問是允許的最低訪問級別。 私有成員只有在聲明它們的類和結構體中才是可訪問的 protected 受保護的,訪問許可權於包含類或包含類派生的類型 inter ...
  • 最初接觸時,感覺很好玩,然後就自己研究了下,做了個demo,然後整理下,下次可以直接使用啦,英文大小寫,點擊可以切換 上代碼了。。。。 頁面代碼: <img id="Img" src="/Login/GetCheckCode" /> 這個是頁面JQuery點擊更換方法 $("#Img").click ...
  • 摘要:.NET中的枚舉分為簡單枚舉和標誌枚舉,這次主要總結一下標誌枚舉適用條件,以及它的使用方法,併在文章的最後列舉枚舉使用的一些規範。 在剛接觸.NET的枚舉時,只用簡單的枚舉,對於標記枚舉,只知道是在枚舉類型加上 特性,然後給枚舉值賦予十六進位的值,並且書中還特別明確規定值必須是以2的指數才可以 ...
  • 最近發現easyui時間控制項的值格式不支持帶斜杠的日期(2016/10/31),必須是2016-10-31這類的才能正常使用,否則預設初始化為當前時間 斜杠顯示異常:顯示的是當前系統日期 如上換成橫杠之後正常顯示: 如上,必須把value換成帶橫杠 的日期格式才能正常初始化,已測試過easyui1. ...
  • 說到 Microsoft Bot Framework 其實微軟發佈了已經有一段時間了,有很多朋友可能還不太瞭解,微軟Bot的功能今天我給大家簡單的介紹一下,Bot Framework的開發基礎以及如何使用Bot Framework和我們的一個現有的三方客服(例如一個微信的公共號)集成起來。 ...
  • 背景 本地環境:Win7,Visual Studio 2013, IIS 7.5 WebForm 項目,添加一個http介面給別人調用。 我的做法是添加了一個Controller,Application_Start 裡面添加路由。 然後本地測試通過。 發佈 發佈機器環境: Window Server ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...