准备工作
Visual Studio 新建一个“ASP.NET Web 应用程序(.NET Framework)”,最后一步选择模板时,选择“空”,然后在右边勾上“Web API”。
我们可以看到 App_Start/WebApiConfig.cs 中配置了路由,我们保持默认不变:
public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
在 Controllers 上新建一个“Web API 2 控制器 - 空”,我们取名:BookController,自动派生自 ApiController,代码如下:
public class BookController : ApiController { public string Get() { return "itpow"; } }
Ctrl + F5 运行。
基本细节
忽略大小写
根据路由规则,我们在浏览器中输入 xxx/api/book,即可得到 itpow。关于此,请继续阅读.NET Web API 如何输出字符串、XML、JSON。
这是忽略大小写的,xxx/aPI/boOk,效果是一样的。
最后加不加斜杠也是一样的。
Get、Post 不会相互“串”
使用 Postman 一类的调试功能,以 POST 方式提交上述网址,会发现:
{ "Message": "请求的资源不支持 http 方法“POST”。" }
因为我们只写了 Get 方法,没写 Post 方法,它们之间并不会串,不存在说 Post 不存在,交给 Get 处理的情况。
反过来也是一样的。
Get 参数可用路由,也可用 QueryString
public class BookController : ApiController { public string Get(int id) { return "itpow" + id; } }
现在我们加了个参数,id。访问有两种形式:
xxx/api/book/2 或 xxx/api/book/2/
xxx/api/book?id=2 或 xxx/api/book/?id=2
得到的结果都是 itpow2。
参数匹配
调用参数多得少不得(重要)
如上,假如我们访问:
xxx/api/book?id=2&name=b 或 xxx/api/book/?id=2&name=b
得到的结果和上面是一样的。
不过要注意,不能这样访问:
xxx/api/book/2/b 或 xxx/api/book/2/b/
因为我们前面没有这样配路由(我们使用默认路由:api/{controller}/{id}),所以会报 404 错误。
同样,对 Get() 方法(不带参数),我们用带了 id 的 Url 去访问,是不会出错的,因为参数多得少不得嘛。
如果参数少了,会报什么错误呢?
比如要求 1 个参数,但是没提供参数(注意:id= 不叫没参数,它叫参数没值)。
或者要求 id 参数,但是我们 QueryString 中不叫 id,叫 id1。
是会报错的:
{ "Message": "找不到与请求 URI“http://localhost:57762/api/book?id1=2”匹配的 HTTP 资源。", "MessageDetail": "在控制器“Book”上找不到与该请求匹配的操作。" }
支持重载
public class BookController : ApiController { public string Get() { return "itpow"; } public string Get(int id) { return "itpow" + id; } }
根据有没有传 id 参数,来决定调哪个。
路由中 id 和参数中 id 不一样时
Get 方法中的参数 id 名字,与 QueryString 中的 id 应该一样。
而路由仅仅是帮助我们构造 QueryString,比如我把路由中 id 改为 id1,xxx/api/book/2 实际上是 xxx/api/book?id1=2,至于什么效果,根据前面的总结就知道了。
QueryString 的参数顺序,不需要与 Get 方法的参数顺序一致。因为它是看名称来匹配的,不是看顺序来匹配的。
Post
Post 方法的参数,也可能是 QueryString(重要)
public class BookController : ApiController { public string Post(int id) { return "itpow" + id; } }
如上是 Post 方法了,我们应该 POST 提交,这个 id 是不是 POST 项的一部分呢?错,它仍然应该由 QueryString 指定。
Json 参数不是 QueryString
public class BookController : ApiController { public string Post(RequestJson requestJson) { return "itpow" + requestJson.id; } } public class RequestJson { public int id; }
如上,是不是通过 QueryString 提交一个名称为 requestJson 的数据呢?
错!这里就不再是 QueryString 了,而是 POST,并且是不带参数名称的 POST。
如下:
这里还有一点说明:利用 x-www-form-urlencoded(就是普通 POST)提交一个任意名称的值,它不会报错,虽然 JSON 不存在,但是它以默认值来赋,此时 id 作为 int 默认值是 0。(看完本文,就更能理解了)
不支持 Json 内容级别的重载(重要)
public class BookController : ApiController { public string Post(RequestJson1 requestJson) { return "itpow" + requestJson.id; } public string Post(RequestJson2 requestJson) { return "itpow" + requestJson.name; } } public class RequestJson1 { public int id; } public class RequestJson2 { public string name; }
以上程序编译不出错,我们在想,是不是会根据不同的 Json 格式,调用不同的方法呢?
其实还实现不到这么细,它暂时还无法根据内容分辨是 RequestJson1,还是 RequestJson2。
会出现“找到了与该请求匹配的多个操作”的错误。
QueryString 与 Json 混合
public string Post(int type, RequestJson1 requestJson)
它会知道 type 来自于 QueryString,requestJson 来自于 POST。
FromBody
前面说,Post 方法:
JSON 以外的参数,来自于 QueryString。
JSON 参数来自于 Post。
但是我看到有一个 FromBody,FromBody 是不是指不让其来自于 QueryString 呢?
public class BookController : ApiController { public string Post([FromBody]int id) { return "itpow" + id; } }
我们是不是 POST id=1,就可以调用它了呢?
不对!
FromBody,是指整个 Post 内容,如上的话,调用时,我们就直接 POST id 的值,不要写 id 名称。
所以我们继续总结应该是这样的:
普通参数,没标明 FromBody,来自于 QueryString。
普通参数,标题了 FromBody,来自于整个 Post 内容区。
JSON 参数,来自于整个 POST 内容区。
如果我们不要取整个 POST 内容区,就要用普通的提交项,可用 Request.Form,比如:
public class BookController : ApiController { public string Post() { return "itpow" + HttpContext.Current.Request.Form["id"]; } }
相关阅读