越来越喜欢 asp.net web api,很大原因是因为非常干净。而其中 POST 是作为修改交互极为重要的一个请求。当然为了体验,和 asp.net web api交互总是离不开 jQuery 或者其实类似 ajax 请求方法,但往往会有一些小小诡异,比如:

咦,为什么都是null?

所以这篇文章会讲解一些 POST 请求时可能的一些问题。

POST原始参数数据到Asp.net web API

public void Post(string value){}

原则上我们只需要按标准的使用 $.post,比如:

$.post('/api/values', { value: 'asdf' });

可结果是:

POST http://localhost:53924/api/Values 404 (Not Found) 

WHY???很明显路由未找到,可这与我们期待不同呀。

必须标记参数[FromBody]

这是一种概念问题,因为对于 POST 时,按我们想当然自然是会自动将 POST 内容直接给 value。而对于路由而言这是一个完整的请求参数,自然就返回一个 404 错误。

我们需要给参数加上 [FromBody] 属性,比如:

public void Post([FromBody]string value){}
$.post('/api/values', { value: 'asdf'}, function(d) { console.log(d); });
// 输出:null

以上我们可以正常的请求成功。但输出的结果还是 null,这不应该我传递是 asdf,这一点我后面再提。

Asp.net web API 参数绑定规则

默认下,ASP.NET web API按以下两种规则绑定参数:

  1. 简单类型主要包括原始类型(int、bool、double等)含(TimeSpan、Guid待)以及String,默认会尝试从 URI 获取。
  2. 复杂类型会尝试从请求体获取,并通过媒体类型格局化器进行解析。

每一个方法只能有一个[FromBody]

除非你自定义一个模型绑定方法,否则你只能使用一个 [FromBody],而对于 POST大部分情况下是多个参数,所以最好的是采用复杂类型。

为什么只允许一个,这应该从认识 RESTful 架构开始,对于一个资源对应一个特定方法,而把数据分成几个松散参数也违背 ASP.NET API 吧。

public class Album {
    public string name {get;set;}
}
public void Post(int id, Album album){}
$.post('/api/values?id=1', { name: 'asdf'}, function(d) { console.log(d); });

以上,这是将简单类型和复杂类型同时使用。

[FromBody]参数必须进行键值编码

回过头看 null 问题,ASP.NET web API需要我们为参数指定 [FromBody],这是一种特定格式。正因为这种特定格式,会依赖 Content-Type类型来解析请求体应该采用什么格式,而绝大部分客户端和服务端采用的是键值对和JSON两种。

  1. 键值对:jQuery默认就是采用这种方式,而对于ASP.NET web API默认是空值做为取值条件,所以我们应该 $.post('/api/values', { '': 'asdf' }); 这样 value 参数才能够正常绑定。

  2. JSON:当Content-Type:application/json时,这也是大多数客户端所习惯采用的比如(AngularJS),对于这种情况我们应该 $.ajax( { type:'post', url: '/api/values', contentType: 'application/json', data: '"asdf"' }).done(function(d) { console.log(d); });

415 Unsupported Media Type

当我们传递的请求体内容无法被正常解析时,会得到这个错误。所以在传递请求体内容时要注意。