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

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

161453-20151104102932680-381106380.png

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

[p2]161453-20151104103003399-365934486.png

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

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

转载于:https://www.cnblogs.com/bnbqian/p/4935227.html

什么是Nancy呢?如果你学习过Ruby的话,就会知道Ruby有个框架叫做Sinatra,Nancy就是Sinatra的.Net版本。如果你感觉微软的MVC过于笨重、过于繁琐,那么Nancy可能就是你苦苦寻找的东西。Nancy是一个轻量级的独立的框架,下面是官网的一些介绍:Nancy 是一个轻量级用于构建基于 HTTP 的 Web 服务,基于 .NET 和 Mono 平台,框架的目标是保持尽可能多的方式,并提供一个super-duper-happy-path所有交互。Nancy 设计用于处理  DELETE ,  GET ,  HEAD ,  OPTIONS ,  POST ,  PUT   和 PATCH  等请求方法,并提供简单优雅的 DSL 以返回响应。Nancy和Asp.net MVC原理相似,但有自己的一套路由机制,在使用上更加易用,可以用Nancy快速开发一些网站。Nancy并不依赖任何现有的框架,所以他可以运行在任何平台上面。官方网站 http://nancyfx.org/ 更详细的介绍参见 http://blog.spinthemoose.com/2011/07/18/nancy-a-micro-web-framework-for-net/ 顺便介绍个使用Nancy 做的Quartz.net的web控制台 https://quartznetwebconsole.codeplex.com/ 参考文章:使用Nancy和Simple.Data两个轻量级的框架打造一个分布式开发系统(一)Frictionless .NET Web App Development with NancyFrictionless .NET Web App Development with Nancy Part II - Introducing a View EngineFrictionless .NET Web App Development with Nancy Part III - Introducing MongoDBFrictionless .NET Web App Development with Nancy Part IV – Hosting Slides from ANUG talk on Nancy扩展NoteService,支持NancyFx用Nancy和Simple.Data创建一个图片博客 第一部分:开始一个工程用Nancy和Simple.Data创建一个图片博客 第部分:定义routes用Nancy和Simple.Data创建一个图片博客 第三部分:渲染一些ViewsIntegrating Nancy with protobuf-netBuild Simple Web UIs with the Nancy Framework轻量级MVC框架:Nancy学习 标签:web框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值