转载:http://www.th7.cn/Program/net/201410/302571.shtml

ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程。在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一文中,体验了通过模版、惯例、HTTP方法来设置路由,这种做法的好处是把路由模版统一放在了App_Start文件夹下的WebApiConfig类中,方便管理,但缺点是不够灵活。

REST把一切都看成资源,有时候,一个资源连带子资源,比如Customer和Orders密切关联,我们可能希望输入这样的请求:customers/1/orders,但仅仅凭借惯例,很难实现这种路由。而实际上,ASP.NET Web API为我们准备了Route特性,该特性可以直接打到Action上,使用非常灵活、直观。

下面就在ASP.NET MVC4下来体验Route特性的使用方法。

允许Route特性

首先需要在WebApiConfig中设置。


using System.Web.Http;

namespace MyRoutingAttributes4
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //设置特性路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            // 取消注释下面的代码行可对具有 IQueryable 或 IQueryable<T> 返回类型的操作启用查询支持。
            // 若要避免处理意外查询或恶意查询,请使用 QueryableAttribute 上的验证设置来验证传入查询。
            // 有关详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=279712。
            //config.EnableQuerySupport();

            // 若要在应用程序中禁用跟踪,请注释掉或删除以下代码行
            // 有关详细信息,请参阅: http://www.asp.net/web-api
            config.EnableSystemDiagnosticsTracing();
        }
    }
}


以上的MapHttpAttributeRoutes方法只在ASP.NET Web API较新的版本中才有,如果你的版本比较低,可以通过"NuGet程序包管理器控制台"卸载旧版本,安装最新版本。


Uninstall-Package microsoft.aspnet.webapi –Force
install-package microsoft.aspnet.webapi

接下来,在Global.asax中,需要把原先注册WebApiConfig的方式注释掉,采纳新的方式,如下:


    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            //WebApiConfig.Register(GlobalConfiguration.Configuration);
            //Web API,启动特性路由
            GlobalConfiguration.Configure(WebApiConfig.Register);

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }

这时候运行项目可能会报如下错误:

这是因为在下载使用ASP.NET Web API最新版本的时候,顺带下载了一个最新版本的icrosoft.AspNet.WebApi.HelpPage。可以把最新版的HelpPage卸载掉,再下载相对老的版本。


Uninstall-Package Microsoft.AspNet.WebApi.HelpPage –Force
Install-Package Microsoft.AspNet.WebApi.HelpPage -Pre

使用Route特性

创建一个Cusomter类。


namespace MyRoutingAttributes4.Models
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

创建一个Order类。


namespace MyRoutingAttributes4.Models
{
    public class Order
    {
        public int Id { get; set; }
        public decimal Total { get; set; }
        public int CustomerId { get; set; }

        public Customer Customer { get; set; }
    }
}

创建一个Database类,用来获取Order集合。


using System.Collections.Generic;
using System.Linq;
using MyRoutingAttributes4.Models;

namespace MyRoutingAttributes4
{
    public class Database
    {
        public static IEnumerable<Order> GetOrdersByCustomerId(int customerId)
        {
            return GetOrders().Where(o => o.CustomerId == customerId);
        }

        private static IEnumerable<Order> GetOrders()
        {
            Customer cus1 = new Customer() { Id = 1, Name = "张三" };
            Customer cus2 = new Customer() { Id = 2, Name = "李四" };

            List<Order> orders = new List<Order>()
            {
                new Order(){Id = 1, Total = 80M, CustomerId = 1, Customer = cus1},
                new Order(){Id = 2, Total = 100M, CustomerId = 1, Customer = cus1},
                new Order(){Id = 3, Total = 120M, CustomerId = 2, Customer = cus2}
            };

            return orders;
        } 
    }
}


创建一个空的API控制器,编写如下:


using System.Collections.Generic;
using System.Web.Http;
using MyRoutingAttributes4.Models;

namespace MyRoutingAttributes4.Controllers
{
    public class OrdersController : ApiController
    {
        [Route("customers/{customerId}/orders")]
        [HttpGet]
        public IEnumerable<Order> FindOrdersByCustomer(int customerId)
        {
            return Database.GetOrdersByCustomerId(customerId);
        }
    }
}


在浏览器中输入如下:

如果你使用的是ASP.NET MVC4进行开发,在程序第一次运行的时候,可能会报如下错误:

