通过 application/x-www-form-urlencoded 反序列化时未使用 WebAPI DataMember 名称

Posted

技术标签:

【中文标题】通过 application/x-www-form-urlencoded 反序列化时未使用 WebAPI DataMember 名称【英文标题】:WebAPI DataMember Name not used when de/serializing via application/x-www-form-urlencoded 【发布时间】:2015-07-07 16:09:05 【问题描述】:

已经花了几个小时试图解决在处理 HTTP POST 表单请求 (Content-Type: application/x-www-form-urlencoded) 时忽略 DataMemberAttribute 上的 Name 属性的问题。

我在 .NET 4.5 上运行 Microsoft.AspNet.WebApi 5.2.3 应用程序,由 IIS 托管。

我有这个模型(演示):

// library
public interface IPayload

    string DataId  get; set; 
    int RelationId  get; set; 


// web app project
[DataContract]
public class MyPayload : IPayload

    [Required]
    [DataMember(Name = "id")]
    public string DataId  get; set; 

    [Required]
    [DataMember(Name = "rel")]
    public int RelationId  get; set; 

然后我有控制器:

[HttpPost]
[Route("~/api/stuff")]
public async Task<HttpResponseMessage> DoMagic(MyPayload payload)

    // ... breakpoint

(请注意,我实际上使用的是模型类型,而不仅仅是控制器中的接口)


当我这样发送数据时:

curl -X POST --data '"id":"foo","rel":1' -H "Content-Type: application/json" -H "Content-Length: 20" http://localhost/api/stuff

我的模型反序列化正确。


但是,当我这样做时:

curl --data "id=foo" --data "rel=1" http://localhost/api/stuff

...我得到的是空模型 - 自定义名称被忽略,所有属性都有默认值。

最后,当我提出这样的要求时:

curl --data "DataId=foo" --data "RelationId=1" http://localhost/api/stuff

...模型已正确序列化。


所以我想知道,我做错了什么。我花了很多时间阅读,我发现的大多数案例都是关于缺少我的案例中存在的DataContractAttribute

控制器参数前面的属性FromBody也没有改变任何东西。

在我的应用程序中,这些格式化程序已注册:

System.Net.Http.Formatting.JsonMediaTypeFormatter System.Net.Http.Formatting.XmlMediaTypeFormatter System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter

SupportedMediaTypes 中只有最后两个包含 application/x-www-form-urlencoded

【问题讨论】:

您是否已经尝试过 [FromUri] 属性? 说实话,我并没有因为内容真的在正文中 - 如果我尝试使用它,我实际上得到了null 我也尝试了ModelBinder(空的,因为我还没有实现任何自定义活页夹),它对我也没有多大帮助。另外,我不会走这条路——对于 JSON,它可以工作,那我为什么要在这里实现 binder? 但是您声明“在处理 HTTP POST 表单请求时 (Content-Type: application/x-www-form-urlencoded)”? 对不起,我的意思是当我的动作处理程序 DoMagic 由于 POST 请求而被调用时。我期待请求正文中的数据(正如任何人都希望从 POST 获得的那样,对吧?:))——所以基本上,我正在发送 POST 有效负载。如果我发送带有适当 Content-Type 标头的 JSON,它就可以工作。当我提交表单时它不起作用(method="post")。 您的RequestContext.RouteDataRequest.Content 是什么样的?我对 curl 不熟悉,但我看到的 here 与您的帖子有些不同。 【参考方案1】:

在调试了一段时间后,我必须自己回答。

System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter 未使用,因为我的模型不是从 FormDataCollection 派生的,也不是 JS 令牌类型。所以格式化程序System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter 正在使用中。

CompositeModelBinder 中使用的绑定器是:

TypeMatchModelBinder(跳过) MutableObjectModelBinder(已使用)

我没有找到任何代码痕迹,这将考虑到 DataMemberAttributeName 属性 - 所以我必须为我的类型实现自己的 IModelBinder,这将负责自定义。

请注意:序列化对象时,一切都按预期工作 - 上述问题仅与从请求正文反序列化有关。

来源

System.Net.Http.Formatting.Formatting System.Web.Http.ModelBinding

我希望我没有错过任何东西。如果是这样,请纠正我。

【讨论】:

以上是关于通过 application/x-www-form-urlencoded 反序列化时未使用 WebAPI DataMember 名称的主要内容,如果未能解决你的问题,请参考以下文章

php 获取不到post的值

测试2

Python-提交json请求

Python-提交json请求

Python-提交json请求

如何使用 XMLHttpRequest 发送 POST 数据