转载

Nancy 详解(二) 简易路由实现

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

路由注册

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

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 里面子查询的一个简易语法,这里首先使用嵌套语句遍历每个路由规则构建正则表达式。

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

Nancy 详解(二) 简易路由实现

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

[p2] Nancy 详解(二) 简易路由实现

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

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 里面的对象就是我们路由规则里面注册的方法。

正文到此结束
Loading...