WebApi2官网学习记录---Attribute Routing

从WebApi 1迁移到WebAPI 2要改变配置代码如下:

WebApi 1:

protected void Application_Start()
{
    // WARNING - Not compatible with attribute routing.
    WebApiConfig.Register(GlobalConfiguration.Configuration);
}

WebAPI 2:

protected void Application_Start()
{
    // Pass a delegate to the Configure method.
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

添加一个Route Attributes

public class OrdersController : ApiController
{
    [Route("customers/{customerId}/orders")]
    [HttpGet]
    public IEnumerable<Order> FindOrdersByCustomer(int customerId) { ... }
}

可以匹配一下URL:

  • http://localhost/customers/1/orders
  • http://localhost/customers/bob/orders
  • http://localhost/customers/1234-5678/orders

匹配http post请求的CreateBook

[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }
[Route("api/books")]
[AcceptVerbs("MKCOL")]
public void MakeCollection() { 

Route Prefixes

对于同一个controller路由有相同的前缀, 此时可以使用 [RoutePrefix] attribute

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET api/books
    [Route("")]
    public IEnumerable<Book> Get() { ... }

    // GET api/books/5
    [Route("{id:int}")]
    public Book Get(int id) { ... }

    // POST api/books
    [Route("")]
    public HttpResponseMessage Post(Book book) { ... }
}

可以在方法的attribute中使用(~)重写路由前缀

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET /api/authors/1/books
    [Route("~/api/authors/{authorId:int}/books")]
    public IEnumerable<Book> GetByAuthor(int authorId) { ... }

    // ...
}

路由前缀中可以包含参数

[RoutePrefix("customers/{customerId}")]
public class OrdersController : ApiController
{
    // GET customers/1/orders
    [Route("orders")]
    public IEnumerable<Order> Get(int customerId) { ... }
}

路由约束

  路由约束用于严格匹配路由中的参数,通用语法是{参数:约束},如下:

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

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

支持的约束如下表所示:

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)}
{x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

注意:带括号的约束,如"min",可以对路由中的参数应用多个约束,用冒号分割约束

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

 自定义路由约束

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;
    }
}

修改WebAPIConfig.cs
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}")]
public HttpResponseMessage GetNonZero(int id) { ... }

可选的URI参数和默认值

第一种方式,默认值直接分配给了方法参数,因此参数获得的是精确的值

第二种方式,默认值通过model-binding进行处理,默认的model-binder将字符串类型的默认值"1033"转为int形的1033,对于model-binder可能有所不同。

 1 第一种写法
 2 public class BooksController : ApiController
 3 {
 4     [Route("api/books/locale/{lcid:int?}")]
 5     public IEnumerable<Book> GetBooksByLocale(int lcid = 1033) { ... }
 6 }
 7
 8 第二种写法
 9 public class BooksController : ApiController
10 {
11     [Route("api/books/locale/{lcid:int=1033}")]
12     public IEnumerable<Book> GetBooksByLocale(int lcid) { ... }
13 }

Route Names

web api中每个路由有一个name,Route names可以用来生成links

 1 public class BooksController : ApiController
 2 {
 3     [Route("api/books/{id}", Name="GetBookById")]
 4     public BookDto GetBook(int id)
 5     {
 6         // Implementation not shown...
 7     }
 8
 9     [Route("api/books")]
10     public HttpResponseMessage Post(Book book)
11     {
12         // Validate and add book to database (not shown)
13
14         var response = Request.CreateResponse(HttpStatusCode.Created);
15
16         // Generate a link to the new book and set the Location header in the response.
17         string uri = Url.Link("GetBookById", new { id = book.BookId });
18         response.Headers.Location = new Uri(uri);
19         return response;
20     }
21 }

Route Order

通过设置RouteOrder属性在route attribute上,可以指定Route的顺序,值越小先被计算,默认顺序对应的值是0

路由顺序的选择:

  • 比较RouteOrder属性
  • 对于URI部分按如下进行排序
  1. URI的固定部分(literal segments)  
  2. 带约束的路由参数
  3. 不带约束的路由参数
  4. 带约束的通配符
  5. 不带约束的通配符
  • route的排序不区分大小写的
[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) { ... }
}

