.NET下RestFulService使用(4) WebAPI路由特性

本来是上一篇的内容的,相对独立完整,内容也充足,重构提取出来作为一个独立的文章。

参考资料:https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing

根据参加资料的教程一步一步操作,确实可以,隐藏前面不行应该是类上少了[RoutePrefix("")],另外RoutePrefix里面的字符串可以是"a/b/c"这样的,也能是空的,空的情况下,打开网站首页就把列表显示出来了。

测试 GetBook 

1.正常状态

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int id)
        {
            BookDto book =
                await db.Books.Include(b => b.Author).Where(b => b.BookId == id).Select(AsBookDto).FirstOrDefaultAsync();
            if (book == null)
            {
                return NotFound();
            }

            return Ok(book);
        }

http://localhost:7390/api/books/1 =>正常

http://localhost:7390/api/books/1.1  => 404 不会进入方法

HTTP Error 404.0 - Not Found
您要找的资源已被删除、已更名或暂时不可用。

http://localhost:7390/api/books/a => 405 Method Not Allowed 错误

<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>

2.修改变量名 为name

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int name)
        {

        }

http://localhost:7390/api/books/1 => 404

<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:7390/api/books/1'.
</Message>
<MessageDetail>
No action was found on the controller 'Books' that matches the request.
</MessageDetail>
</Error>

http://localhost:7390/api/books/1.1  => 同上

http://localhost:7390/api/books/a => 同上 405 Method Not Allowed 错误

路径变量和方法变量不一致的话就会导致无法识别改路径,无法路由到具体的方法,也就是404 not found了。

3.修改变量类型

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(string id)
        {

        }

结果和正常状态一样

4.去掉路径变量中的int

 

http://localhost:7390/api/books/1 => 正常

http://localhost:7390/api/books/a => 正常 能进去方法 虽然是404 内容为空

http://localhost:7390/api/books/1.1  => 同上

1.1为什么不行,.号的关系吗?

