使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【外传】——Attribute Routing

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【外传】——Attribute Routing

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html

题外话:由于这个技术点是新学的,并不属于原系列,但借助了原系列的项目背景,故命名外传系列,以后也可能在这个系列中附加一些新的技术。

前言

在Web Api 2.0中,提出了一种新的配置路由方式——基于特性的路由(Attribute-based Routing),在我们之前介绍的配置路由方式称为——基于公约的路由(Convention-based Routing),新的路由配置方式同样应用在MVC5中,因此本文就来介绍一下基于特性的路由。

在之前的一篇文章中,我们处理了这么一个业务——实现学生选课。我们是通过在“WebApiConfig”定制了一条路由数据来实现的,这条路由实现了选课以及根据课程Id来查询选择选择该课程的所有学生信息,感觉设计还可以。在实际应用中一般来说查询用的是最多的,使用Attribute Routing来注册路由会更灵活,控制起来也更方便,更符合Rest。本文以根据课程的名字来查询所有选择该课程的学生信息以及根据课程名字以及学生名字查询某一学生的信息。

基于特性的路由介绍

顾名思义,新路由将使用一个特性来实现路由注册,如下:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=true, Inherited=true)]
    public sealed class RouteAttribute : Attribute, IHttpRouteInfoProvider
    {
        public RouteAttribute();
        public RouteAttribute(string template);

        public string  Name { get; set; }
        public int     Order { get; set; }
        public string  Template { get; private set; }
    }

这个类包含3个属性:Name指路由的名字,Order是指路由的顺序,Template就是我们要去匹配URL的模板

实现Attribute Routing

原理性的东西不多介绍的(我也没多研究 呵呵),能把学到的技术运用到实际中才是王道,上来一大堆原理容易晕,以后需要深入研究再看原理。

在“EnrollmentsController”中新增一个方法GetStudentsInfo:

[Route("api/enrollments/{courseName}/{studentName?}")]
        public IEnumerable<StudentBaseModel> GetStudentsInfo(string courseName, string studentName="")
        {
            IQueryable<Student> query;
            Course course=  TheRepository.GetAllCourses().Where(c => c.Name == courseName).FirstOrDefault();
            if (course==null )
            {
                return null ;
            }
             query = TheRepository.GetEnrolledStudentsInCourse(course.Id).OrderBy(s => s.LastName);
            if (!string.IsNullOrWhiteSpace(studentName))
            {
                query = query.Where(s => s.FirstName == studentName);
            }
            var totalCount = query.Count();

            System.Web.HttpContext.Current.Response.Headers.Add("X-InlineCount", totalCount.ToString());

            var results = query

                        .ToList()
                        .Select(s => TheModelFactory.Create(s));

            return results;

        }

在我们的Action上使用了RouteAttribute。分析一下这个URL模板("api/enrollments/{courseName}/{studentName?}"),{courseName}会匹配到Action的courseName参数上,对于Action的另一个参数studentName是一个可选参数,也就是说请求中没有给出值那么就是默认的空字符串,有值得话就会被赋值,因此我们在“{studentName}”后面加上? 标记为可选的URI参数。

ok,就这么简单,测试一次:

结果:

呃,出错了。。。

一个新的问题

出错了,不过不管怎么说解决方案总归是有的,首先看下错误原因:是在LearningControllerSelector类的方法中出现了空引用,那么我们就不得不看下这个方法:

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {
            var controllers = GetControllerMapping(); //Will ignore any controls in same name even if they are in different namepsace

            var routeData = request.GetRouteData();

            var controllerName = routeData.Values["controller"].ToString();

            HttpControllerDescriptor controllerDescriptor;

            if (controllers.TryGetValue(controllerName, out controllerDescriptor))
            {

                var version = "2";

                var versionedControllerName = string.Concat(controllerName, "V", version);

                HttpControllerDescriptor versionedControllerDescriptor;
                if (controllers.TryGetValue(versionedControllerName, out versionedControllerDescriptor))
                {
                    return versionedControllerDescriptor;
                }

                return controllerDescriptor;
            }

            return null;

        }

