通过 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.RouteData
和Request.Content
是什么样的?我对 curl 不熟悉,但我看到的 here 与您的帖子有些不同。
【参考方案1】:
在调试了一段时间后,我必须自己回答。
System.Net.Http.Formatting.FormUrlEncodedMediaTypeFormatter
未使用,因为我的模型不是从 FormDataCollection
派生的,也不是 JS 令牌类型。所以格式化程序System.Web.Http.ModelBinding.JQueryMvcFormUrlEncodedFormatter
正在使用中。
CompositeModelBinder
中使用的绑定器是:
TypeMatchModelBinder
(跳过)
MutableObjectModelBinder
(已使用)
我没有找到任何代码痕迹,这将考虑到 DataMemberAttribute
的 Name
属性 - 所以我必须为我的类型实现自己的 IModelBinder
,这将负责自定义。
请注意:序列化对象时,一切都按预期工作 - 上述问题仅与从请求正文反序列化有关。
来源
System.Net.Http.Formatting.Formatting System.Web.Http.ModelBinding我希望我没有错过任何东西。如果是这样,请纠正我。
【讨论】:
以上是关于通过 application/x-www-form-urlencoded 反序列化时未使用 WebAPI DataMember 名称的主要内容,如果未能解决你的问题,请参考以下文章