5.类型改为float

        [Route("{id:float}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(float id)
        {

        }

http://localhost:7390/api/books/1 => 正常

http://localhost:7390/api/books/a => 同上 405 Method Not Allowed 错误

http://localhost:7390/api/books/1.1  => 同上

问题还是.上

找到解决办法了 参考:https://blog.csdn.net/kkliu201210/article/details/47999585

url中含有小数点,浏览器会认为是访问的文件

解决办法:

1、访问API时,url的末尾加  /  ,

/ 前面的内容就算有小数点,浏览器也会认为是路径

2、API中用  [FromBody]dynamic value  来接受值



两种方法都验证过

用添加/的方式 http://localhost:7390/api/books/1.1/,能够进入方法,返回结果和a一样 404 空。

6.路径歧义

6.1去掉int,同时有另外一个相似路径,如何区分呢,按教程原本是有int时根据类型区分的。

        [Route("{id}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int id)
        {

        }

        [Route("{genre}")]
        public IQueryable<BookDto> GetBooksByGenre(string genre)
        {

        }

特意把方法里面的类型还是保留为int的

结果不行:

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Multiple actions were found that match the request: GetBook on type BooksAPI.Controllers.BooksController GetBooksByGenre on type BooksAPI.Controllers.BooksController
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
在 System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext) 在 System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext) 在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
</Error>

6.2 试着在另一个方法设置为类型string

        [Route("{id}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int id)
        {

        }

        [Route("{genre:string}")]
        public IQueryable<BookDto> GetBooksByGenre(string genre)
        {

        }

结果一运行就出错

The inline constraint resolver of type 'DefaultInlineConstraintResolver' was unable to resolve the following inline constraint: 'string'.
说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

异常详细信息: System.InvalidOperationException: The inline constraint resolver of type 'DefaultInlineConstraintResolver' was unable to resolve the following inline constraint: 'string'.

源错误: 


行 12:         protected void Application_Start()
行 13:         {
行 14:             GlobalConfiguration.Configure(WebApiConfig.Register);
行 15:         }
行 16:     }

源文件: E:\Documents\Visual Studio 2015\Projects\BooksAPI\Global.asax.cs    行: 14 

看来不支持string类型

6.3 id路径中设置为int,方法改为string

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(string id)
        {

        }

        [Route("{genre}")]
        public IQueryable<BookDto> GetBooksByGenre(string genre)
        {

        }

可以

6.4 添加一个float的id类型

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int id)
        {
        }

        [Route("{id:float}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(float id)
        {
        }

        [Route("{genre}")]
        public IQueryable<BookDto> GetBooksByGenre(string genre)
        {
        }

http://localhost:7390/api/books/1 不行

{"Message":"An error has occurred.","ExceptionMessage":"Multiple actions were found that match the request: \r\nGetBook on type BooksAPI.Controllers.BooksController\r\nGetBook on type BooksAPI.Controllers.BooksController","ExceptionType":"System.InvalidOperationException","StackTrace":"   在 System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n   在 System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n   在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n   在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}

http://localhost:7390/api/books/1.1/ 可以进入float类型的方法,

7.添加方法变量

        [Route("{id:int}")]
        [ResponseType(typeof(BookDto))]
        public async Task<IHttpActionResult> GetBook(int id,string name)
        {
        }

不行,无法进入方法

8.多个路径变量

        [Route("{a},{b}")]
        public int GetBook1(int a,int b)
        {
            return  a + b;
        }

        [Route("{a}/{b}")]
        public int GetBook2(int a, int b)
        {
            return a + b;
        }

http://localhost:7390/api/books/1,2 =>可以

http://localhost:7390/api/books/1/2 =>可以

9.方法名

        [Route("{a},{b}")]
        public int Add1(int a,int b)
        {
            return  a + b;
        }

        [Route("{a}/{b}")]
        public int Add2(int a, int b)
        {
            return a + b;
        }

结果:

<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
        [Route("{a},{b}")]
        [ResponseType(typeof(BookDto))]
        public int GetAdd1(int a,int b)
        {
            return  a + b;
        }

        [Route("{a}/{b}")]
        [ResponseType(typeof(BookDto))]
        public int GetAdd2(int a, int b)
        {
            return a + b;
        }

是可以的 关键就是是否Get开头吧

        [Route("{a},{b}")]
        [HttpGet]
        public int Add1(int a,int b)
        {
            return  a + b;
        }

        [Route("{a}/{b}")]
        [HttpGet]
        public int Add2(int a, int b)
        {
            return a + b;
        }

添加[HttpGet]则也是可以的

10.查询参数

        [Route("add/{a},{b}")]
        [HttpGet]
        public int Add1(int a,int b)
        {
            return  a + b;
        }

        [Route("add/{a}/{b}")]
        [HttpGet]
        public int Add2(int a, int b)
        {
            return a + b;
        }

        [Route("add/")]
        [HttpGet]
        public int Add3(int a, int b)
        {
           return a + b;
        }

http://localhost:7390/api/books/add/1,2 =>可以

http://localhost:7390/api/books/add/1/2 =>可以

http://localhost:7390/api/books/add/?a=1&b=2  =>可以

http://localhost:7390/api/books/add/?a=1&b=2&c=3  =>可以 参数可以多

http://localhost:7390/api/books/add/?a=1  =>不行 参数不能少

 

        [Route("add/?a={a}&b={b}")]
        [HttpGet]
        public int Add3(int a, int b)
        {
           return a + b;
        }

运行不行

“/”应用程序中的服务器错误。
The route template cannot start with a '/' or '~' character and it cannot contain a '?' character.
参数名: routeTemplate
说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

异常详细信息: System.ArgumentException: The route template cannot start with a '/' or '~' character and it cannot contain a '?' character.
参数名: routeTemplate

源错误: 


行 12:         protected void Application_Start()
行 13:         {
行 14:             GlobalConfiguration.Configure(WebApiConfig.Register);
行 15:         }
行 16:     }

源文件: E:\Documents\Visual Studio 2015\Projects\BooksAPI\Global.asax.cs    行: 14 

也就是?a=1&b=2这种参数的方式不需要特别指明,默认就是能解析的

 

        [Route("add/a={a}&b={b}")]
        [HttpGet]
        public int Add3(int a, int b)
        {
           return a + b;
        }

运行没问题

但是 http://localhost:7390/api/books/add/a=1&b=2 的结果是:

“/”应用程序中的服务器错误。

从客户端(&)中检测到有潜在危险的 Request.Path 值。

说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

异常详细信息: System.Web.HttpException: 从客户端(&)中检测到有潜在危险的 Request.Path 值。

源错误: 

执行当前 Web 请求期间生成了未经处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。

堆栈跟踪: 


[HttpException (0x80004005): 从客户端(&)中检测到有潜在危险的 Request.Path 值。]
   System.Web.HttpRequest.ValidateInputIfRequiredByConfig() +9908976
   System.Web.PipelineStepManager.ValidateHelper(HttpContext context) +53
        [Route("add/a={a}")]
        [HttpGet]
        public int Add3(int a)
        {
           return a;
        }

可以的

        [Route("add/a={a};b={b}")]
        [HttpGet]
        public int Add3(int a)
        {
           return a;
        }

可以的,说明前面不行的原因是&号吧,实际上路径变量里面就是一种字符串匹配的模板(正则表达式?){a},{b}和a={a};b={b}本质上没区别的

另外 http://localhost:7390/api/books/add/a=  20;b= 4 可以

而 http://localhost:7390/api/books/add/a =  20;b = 4 不行

正则表达式匹配的话也是类似这样的

11.正则表达式

教程中的最后部分

        [Route("date/{pubdate:datetime:regex(\\d{4}-\\d{2}-\\d{2})}")]
        [Route("date/{*pubdate:datetime:regex(\\d{4}/\\d{2}/\\d{2})}")]
        public IQueryable<BookDto> GetBooks(DateTime pubdate)
        {
            return
                db.Books.Include(b => b.Author)
                    .Where(b => DbFunctions.TruncateTime(b.PublishDate) == DbFunctions.TruncateTime(pubdate))
                    .Select(AsBookDto);
        }

1.datetime类型支持

2.regex匹配正则表达式

3.*让路由引擎匹配uri中的剩下的所有部分,不加的话/就无法区分开来了

4.可以有多个uri路由到一个方法

        [Route("add/{a},{b}")]
        [Route("add/{a}/{b}")]
        [Route("add/")]
        [HttpGet]
        public int Add(int a,int b)
        {
            return  a + b;
        }

也是可以的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值