[A]System.Web.WebPages.Razor.Configuration.HostSection 无法强制转换为 [B]System.Web.WebPages.Razor.Configuration.HostSection。类型 A 源自“System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”(在上下文“Default”中的“C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Web.WebPages.Razor/v4.0_2.0.0.0__31bf3856ad364e35/System.Web.WebPages.Razor.dll”位置处)。类型
B 源自“System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”(在上下文“Default”中的“C:/Windows/Microsoft.NET/Framework/v4.0.30319/Temporary ASP.NET Files/vs/feb7ce97/a525d58a/asse

这是因为,在下载最新版本的ASP.NET Web API的时候,用到了Razor的最新版本。需要在根目录下的Web.config中作如下配置:


  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      ......
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

使用RoutePrefix特性

如果想给某个API控制器中的所有Action加上一个前缀,可把RoutePrefix特性打在API控制器上。

比如我们希望是这样的格式:http://localhost/api/customers/1/orders

这样来修改OrdersController。


using System.Collections.Generic;
using System.Web.Http;
using MyRoutingAttributes4.Models;

namespace MyRoutingAttributes4.Controllers
{
    [RoutePrefix("api")]
    public class OrdersController : ApiController
    {
        [Route("customers/{customerId}/orders")]
        [HttpGet]
        public IEnumerable<Order> FindOrdersByCustomer(int customerId)
        {
            return Database.GetOrdersByCustomerId(customerId);
        }
    }
}


还可以在Route特性中使用~来重写Action的前缀规则。


using System.Collections.Generic;
using System.Web.Http;
using MyRoutingAttributes4.Models;

namespace MyRoutingAttributes4.Controllers
{
    [RoutePrefix("api")]
    public class OrdersController : ApiController
    {
        [Route("~/myapi/customers/{customerId:int}/orders")]
        [HttpGet]
        public IEnumerable<Order> FindOrdersByCustomer(int customerId)
        {
            return Database.GetOrdersByCustomerId(customerId);
        }
    }
}


RoutePrefix特性定义的前缀还可以带参数变量:


    [RoutePrefix("api/{customerId}")]
    public class OrdersController : ApiController

路由约束

可以通过"{参数变量名称:约束}"来约束路由中的参数变量。


[Route("users/{id:int}"]
public User GetUserById(int id) { ... }

[Route("users/{name}"]
public User GetUserByName(string name) { ... }

以上,如果片段变量id为int类型,就路由到第一个Action,如果不是,路由到第二个Action。

ASP.NET Web API内置约束包括:


{x:alpha} 约束大小写英文字母
{x:bool}
{x:datetime}
{x:decimal}
{x:double}
{x:float}
{x:guid}
{x:int}
{x:length(6)}
{x:length(1,20)} 约束长度范围
{x:long}
{x:maxlength(10)}
{x:min(10)}
{x:range(10,50)}
{x:regex(正则表达式)}

可以为一个参数变量同时设置多个约束:

[Route("api/{id:int:min(1)}")]

实现IHttpRouteConstraint接口,可自定义约束规则。实现一个不能为0的约束。


public class NonZeroConstraint : IHttpRouteConstraint
{
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, 
        IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            long longValue;
            if (value is long)
            {
                longValue = (long)value;
                return longValue != 0;
            }

            string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
            if (Int64.TryParse(valueString, NumberStyles.Integer, 
                CultureInfo.InvariantCulture, out longValue))
            {
                return longValue != 0;
            }
        }
        return false;
    }
}


在App_Start文件夹中的WebApiConfig中注册自定义约束。


public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));

        config.MapHttpAttributeRoutes(constraintResolver);
    }
}


使用自定义约束。

[Route("{id:nonzero}")]

可选参数及其默认值

如果一个路由参数变量是可选的,同时必须给该参数一个默认值。


[Route("api/{id:int?}")]
public IEnumerable<T> Get(int id = 8){}

在约束后面加?,表示可选,在方法参数中给id设置默认值。

给路由设置名称


public class BooksController : ApiController
{
    [Route("api/books/{id}", Name="GetBookById")]
    public BookDto GetBook(int id) 
    {
        // Implementation not shown...
    }

    [Route("api/books")]
    public HttpResponseMessage Post(Book book)
    {
        // Validate and add book to database (not shown)

        var response = Request.CreateResponse(HttpStatusCode.Created);

        // Generate a link to the new book and set the Location header in the response.
        string uri = Url.Link("GetBookById", new { id = book.BookId });
        response.Headers.Location = new Uri(uri);
        return response;
    }
}

路由优先顺序

Route特性设置的路由优先顺序是根据惯例和RouteOrder属性来确定的。

惯例是:

1、静态片段变量

2、带约束的片段变量

3、不带约束的片段变量

4、带约束的通配符片段变量

5、不带约束的通配符片段变量

RouteOrder属性的默认值是0,属性值越小,排在越前面。


[RoutePrefix("orders")]
public class OrdersController : ApiController
{
    [Route("{id:int}")] // constrained parameter
    public HttpResponseMessage Get(int id) { ... }

    [Route("details")]  // literal
    public HttpResponseMessage GetDetails() { ... }

    [Route("pending", RouteOrder = 1)]
    public HttpResponseMessage GetPending() { ... }

    [Route("{customerName}")]  // unconstrained parameter
    public HttpResponseMessage GetByCustomer(string customerName) { ... }