看了这段代码我们不难发现这个方法是我们重写了基类的方法,目的是为了实现现版本控制(详情可移步:http://www.cnblogs.com/fzrain/p/3558765.html),在我们重写的方法中我们用到了RouteData中包含的Controller的名字,而这个名字是由基于公约的路由与URI匹配得到的,因此我们这里肯定是没有的。因为我们的项目混合了2钟路由配置,而自定义的方法是针对基于公约的路由配置,因此对于Attribute Routing我们直接使用默认的选择方式:

在“var controllerName = routeData.Values["controller"].ToString(); ”代码之前加一个判断:

if (string.IsNullOrWhiteSpace(routeData.Route.RouteTemplate))
            {
               return   base.SelectController(request);
            }

再次请求就会得到如下结果:

结果正确,解决方案感觉还可以再考虑考虑,大家有什么好的建议可以提。但是不管怎么说,有一点是明确的:对于基于特性的路由规则,不需要包含Controller的名字,在本案列中感觉上是寻找Acton上的路由模板来匹配请求的URI,然后确定对应的Action。

总结

基于特性路由(Attribute Routing)是一种新的定制路由规则方式,与传统的配置方式相比更灵活,但同时比较分散,在web api中,2钟路由配置方式可以共存,所以本文只是介绍一种新的配置方式,做项目时也可以多一种选择。

本文参考相关链接:http://www.cnblogs.com/aehyok/p/3449851.html

                      http://www.cnblogs.com/artech/p/attribute-routing-01.html

源码地址:https://github.com/fzrain/WebApi.eLearning

时间: 2024-12-21 23:00:08

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【外传】——Attribute Routing的相关文章

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【四】——实现模型工厂,依赖注入以及格式配置

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[四]--实现模型工厂,依赖注入以及格式配置 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在上一篇中,我们已经初步开始使用Web Api了,但同时出现了一些很多不足之处,本章我们就着重来解决这些不足. 上篇导航:http://www.cnblogs.com/fzrain/p/3510035.html 配置JSON的格式 Web Api提供Xml和JSON作

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【十】——使用CacheCow和ETag缓存资源

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[十]--使用CacheCow和ETag缓存资源 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 本文将使用一个开源框架CacheCow来实现针对Http请求资源缓存,本文主要介绍服务器端的缓存. 使用缓存技术可以很好的提高Web Api的性能,减小服务器的开销.我们把这种缓存形式称之为:条件化请求(Conditional Requests).具体表现为:客户

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[开篇][持续更新中...] 最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tutorial-building-asp-net-web-api-restful-service/.于是打算跟着学一下,把学习过程记录在博客园的同时也分享给大家. 每一篇结束后我都会把代码共享 由于

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【三】——Web Api入门

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[三]--Web Api入门 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 经过前2节的介绍,我们已经把数据访问层搭建好了,从本章开始就是Web Api部分了.在正式开始之前,再一次回顾一下Web Api的应用场景:Web Api可以与 MVC,WebForm结合使用,也可以作为一个单独的Web服务.在正式讨论Web Api的配置以及如何构造我们的URI来消

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【七】——实现资源的分页

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[七]--实现资源的分页 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这篇文章我们将使用不同的方式实现手动分页(关于高端大气上档次的OData本文暂不涉及,但有可能会在系列的后期介绍,还没确定...),对于分页的结果,我们将采用2种不同的方式响应给客户端(1.将分页元数据封装在响应Body中2.在http响应报文头部添加分页信息). 众所周知,在服务器端一

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[五]--在Web Api中实现Http方法(Put,Post,Delete) 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现--Post(新增),Put(修改),Delete(删除),Get(查询).查询在前几章我们已经实现了,本章就在我们的案列(CourseController)

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【六】&amp;mdash;&amp;mdash;实现资源间的关联

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[六]--实现资源间的关联 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章主要介绍一下资源间的关联--例如在学生和课程之间就存在这样的关联:每一个课程都会有多个学生来选,如何获取这些有关联的信息?如何实现选课的业务?对于客户端应该怎么来调用呢?下面给出解决方案: 配置对应的路由 对于上面的需求,我们可以先定制一个URI模板:"api/courses

使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[八]--Web Api的安全性 系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议(http://),因此客户端与服务器之间的通信是没有加密的.在本篇中,我们将在"StudentController"中添加身份验证功能--通过验证用户名与密码来判断是否是合法用

通过Knockout.js + ASP.NET Web API构建一个简单的CRUD应用

较之面向最终消费者的网站,企业级Web应用对用户体验的要求要低一些.不过客户对"用户体验"的要求是"与日俱增"的,很多被"惯坏了"的用户已经不能忍受Postback带来的页面刷新,所以Ajax在企业级Web应用中得到了广泛的应用.企业级Web应用的一个特点是以"数据处理"为主,所以"面向绑定"的Knockout.js 是一个不错的选择.ASP.NET Web API,作为.NET平台最好的REST服务开发平