前文中,我介紹了Nancy的來源和優點,並創建了一個簡單的Nancy應用,在網頁中輸出了一個"Hello World",本篇我來總結一下Nancy中的路由
Nancy中的路由的定義
Nancy中的路由是定義在每個Module的構造函數中的。
為了創建一個路由,你需要定義如下4個部分
- Http請求的方法(Method)
- 路由模板(Pattern)
- 處理對應路由模板請求的響應方法(Action)
- 條件約束(Condition)
以前篇的代碼為例
public class HelloModule : NancyModule
{
public HelloModule()
{
Get("/", p => "Hello World");
}
}
當前構造中定義了的一個路由
- 它的Http請求方法是GET
- 它的路由模板是"/", 即網站根目錄
- 它的響應結果是輸出一個"Hello World"
- 這里它沒有指定任何的條件約束
Nancy中支持的Http請求方法(Http Method)
Nancy中支持DELETE
, GET
, HEAD
, OPTIONS
, POST
, PUT
和PATCH
Nancy中的路由模板(Pattern)
下面我們介紹一下Nancy中默認提供的幾種路由片段和約束條件。
Nancy中的幾種路由片段
Nancy中默認支持一下幾種路由片段。
純文字片段(Literal Segment)
例: /products/cocacola
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/cocacola", p => "Coca Cola");
}
}
含變量的片段(Capture Segment)
Nancy中Get方法的第二個參數是一個Func委托, Func<dynamic, object>
, 該委托的指向方法的第一個參數是dynamic
類型的變量, 我們可以從該變量上獲取Url中的可變參數的值。
例: /products/{productName}
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productName}", p => p.productName);
}
}
含可空變量的片段(Capture Segment - Optional)
Nancy中的Url參數也支持可空類型, 只需要在參數后面加一個問號。
例:/products/{productName?}
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productName?}", p => p.productName == null ? "Missing the name" : p.productName);
}
}
Nancy中對於可空類型的參數也可以設置默認值, 默認值可以放在問號的后面。
例:/products/{productName?defaultName}
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productName?defaultName}", p => p.productName);
}
}
正則片段(RegEx Segment)
Nancy的路由模板中也可以使用正則表達式。
例:/products/(?
[\d]{2,})
public class ProductModule : NancyModule
{
public ProductModule()
{
Get(@"/products/(?<productId>[\d]{2,})", p => "Your product id is " + p.productId);
}
}
這個正則的意思是只允許2位數以上的整數。
貪婪片段(Greedy Segment)
Nancy中可以在變量尾部追加一個星號,表示匹配從當前位置到Url結尾的所有字符串。
例:/products/{productName*}
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productName*}", p => p.productName);
}
}
現在我們把星號去掉看一下區別。
例:/products/{productName}
不能匹配到任何路由模板。
優先級別
在ASP.NET MVC中我們會使用MapRoute方法定義的路由模板,當有請求進入的時候,MVC Handler會根據我們定義的路由模板順序來依次匹配, 如果匹配成功就會進入對應的Action方法處理請求。
那么在Nancy這種無配置的框架中如何確定模板的匹配順序呢?
在Nancy中,對於默認提供的幾種路由片段類型,Nancy都提供了一個模板分數(Pattern Scoring),模板分數越高的越優先匹配。
Nancy中幾種基本模板類型的分數
模板 | 分數 |
---|---|
純文字片段(Literal Segment) | 10000 |
含變量的片段(Capture Segment) | 1000 |
含可空變量的片段(Capture Segment - Optional) | 1000 |
正則片段(RegEx Segment) | 1000 |
貪婪正則片段(Greedy RegEx Segment) | 100 |
多變量片段(Multiple Captures Segment) | 100 |
貪婪片段(Greedy Segment) | 0 |
例:當前有2個路由模板"/products/{productName}"和"/products/coffee",我們請求Url為/products/coffee時,結果如下
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productName}", p => p.productName);
Get("/products/coffee", p => "Hello Coffee.");
}
}
這里是因為純文字片段的優先級別比含變量的片段高,所以優先處理了當前請求。
路由片段參數類型約束
Nancy還可以在路由模板中對參數類型進行約束。約束的格式是"{變量名: 約束類型}"。
例: "/products/{productId:int}"
public class ProductModule : NancyModule
{
public ProductModule()
{
Get("/products/{productId:int}", p => "Product id is " + p.productId);
}
}
當約束條件匹配時,請求成功。
當約束條件不匹配時,請求失敗。
常規約束
Nancy中提供如下的常規約束類型。
約束類型 | 解釋說明 |
---|---|
int | 只允許Int32的數字 |
long | 只允許Int64的數字 |
decimal | 只允許小數 |
guid | 只允許Guid |
bool | 只允許true/false |
alpha | 只允許字母 |
datetime | 只允許時間 |
datetime(format) | 只允許特定格式時間 |
min(mininum) | 允許的最小整數值 |
max(maxinum) | 允許的最大整數值 |
range(mininum, maxinum) | 允許的整數值范圍 |
minlength(length) | 允許的字符串最小長度 |
maxlength(length) | 允許的字符串最大長度 |
length(length) | 允許的字符串長度范圍 |
version | 只允許版本號,例1.0.0 |
自定義約束
Nancy中可以通過繼承RouteSegmentConstraintBase
和ParameterizedRouteSegmentConstraintBase
來自定義約束條件。
RouteSegmentConstraintBase
- 不帶參數約束條件的積累
ParameterizedRouteSegmentConstraintBase- 帶參數約束條件的基類
下面我們自己創建一個email約束。
首先我們創建一個EmailRouteSegmentConstraint
類,並繼承RouteSegmentConstraintBase
類,其代碼如下
public class EmailRouteSegmentConstraint : RouteSegmentConstraintBase<string>
{
public override string Name
{
get { return "email"; }
}
protected override bool TryMatch(string constraint, string segment, out string matchedValue)
{
if (segment.Contains("@"))
{
matchedValue = segment;
return true;
}
matchedValue = null;
return false;
}
}
其中TryMatch方法表示嘗試判斷參數是否匹配,如果返回true就是匹配成功,false就是匹配失敗。Name屬性表示了當前約束的名稱。
我們創建一個新的StaffModule
類,其代碼如下
public class StaffModule : NancyModule
{
public StaffModule()
{
Get("/staff/{email:email}", p => "Your email is " + p.email);
}
}
下面我們啟動項目,在瀏覽器中輸入/staff/lamondlu@qq.com,請求被正確處理。
這時如果我們在瀏覽器中輸入/staff/lamondlu, 系統會返回404。
Nancy中的條件約束(Condition)
Nancy中還可以實現針對請求的一些條件約束。
例如:當提交的Form中包含email字段,且email字段的值為lamondlu@qq.com時才處理當前請求。
public class StaffModule : NancyModule
{
public StaffModule()
{
Post("/staff", p => "Submited", p => p.Request.Form.email == "lamondlu@qq.com");
}
}
這里我加入了第三個參數condition, condition是一個Func<NancyContext, bool>
類型的委托, 從NancyContext中我們可以獲得請求的所有信息。這里我從請求的Form中讀取的email字段,如果email字段的值是lamondlu@qq.com, Nancy將返回一個Submited文本。
下面我們使用Postman來測試一下。
首先我們在Form中不加入任何字段,請求結果如下。
然后我們在Form中加入email字段,且值為lamondlu@qq.com, 請求結果如下。
請求被正確處理了。
以上就是Nancy路由部分的全部內容,有興趣的同學可以加我的QQ:309728709一起研究, 下一次我將分享Nancy中的視圖引擎。