zoukankan      html  css  js  c++  java
  • WebApi路由

    一、MVC和WebApi路由机制比较

    1、MVC里面的路由
    在MVC里面,默认路由机制是通过url路径去匹配对应的action方法,比如/Home/Index这个url,就表示匹配Home这个Controller下面的Index方法,这个很好理解,因为在MVC里面定义了一个默认路由,在App_Start文件夹下面有一个RouteConfig.cs文件

        public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.MapRoute(
                    name: "Default",
                    url: "{controller}/{action}/{id}",
                    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                );
            }
        }
    

    url: "{controller}/{action}/{id}"这个定义了我们url的规则,{controller}/{action}定义了路由的必须参数,{id}是可选参数
    2、WebApi里面的路由
    WebApi的默认路由是通过http的方法(get/post/put/delete)去匹配对应的action,也就是说webapi的默认路由并不需要指定action的名称。还是来看看它的默认路由配置,我们新建一个Webapi项目,在App_Start文件夹下面自动生成一个WebApiConfig.cs文件:

        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API 路由
                config.MapHttpAttributeRoutes();
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
        }
    

    和MVC类似,routeTemplate: "api/{controller}/{id}"这个定义了路由的模板,api/{controller}是必选参数,{id}是可选参数

    那么问题就来了,如果我们的url不包含action的名称,那么如何找到请求的方法呢?

    eg:

    public class ValuesController : ApiController
        {
            // GET api/values
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }
    
            // GET api/values/5
            public string Get(int id)
            {
                return "value";
            }
    
            // POST api/values
            public void Post([FromBody]string value)
            {
            }
    
            // PUT api/values/5
            public void Put(int id, [FromBody]string value)
            {
            }
    
            // DELETE api/values/5
            public void Delete(int id)
            {
            }
        }
    

    通过浏览器访问url

    //浏览器返回
    <ArrayOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <string>value1</string>
    <string>value2</string>
    </ArrayOfstring>
    

    Webapi的路由规则是通过http方法去匹配对应的action,浏览器默认通过url访问的都是get请求,webapi的路由引擎就会去找控制器里面的get请求的方法,由于没有参数,所以自动匹配到了无参数的get请求→Get()方法

    ++WebApi也支持MVC里面的路由机制,但RestFul风格的服务要求请求的url里面不能包含action,所以,在WebApi里面是并不提倡使用MVC路由机制的++

    特性路由

    WebApi2默认的路由规则我们称作基于约定路由,很多时候我们使用RESTful风格的URI.简单的路由是没问题的,如 api/Products/{id},但有些事很难处理的,如资源之间存在嵌套关系:客户包含订单,书有作者属性等等。对于这种Uri,我们希望的路由是这样的:/costomers/{customerid}/orders 或 /costomers/{customerid}/orders/{orderid}

    通过使用特性路由,我们还可以做API的版本控制

    public class ValuesController : ApiController
        {
            [Route("api/Values/{id}/V1")]
            public string Get(int id)
            {
                return $"value {id}";
            }
            [Route("api/Values/{id}/V2")]
            public string GetV2(int id)
            {
                return $"value V2 {id}";
            }
        }
    
    //~/api/Values/1/v1返回
    <string>value 1</string>
    //~/api/Values/1/v2返回
    <string>value V2 1</string>
    

    如果要启用特性路由,需要改成如下代码

        public class WebApiApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
               //...
               GlobalConfiguration.Configure(WebApiConfig.Register);
               //...
            }
        }
    

    启用特性路由还需要在配置过程中调用System.Web.HttpConfigurationExtensions类的MapHttpAttributeRoutes方法

    using System.Web.Http;
    
    namespace WebApplication
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                // Other Web API configuration not shown.
            }
        }
    }
    

    默认情况,WebApi会根据action的方法名前缀查找action(不区分大小写),比如GetUsers,会匹配Get。通过在action上添加HttpMethod特性,可以覆盖action需要映射的Http Method。
    可使用的特性包括:[HttpDelete],[HttpPost],[HttpHead],[HttpOptions],[HttpPatch],[HttpGet],[HttpPut]

    配置好特性路由,开始使用

        public class DefaultController : ApiController
        {
            [Route("api/Default/{id:int}/{name}")]
            public string GetUser(int id,string name)
            {
                return $"{nameof(GetUser)} id:{id} name:{name}";
            }
            [Route("")]
            [Route("api")]
            [Route("api/Default")]
            public string Get()
            {
                return $"Get value {DateTime.Now}";
            }
        }
    

    在方法上标记Route 即指定方法路由规则,也可以在一个方法上标记多个路由规则

    //http://localhost:24727  http://localhost:24727/api http://localhost:24727/api/default  访问的都是DefaultController控制器下的Get()方法
    <string>Get value 2020/4/29 14:23:22</string>
    
    //http://localhost:24727/api/default/1/aaa 访问DefaultController控制器下的GetUser()方法
    <string>GetUser id:1 name:aaa</string>
    

    路由约束

    路由约束让我们可以限制模板参数的匹配方式。一般的语法是 "{参数:约束类型}":

    约束 介绍 示例
    alpha 匹配大写或小写字母 (a-z, A-Z) {x:alpha}
    bool {x:bool}
    datetime {x:datetime}
    decimal {x:decimal}
    double {x:double}
    float 匹配一个 32位浮点数 {x:float}
    guid {x:guid}
    int {x:int}
    length 匹配一个长度在指定范围内的字符串 {x:length(6)}
    {x:length(1,20)}
    long {x:long}
    max 匹配指定了最大值的整数 {x:max(10)}
    maxlength 匹配指定了最大长度字符串 {x:maxlength(10)}
    min 匹配指定了最小值的整数 {x:min(10)}
    minlength 匹配指定了最小长度字符串 {x:minlength(10)}
    range 匹配指定了大小区间的整数 {x:range(10,50)}
    regex 匹配一个正则表达式 {x:regex(^d{3}-d{3}-d{4}$)}

    如果要指定多个约束,需要用冒号间隔 [Route("api/Default/{id:int:max(10)}")]

            [HttpGet]
            [Route("api/Default/{id:int:max(10)}")]
            public string MultipleConstraints(int id)
            {
                return $"{nameof(MultipleConstraints)} id:{id} {DateTime.Now}";
            }
    
    //http://localhost:24727/api/default/10 这里的id只能传小于10的整数 否则会报错找不到方法
    <string>MultipleConstraints id:10 2020/4/29 14:43:16</string>
    

    在参数约束后面添加一个问号,可以设定URI参数是可选的;

            [HttpGet]
            [Route("api/Default/{id:int?}")]
            public string OptionalParameter(int id=10)
            {
                return $"{nameof(OptionalParameter)} id:{id} {DateTime.Now}";
            }
            //http://localhost:24727/api/default
            <string>OptionalParameter id:10 2020/4/29 14:58:51</string>
    

    也可以像普通方法那样指定默认值:

            [HttpGet]
            [Route("api/Default/{id:int=111}")]
            public string DefaultParameter(int id)
            {
                return $"{nameof(DefaultParameter)} id:{id} {DateTime.Now}";
            } 
            //http://localhost:24727/api/default 
            <string>DefaultParameter id:111 2020/4/29 14:56:52</string>
    

    通常情况下,一个Controller下的action会使用相似的路由模板,这时候可以为整个controller指定[RoutePrefix]特性,以使用共同的前缀

        [RoutePrefix("api/default/{id:int}")]//路由前缀中可以包含参数
        public class DefaultController : ApiController
        {
            [HttpGet]
            [Route("")]//这里的[Route("")]不能省略否则会找不到方法
            public string Prefix(int id)
            {
                return $"{nameof(Prefix)} id:{id} {DateTime.Now}";
            }
            [HttpGet]
            [Route("other")]
            public string NotPrefix(int id)
            {
                return $"{nameof(NotPrefix)} id:{id} {DateTime.Now}";
            }
            [HttpGet]
            [Route("~/api/other/{id:int}")]//如果有某个特殊路由不希望使用前缀,可以在路由中添加~/
            public string Other(int id)
            {
                return $"{nameof(Other)} id:{id} {DateTime.Now}";
            }
            [HttpGet]
            [Route("~/api/Date/{id:int}/{*date:datetime:regex(\d{4}/\d{2}/\d{2})}")]//有时候需要几个路由片段结合起作用,这时候就需要使用字符* 不过这种参数只能用作路由的最后一个参数 
            public string Date(int id,DateTime date)
            {
                return $"{nameof(Date)} id:{id} date:{date} {DateTime.Now}";
            }
        }
    
    //http://localhost:24727/api/default/1
    <string>Prefix id:1 2020/4/29 15:55:34</string>
    //http://localhost:24727/api/default/1/other
    <string>NotPrefix id:1 2020/4/29 15:56:00</string>
    //http://localhost:24727/api/other/1
    <string>Other id:1 2020/4/29 15:56:25</string>
    //http://localhost:24727/api/date/1/2020/04/29
    <string>
    Date id:1 date:2020/4/29 0:00:00 2020/4/29 15:44:52
    </string>
    

    路由顺序

    通过设定特性[Route("xxx",RouteOrder=n)]可以指定路由的查找顺序
    不过意义不大,通过顺序来控制,还不如设定更好的路由来的实际,而且不至于混乱。

    本文参考文档:
  • 相关阅读:
    HDU
    HDU
    HDU
    【JZOJ4231】寻找神格【分块】
    【JZOJ4231】寻找神格【分块】
    【JZOJ4230】淬炼神体【数论,数学】【二分】
    【JZOJ4230】淬炼神体【数论,数学】【二分】
    【JZOJ4229】学习神技【数论,数学】
    【JZOJ4229】学习神技【数论,数学】
    【JZOJ3771】【NOI2015模拟8.15】小 Z 的烦恼【高精度】【数论】
  • 原文地址:https://www.cnblogs.com/Dewumu/p/12803652.html
Copyright © 2011-2022 走看看