继续上面的简易版本,有意思的点剩下便是路由实现了。

路由注册

首先,来看一下基本的路由注册过程。

public FakeNancyModuleWithoutBasePath()
{
Delete["/"] = x => {
return "Default delete root";
}; Get["/"] = x => {
return "Default get root";
}; Get["/fake/should/have/conflicting/route/defined"] = x => {
return new Response { Contents = "FakeNancyModuleWithoutBasePath" };
}; Post["/"] = x => {
return "Default post root";
}; Put["/"] = x => {
return "Default put root";
};
}

这里的Get,Post,Put,Delete对应HttpMethod里面的4个方法。习惯了微软.Net MVC 或者.Net Webapi的人的可能初次使用会觉得比较怪,实际上这种方式在其他各种语言上都有类似的用法。

这里的实现只是4个类型为字典的属性,注册的过程实际上是字典里面赋值。

    public IDictionary<string, Func<dynamic, Response>> Delete { get; private set; }

    public IDictionary<string, Func<dynamic, Response>> Get { get; private set; }

    public IDictionary<string, Func<dynamic, Response>> Post { get; private set; }

    public IDictionary<string, Func<dynamic, Response>> Put { get; private set; }

当然,为了方便模块的划分,路由可以带统一的前缀,这里称为BasePath

 public FakeNancyModuleWithBasePath() : base("/fake")
{
Delete["/"] = x => {
throw new NotImplementedException();
}; Get["/route/with/some/parts"] = x => {
return new Response { Contents = "FakeNancyModuleWithBasePath" };
};
}

路由解析

路由的解析由IRouteResolver来完成,这里使用接口是为了方便将来实现不同的路由解析机制,以及单元测试。

public interface IRouteResolver
{
IRoute GetRoute(IRequest request, IEnumerable<RouteDescription> descriptions);
}

路由的解析核心就一句LINQ,相当的简单的粗暴。

    public IRoute GetRoute(IRequest request, IEnumerable<RouteDescription> descriptions)
{
var matchingRoutes =
from description in descriptions
let matcher = BuildRegexMatcher(description)
let result = matcher.Match(request.Path)
where result.Success
select new
{
Groups = result.Groups,
Description = description
}; var selected = matchingRoutes
.OrderByDescending(x => GetSegmentCount(x.Description))
.FirstOrDefault(); return selected != null ?
new Route(selected.Description.GetModuleQualifiedPath(), GetParameters(selected.Description, selected.Groups), selected.Description.Action) :
new NoMatchingRouteFoundRoute(request.Path);
}

下面来拆分这个过程。

descriptions是什么?

这个是我们刚开始注册的路由字典,当然预先已经依据请求的Http Verb预先过滤了一轮,这里的过滤方式采用反射request.Verb动词的方式,这个有改进的空间,但是无异于提供了一种实现的手段。我们的例子中,这一步就只留下了所有Get字典下面的路由规则。

public static IEnumerable<RouteDescription> GetRouteDescription(this NancyModule source, IRequest request)
{
const BindingFlags flags =
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase; var property =
typeof(NancyModule).GetProperty(request.Verb, flags); if (property == null)
return Enumerable.Empty<RouteDescription>(); return
from route in property.GetValue(source, null) as IDictionary<string, Func<object, Response>>
select new RouteDescription
{
Action = route.Value,
ModulePath = source.ModulePath,
Path = route.Key
};
}

let是LINQ 里面子查询的一个简易语法,这里首先使用嵌套语句遍历每个路由规则构建正则表达式。

对于不带参数的路由规则,正则表达就构建只是简单的忽视大小写。

对于带参数的路由规则,需要提取值。关于正则表达式的基础知识,参见其他博客。

[p2]

当然,规则很有可能有冲突,这里按照一定的规则返回第一条。

var selected = matchingRoutes
.OrderByDescending(x => GetSegmentCount(x.Description))
.FirstOrDefault();

当前版本的优先级规则是片段的数量

    private static int GetSegmentCount(RouteDescription description)
{
var moduleQualifiedPath =
description.GetModuleQualifiedPath(); var indexOfFirstParameter =
moduleQualifiedPath.IndexOf('{'); if (indexOfFirstParameter > -1)
moduleQualifiedPath = moduleQualifiedPath.Substring(0, indexOfFirstParameter); return moduleQualifiedPath.Split('/').Count();
}