    [Route("{*date:datetime}")]  // wildcard
    public HttpResponseMessage Get(DateTime date) { ... }
}

以上,路由的优先顺序是:

orders/details  静态片段变量,RouteOrder属性值为0

orders/{id} 带约束的片段变量,RouteOrder属性值为0

orders/{customerName} 不带约束的片段变量,RouteOrder属性值为0

orders/{*date} 带约束的通配符片段变量,RouteOrder属性值为0

orders/pending RouteOrder属性值为1

webapi Route 特性的更多相关文章

  1. .NET WebAPI 利用特性捕捉异常

    声明:本方式及代码只使用与.NET Web API. 先创建类继承ExceptionFilterAttribute类型并复写OnException方法. 代码如下: using System; usi ...

  2. ASP.NET Web API实践系列04,通过Route等特性设置路由

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...

  3. Web Api通过Route、RoutePrefix等特性设置路由

    [Route("customers/{customerId}/orders")] [HttpGet] public IEnumerable<Order> FindOrd ...

  4. web api Route属性定义

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...

  5. webapi+entityframework分享

    1. webapi允许跨域的增删改查要在web.config中加入以下文字 <system.webServer> <validation validateIntegratedMode ...

  6. 第一节:WebApi的纯原生态的RestFul风格接口和路由规则介绍

    一. 原生态接口 1. 从默认路由开始分析 在WebApiConfig.cs类中的Register方法中,我们可以看到默认路由如下: 分析:请求地址在 controller 前面需要加上 api/,c ...

  7. ASP.NET Core WebApi

    ASP.NET Core WebApi 创建项目 使用VS新建项目,选择ASP.NET Core WebAPI即可. 此时Startup的Configure.ConfigureService方法中如下 ...

  8. ASP.NET WebApi 路由配置【转】

    一.路由介绍 ASP.NET Web API路由是整个API的入口.我们访问某个资源就是通过路由映射找到对应资源的URL.通过URL来获取资源的. 对于ASP.NET Web API内部实现来讲,我们 ...

  9. ASP.NET WebApi 路由配置

    ASP.NET Web API路由是整个API的入口.我们访问某个资源就是通过路由映射找到对应资源的URL.通过URL来获取资源的. 对于ASP.NET Web API内部实现来讲,我们的请求最终将定 ...

随机推荐

  1. [HNOI2012]集合选数 BZOJ2734

    分析: 构造法...每次找到一个没有被选过的数,用这个数推出一个表格,之后在表格上跑状压DP,时间复杂度O(n) 附上代码: #include <cstdio> #include < ...

  2. 全方位Bindind分析

    Binding,音译为绑定,通道捆她想一条数据的高速绑着“源”与“目标”: “源”乃提供数据的一方:“目标”乃接收数据并作出相应反应的一方: 过程感觉就像是,给一个“激励”,就会作出“反应”那样--- ...

  3. 学会查看Linux手册页(man文档)

    区段1:用户指令区段2:系统调用区段3:程序库调用区段4:设备区段5:文件格式区段6:游戏区段7:杂项区段8:系统指令区段9:内核内部指令区段n:Tcl或Tk指令 如果记不清楚工具或者函数的完整名字, ...

  4. 05-python基础

    1.python是什么? 解释性语言.高级语言.开源.简洁.方便.容易扩展 2.可变类型与不可变类型 可变类型:list.dict.可变集合set 不可变类型:数字,str,tuple元组,froze ...

  5. .NET Core容器化开发系列(零)——计划

    .NET Core相当完善的跨平台特性以及其轻量化的底层接口为我们能顺畅进行微服务开发提供了非常棒的基础. 作为支撑微服务最常见的基础技术--容器化将是本系列的核心内容. 接下来我计划用一个月左右的时 ...

  6. chrome浏览器插件 Octotree 让你浏览GitHub的时候像IDE 一样提供项目目录

    GitHub 作为代码托管平台,竟然没有提供项目目录,方便用户在线快速浏览项目结构.所以,在线分析项目源码就会变得很繁琐,必须一层一层点击,然后再一次一次地向上返回.要知道,本来 GitHub 网站在 ...

  7. Html_兼容性

    那么如何禁止使用IE8兼容模式解析网页呢?在IE8以上版本的浏览器增加了一个X-UA-Compatible 头标记,用于为IE8指定不同的页面渲染模式. <meta http-equiv=&qu ...

  8. B1010.一元多项式求导

    12/25 #include<bits/stdc++.h> using namespace std; void solve(){ int A,B,coef,exp; cin>> ...

  9. openssl证书及配置

    我的环境是:Linux+Apache+MySQL+PHP 1.下载openssl 及相关依赖 #yum install -y openssl 2.进入目录 /etc/pki/tls/certs #cd ...

  10. 20135202闫佳歆--week6 课本第三章学习笔记

    第三章 进程管理 一.进程 1.进程 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程 执行线程, ...