JSON序列化程序在失败的反序列化时创建一个空对象而不是null

时间:2013-04-23 20:55:25

标签: .net asp.net-mvc-4 asp.net-web-api json.net

在WebAPI中,我注意到我们的验证实践中存在不一致的问题。如果您使用xml中的POST发送错误的正文/有效负载,则反序列化将失败并且您将获得空指针。如果您在JSON中发送错误的正文/有效负载,则会得到一个空对象。这是误导,我不喜欢它。有没有办法强制使用失败的json反序列化的空指针??

更新: 我没有反序列化问题。我有一个行为问题似乎是DataContractSerializer和Json.net序列化程序之间的差异。当xml无法反序列化时,有效内容为空。但是,当Json无法反序列化时,似乎它正在实例化预期有效负载的默认实例。

错误的xml有效负载示例: enter image description here

使用错误的json有效负载进行相同调用的示例(有效负载不为空。相反,它是有效负载类的默认实例)

enter image description here

2 个答案:

答案 0 :(得分:4)

默认情况下,Web.API使用MissingMemberHandling.Ignore中的JsonMediaTypeFormatter设置。

您需要使用以下内容将其设置为MissingMemberHandling.Error

GlobalConfiguration.Configuration
   .Formatters.JsonFormatter
   .SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;

并且在发送JSON时应该null,如:

{
   "somenotexistingprop": ""
}

但是,如果发送一个完全空的JSON对象:{},那么您仍然会获得一个空属性而不是null的对象。因为JsonConvert.DeserializeObject在反序列化空JSON时会返回一个空对象(请参阅github的此单元测试)。

答案 1 :(得分:1)

在我的一位团队成员帮助我理解为什么会出现这种情况之后,以下是关于这种情况的一些注意事项:

  1. 我们默认情况下在Json格式化程序上没有“MissingMemberHandling.Error”,因为这可以帮助您将较新版本的客户端与额外成员一起发送到旧版本服务的情况。旧版本的服务仍应能够接受此请求并忽略其他属性。此行为与Xml格式化程序的行为方式一致。

  2. @Sinaesthetic:如果您正在设置“MissingMemberHandling.Error”并且不想依赖“ModelState.IsValid”检查,那么您可以检查ModelState的Keys属性以确定您的请求是否确实由于缺少成员或其他原因而无效。

  3. 以下示例:

    public class Customer
    {
        public int Id { get; set; }
    
        [MaxLength(5)]
        public string Name { get; set; }
    
        public Address Address { get; set; }
    }
    
    public class Address
    {
        public string Line1 { get;set;}
    }
    
    //action
    public void Post([FromBody]Customer customer)
        {
            if (!ModelState.IsValid)
            {
                ModelStateDictionary msd = new ModelStateDictionary();
    
                foreach (string key in ModelState.Keys)
                {
                    if (ModelState[key].Errors.Count > 0)
                    {
                        foreach (ModelError error in ModelState[key].Errors)
                        {
                            Exception ex = error.Exception;
    
                            if (ex != null 
                                && typeof(JsonSerializationException).IsAssignableFrom(ex.GetType()) 
                                && ex.Message.StartsWith("Could not find member"))
                            {
                                msd.AddModelError(key, ex);
                            }
                        }
                    }
                }
    
                if (msd.Count > 0)
                {
                    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, msd));
                }
            }
    
            //process the supplied customer
        }