路由排序如下:

  1. orders/{details}
  2. orders/{id}
  3. orders/{customreName}
  4. orders/{*date}
  5. orders/pending
时间: 2024-10-12 08:08:39

WebApi2官网学习记录---Attribute Routing的相关文章

WebApi2官网学习记录---异常处理

HttpResponseException 当WebAPI的控制器抛出一个未捕获的异常时,默认情况下,大多数异常被转为status code为500的http response即服务端错误. HttpResonseException是一个特别的情况,这个异常可以返回任意指定的http status code,也可以返回具体的错误信息. 1 public Product GetProduct(int id) 2 { 3 Product item = repository.Get(id); 4 if

WebApi2官网学习记录---BSON

BSON 是轻量级的,能够进行快速查询和高效的解码/编码.BSON方便查询是由于elements的前面都有一个表示长度的字段,所以解释器可以快速跳过这个elements:高效的解码/编码是因为numeric数据直接存储为numbers,不用转为string. 在服务端启用BSON   public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Formatter

WebApi2官网学习记录--- Authentication与Authorization

Authentication(认证)   WebAPI中的认证既可以使用HttpModel也可以使用HTTP message handler,具体使用哪个可以参考一下依据: 一个HttpModel可以检测ASP.NET请求管道中的所有请求,一个message handler仅仅可以检测到被路由到这个WebAPI的请求 可以预先设置message handlers,让特定的route使用指定的authentication scheme Http Module只能在IIS中使用,Message ha

WebApi2官网学习记录---Tracing

安装追踪用的包 Install-Package Microsoft.AspNet.WebApi.Tracing Update-Package Microsoft.AspNet.WebApi.WebHost //-Version指定具体的版本 启用追踪的功能(在WebApiConfig.cs中) public static class WebApiConfig { public static void Register(HttpConfiguration config) { SystemDiagn

WebApi2官网学习记录---Content Negotiation

Content Negotiation的意思是:当有多种Content-Type可供选择时,选择最合适的一种进行序列化并返回给client. 主要依据请求中的Accept.Accept-Charset.Accept-Encoding.Accept-Language这些属性决定的,但也会查看其它属性 如,如果请求中包含“ X-Requested-With”(ajax请求),在没哟其它Accept时,则使用JSON. Content Negotiation的工作原理 首先,pipeline从Http

WebApi2官网学习记录---Media Formatters

Web API内建支持XML.JSON.BSON.和form-urlencoded的MiME type. 创建的自定义MIME类型要继承一下类中的一个: MediaTypeFormatter 这个类使用异步的读/写方法 BufferedMediaTypeFormatter 这个类继承自MediaTypeFormatter,但它使用同步的读/写方法 自定义一个MIME类型,如下: public class ProductCsvFormatter:BufferedMediaTypeFormatter

树莓派官网学习记录

树莓派官网学习记录 和GPIO Zero 一起开始 我们将做的 树莓派一侧的排针是称为通用输入输出引脚(GPIO) 这些引脚允许树莓派去控制现实中的东西.你能连接元件到这些引脚上:输出设备像能任意被开关的LED(发光二极管):或者是输入设备像能用作触发事件的一个按钮或者传感器,比如当一个按钮被按下的时候,点亮一只LED. 通过使用GPIO Zero 库,你能很容易的控制树莓派的GPIO引脚. 我们将学习的 通过完成这个资源你将学到: 如何将LED和按钮连接到树莓派的GPIO上 如何通过GPIO

WebApi官网学习记录---web api中的路由

如果一条路由匹配,WebAPI选择controller和action通过如下方式: 1.找到controller,将"controller"赋值给{controller}变量 2.寻找action,web api查看http的请求方式,然后寻找一个以对应请求方式开头的action,如Get请求,需要寻找一个名为Get...的action,这种方式仅支持Get,Post,Put和Delete操作. 除了依据Http请求的方式,还可以显示为action指定http method通过Http

4.Knockout.Js官网学习(事件绑定)

前言 click绑定在DOM元素上添加事件句柄以便元素被点击的时候执行定义的JavaScript 函数.大部分是用在button,input和连接a上,但是可以在任意元素上使用. 简单示例 <h2>ClickBind</h2> <div> You've clicked <span data-bind="text: numberOfClicks"></span> times <button data-bind="