天天看點

NancyFX 第五章 Nancy 路由

    在Nancy中,最為神奇的莫過于路由了,定義路由子產品是構成Nancy應用的骨架。在Nancy中定義路由,和在 ASP.NET MVC那些類似的架構中有着非常大的差別。

    以 ASP.NET MVC 為例,通常情況需要建立一個控制類。多數情況下,這個類提供了路由的約定。通過定義您的控制器類名和該類中的方法的名稱,就能定義了該代碼所處理的“路由”

    請看下面的例子:

using System;
using System.Linq;
using System.Web.Mvc;
namespace Intranet.WebUi.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
       {
           return View();
       }
    }
}      

    這段從标準ASP.NET MVC 應用程式摘錄的代碼定義了Home路由下的Index節點,用于将Http請求路由到這段代碼 ,請求位址應該是這樣的   /home/index 。 如果使用Nancy,就會有些不一樣了。

    首先,在Nancy應用中,繼承NancyModule基類,才能定義路由。第二,不是每個路由都需要定義在一個單獨的類中(如 MVC示例),可以在子產品類的構造構造函數中定義路由,使用Rest動詞定義路由類型。

    當然這可能導緻過于龐大的構造函數,但是也有很多方式處理這個問題。

    在往下看之前,我們需要先了解一些概念......

    如果您習慣于看到從 web 浏覽器的觸發的web 請求,你可能不知道,在它之下是相當複雜的協定。如果你從事于 web相關的開發工作,很可能聽說過稱為 HTTP 協定。HTTP通過使用一系列的動詞來表示用戶端希望伺服器采取某些行動。

    采用Nancy,也無需了解太多HTTP動詞的細節。實際上建立一個REST 風格的應用,用到下面的Rest動詞就好:

  • GET
  • POST
  • PUT
  • DELETE

    GET,顧名思義,用來檢索資料從服務;同樣,删除是習慣請求資料被删除。PUT和POST可能經常會造成混亂。遵循規範, PUT意思是“整體替換指定的”,而POST用于“在現有基礎上添加”。許多開發人員建立基于 rest 風格的應用程式,也不過就是使用GET和POST。

    這方面Nancy走的更進一步,不同于大多數其他 web 為基礎的架構,你可以定義自己的動詞。在某種意義上,允許您建立您自己的基于HTTP的特定領域的語言。讓我們深入剖析的Nancy路由子產品,看看是如何工作的。

    我們的第一個Nancy路由子產品

    看下面的代碼

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
        public BaseRoutes()
        {
            Get[@"/"] = _ => Response.AsFile("index.html", "text/html");
        }
    }
}      

    作為一個Nancy項目,這是例子再簡單不過了。

    這個隻有十一行的代碼,監聽所有向應用程式的"/"根路徑的請求,傳回"Content"檔案一個名為“index.html”HTTP頁面。

    Content 檔案夾是Nancy查詢檔案的預設檔案夾,在下一張關于視圖Views的章節,我們會涉及更多,但現在,隻是確定項目有一個檔案夾被稱為Content,所有的 HTML 檔案都放置于此。

    撇開通常命名空間和類的代碼部分 ,隻有兩點是這個Nancy路由子產品添加的:繼承了NancyModule ,在構造函數中使用GET規則。

    GET規則意味着這将響應使用 GET 動詞的 HTTP 調用,代碼将執行響應根路徑的 GET 請求。

    如何你要擴充這個子產品處理 GET,POST,PUT,和DELETE,你需要這麼處理:

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
        public BaseRoutes()
       {
           Get[@"/"] = _ => Response.AsFile("index.html", "text/html");
           Put[@"/"] = _ => Response.AsFile("index.html", "text/html");
           Post[@"/"] = _ => Response.AsFile("index.html", "text/html");
           Delete[@"/"] = _ => Response.AsFile("index.html", "text/html");
       }
   }
}      

     子產品監聽的路徑或路由需要放置到動詞後面的方括号中。是以,舉個例子,你可以像下面是的修改:

using Nancy;
namespace nancybook.modules25
{
    public class BaseRoutes : NancyModule
    {
       public BaseRoutes()
       {
           Get[@"/allpeople"] = _ => Response.AsFile("index.html", "text/html");
           Put[@"/allpeople"] = _ => Response.AsFile("index.html", "text/html");
           Post[@"/newperson"] = _ => Response.AsFile("index.html",
           "text/html");
           Delete[@"/singleperson"] = _ => Response.AsFile("index.html",
           "text/html");
       }
    }
}      

    為了示範的目的,每個請求都傳回一個靜态網頁。在真是環境中,每個實際的請求你可能都需要根據實際的功能需求編寫合适的處理代碼。本章接下來對這個話題進行更多的介紹。

    你也可以為你的子產品編寫通用的路徑。試想下面的例子:

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
        public BaseRoutes()
        {
            Get[@"/single"] = _ => Response.AsFile("index.html", "text/html");
            Put[@"/single"] = _ => Response.AsFile("index.html", "text/html");
            Post[@"/new"] = _ => Response.AsFile("index.html", "text/html");
            Delete[@"/single"] = _ => Response.AsFile("index.html", "text/html");
        }
     }
}      

     很快你就會發現代碼變得難以閱讀。 另外,如果你想用一緻的命名方法來編寫你的API,重用single 和new 來處理應用程式中的其他資源。

     再一次,Nancy展現了其簡單的處理方式,僅僅通過在子產品類中重載父類NancyModule的構造函數并傳遞根目錄路徑。

namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
        public BaseRoutes() : base("/people")
        {
            Get[@"/single"] = _ => Response.AsFile("index.html", "text/html");
            Put[@"/single"] = _ => Response.AsFile("index.html", "text/html");
            Post[@"/new"] = _ => Response.AsFile("index.html", "text/html");
            Delete[@"/single"] = _ => Response.AsFile("index.html", "text/html");
        }
    }
}      

    通過添加父類構造函數的調用,瞬間已經更改了您的子產品将響應的所有 Url:

  • GET /single
  • PUT /single
  • POST /new
  • DELETE /single

    轉變為:

  • GET /people/single
  • PUT /people/single
  • POST /people/new
  • DELETE /people/single

     加上一點創造性思維和一些聰明的軟體開發點子,你甚至可以在很多地方重用同一個控制器。

    在我們繼續之前,還是要提一個關于“Rest動詞”的警告。一些托管環境(包括ASP.NET/IIS)預設是不支援一些常用的動詞。

    在前面的示例中,如果運作在 IIS 中,你會發現PUT和DELETE導緻伺服器傳回以下錯誤: 503   方法不被允許。

    這并不是Nancy的問題,而是,IIS 隻允許兩個最常見動詞(GET 和 POST)。如果你參考下Stack Overflow的文章,這個問題不難解決。

    路由參數

   正如其他的web工具包,您的路由子產品也可以接收各種各樣的資料。這些資料包括簡單的 URL 參數,如記錄的 ID 或部落格分類号,也有通過POST或PUT傳遞的複雜對象。

   在這一章,我們會講解基于路由的簡單資料,以後的章節再介紹複雜的對象。

    你已經看到了,為響應給定的請求,在Nancy路由子產品中修改URL非常簡單。但如果需要在URL中傳遞記錄ID該怎麼辦?

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
       public BaseRoutes() : base("/people")
       {
           Get[@"/{id}"] = parameters =>
           {
               var myRecordId = parameters.id;
               return Response.AsFile("Pages/index.html", "text/html");
           };
        }
    }
}      

如果你想限定參數的類型,請看下面示例:

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
        public BaseRoutes() : base("/people")
       {
            Get[@"/{id:int}"] = parameters =>
           {
               var myRecordId = parameters.id;
               return Response.AsFile("Pages/index.html", "text/html");
           };
       }
    }
}      

    注意在路由參數上增加了int限制;任何嘗試傳遞非整數參數都會導緻404未找到的錯誤。Nancy定義許多這些的限制,基本上都綁在.NET 基元類型:

  • long
  • decimal
  • guid
  • bool
  • datetime

    你可以在URL中添加很多的參數,如下:

using Nancy;
namespace nancybook.modules
{
    public class BaseRoutes : NancyModule
    {
       public BaseRoutes() : base("/people")
       {
           Get[@"/person/{age:int}/{surname}/categories/{category}/{city}"] =
           parameters =>
           {
               return Response.AsFile("Pages/index.html", "text/html");
           };
       }
    }
}      

    總結

    在本章中,您已經學到了如何使用路由子產品建立應用程式的骨架,了解到了Nancy與ASP.NET MVC在路由上定義的不同。你已經看到了如何定義路由路徑,不再通過類的名字控制路由定義,了解了如何使用動詞和在URL中傳遞參數。在下一章中,我們會看看視圖引擎,看看如何傳回一些其他東西,不隻是普通的 HTML 文檔。