在WebApi服务中,使用[FromUri]属性时DataMember的Name属性会被忽略。

27

我们正在使用Asp.Net WebApi创建RestService。但由于某些原因,在尝试通过[FromURI]属性反序列化复杂属性时,DataMember属性中的Name属性被忽略了。

例如,我们可能会有:

方法:

public IHttpActionResult Get([FromUri]User user)

型号:

[DataContract]
public class User
{
    [DataMember(Name = "username")]
    public string Username{ get; set; }
    [DataMember(Name = "isActive", IsRequired = false)]
    public bool? Active { get; set; }
}

反序列化user时,我们得到了预期的用户名,但是Active的值却是null。另一方面,当序列化数据时,我们得到了预期的isActiveusername。如果我们在查询字符串中使用active发送请求,它也能按预期工作。

显然这是IModelBinder的问题。由于某种原因,它没有使用DataMemberName属性。我检查了包含的格式化程序,发现注册了4个默认格式化程序:

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

我没有办法检查请求中使用了哪一个。 我认为应该是 FormUrlEncodedMediaTypeFormatter,但我不能确定。 此外,我不确定它是否支持 Name 属性。

我已经寻找解决方案,并且最接近的主题是 WebAPI DataMember Name not used when de/serializing via application/x-www-form-urlencoded,但它不使用 [FromUri],而是用 application/x-www-form-urlencoded 属性,并且并没有真正解决问题。

任何想法、提示或建议将不胜感激。


4
你有没有弄清楚出了什么问题?我也面临着同样的问题。 - Zuhaib
2
很遗憾,我在WebApi中遇到了这个bug并且已经想办法解决了它。 - Igor
1
嗨,@jaroslaw,这个问题已经五年了,因此有些过时了,我不确定它在今天是否仍然相关...如果您有特定的相关问题,我建议您在SO上开一个单独的问题。 - Igor
这在FromBody中工作得好吗? - Harkirat singh
你尝试过将 Nullable<Active> 的设置更改为 Active 吗? - Harkirat singh
显示剩余3条评论
2个回答

1

使用 [FromQuery] 替代其他属性。

并为您的请求建立模型 http://localhost:8080/api/users?username=John&isActive=true

[Route("api/users")]
public class UsersController : Controller
{
    [HttpGet]
    public IHttpActionResult Get(User user)
    {
        //...
    }
}

将会是这样的外观

public class User
{
    [FromQuery(Name = "username")]
    public string Username{ get; set; }
    [FromQuery(Name = "isActive")]
    public bool? Active { get; set; }
}

无论如何,最佳实践是将名称保留在模型中作为查询的参数名。

在这种情况下,您不必提供“Name”参数,只需将[FromQuery]保留在查询类上,并且.NET会自动转换为小写。


0

你必须检查你的“get”请求。你的get请求必须像这样;

GET api/foo?username=fooname&active=false

你不需要使用DataContract和DataMember属性来达到这个目的。这些属性只是为了另一种用途,并不是主要使用的原因。
在你的get方法中获得有效结果后,你可以像下面这样检查modelstate:
if (ModelState.IsValid) {
/// your code goes here    
}

1
你好,orhun.begendi,感谢你的帮助尝试。不幸的是,那不是问题所在。 请求已经通过并且我已经“获取”它了 :) 问题在于DataMember描述符中定义的名称被忽略了。 请再次阅读整个描述 :) - Igor
你好,你看了这篇文章吗?http://aspnetwebstack.codeplex.com/workitem/270 我觉得这对这个主题非常有用,通过这个配置,你可以强制在Web API请求中使用datamember属性, GlobalConfiguration.Configuration.Services.RemoveAll( typeof(System.Web.Http.Validation.ModelValidatorProvider), v => v is InvalidModelValidatorProvider); 希望这对你有所帮助。 - orhun.begendi
你好,你可以尝试构建自己的模型绑定。可以继承IModelBinder接口。这可能会很有帮助,你可以查看这篇文章: http://www.strathweb.com/2013/04/asp-net-web-api-parameter-binding-part-1-understanding-binding-from-uri/ - orhun.begendi
OP想要使用..&isActive=false,例如。这里没有什么需要检查的,因为没有分配任何内容来检查。 - user2864740

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接