当前匹配的路由规则"/fake/should/have/conflicting/route/defined" 的片段数就是7,当片段数也无法区别的时候就返回其中一条。

最后返回我们需要的Route对象。

  public Route(string path, RouteParameters parameters, Func<object, Response> action)
{
if (path == null)
{
throw new ArgumentNullException("path", "The path parameter cannot be null.");
} if (action == null)
{
throw new ArgumentNullException("action", "The action parameter cannot be null.");
} this.Path = path;
this.Parameters = parameters;
this.Action = action;
}

Route 里面的对象就是我们路由规则里面注册的方法。

.NET Nancy 详解(二) 简易路由实现的更多相关文章

  1. XSD详解二 - 简易元素、属性、内容限定

    一.XSD 简易元素 XML Schema 可定义 XML 文件的元素. 简易元素指那些只包含文本的元素.它不会包含任何其他的元素或属性. 1.什么是简易元素? 简易元素指那些仅包含文本的元素.它不会 ...

  2. pika详解(二) BlockingConnection

    pika详解(二) BlockingConnection   本文链接:https://blog.csdn.net/comprel/article/details/94592348 版权 Blocki ...

  3. .NET DLL 保护措施详解(二)关于性能的测试

    先说结果: 加了缓存的结果与C#原生代码差异不大了 我对三种方式进行了测试: 第一种,每次调用均动态编译 第二种,缓存编译好的对象 第三种,直接调用原生C#代码 .net dll保护系列 ------ ...

  4. PopUpWindow使用详解(二)——进阶及答疑

      相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...

  5. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  6. logback -- 配置详解 -- 二 -- <appender>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

  7. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  8. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  9. Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)

    View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇  ...

随机推荐

  1. 实现Redis的主从复制配置

    实现Redis的主从复制配置比较简单,而且容易明白. 下图是要配置的主从复制结构图: 1.说明 Redis主从复制中一个主服务可以有多个从服务,一个从服务可以有多个从服务. 配置比较简单,只需要更改r ...

  2. 通过Nginx和Nginx Plus阻止DDoS攻击

    分布式拒绝服务攻击(DDoS)指的是通过多台机器向一个服务或者网站发送大量看似合法的数据包使其网络阻塞.资源耗尽从而不能为正常用户提供正常服务的攻击手段.随着互联网带宽的增加和相关工具的不断发布,这种 ...

  3. UITableView 系列之自定义 UITableViewCell

    http://www.360doc.com/content/14/0225/14/11029609_355567657.shtml

  4. 【GoLang】golang 如何像Java 一样通过类名反射对象?

    结论: golang不支持解析string然后执行. golang的反射机制只能存在于已经存在的对象上面. 不知道后续的版本有没有规划,现在只能先加载注册,然后实现类似Java工厂模式的反射. 代码示 ...

  5. (转)利用eclipse external tool 执行mvn jetty:run

    一.如果这个工程是标准的maven-webapp那么基本上不用修改,直接运行jetty:run就可以执行. 但是有时候会报错说 [ERROR] No plugin found for prefix ' ...

  6. javascript 数组去重

    2015年5月15日 20:17:05 星期五 原理: .......(说不清楚, 自己看代码吧, 很简单.....) //去重 var hash_already_input = {}; for (v ...

  7. Innodb 表空间卸载、迁移、装载

    从MySQL的Innodb特性中我们知道,Inndob的表空间有共享和独享的特点,如果是共享的.则默认会把表空间存放在一个文件中(ibdata1),当开启独享表空间参数Innodb_file_per_ ...

  8. java操作数据库出错

    "无效的列索引"其实是个低级的错误 出错原因:1.sql串的?号数目和提供的变量数目不一致:例如:jdbcTemplate.update(sql, new Object[] {ne ...

  9. 108. Convert Sorted Array to Binary Search Tree

    题目: Given an array where elements are sorted in ascending order, convert it to a height balanced BST ...

  10. [Android Pro] linux下查看一个文件的属性(ls,lsattr,file,stat)

    reference to : http://blog.chinaunix.net/uid-28458801-id-4615294.html 查看文件属性有多种方法,且这些方法中偏向不同,具体如下: 1 ...