5

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

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

错误的 xml 有效负载示例: 在此处输入图像描述

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

在此处输入图像描述

4

2 回答 2

4

默认情况下,Web.APIMissingMemberHandling.Ignore使用JsonMediaTypeFormatter.

您需要将其设置为MissingMemberHandling.Error

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

你应该null在发送 JSON 时得到:

{
   "somenotexistingprop": ""
}

但是,如果您发送一个完全空的 JSON 对象:{}那么您仍然会得到一个具有空属性的对象,而不是null. 因为JsonConvert.DeserializeObject如果它反序列化一个空的 JSON,则返回一个空对象(参见github的这个单元测试)。

于 2013-04-23T21:25:15.747 回答
1

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

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

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

下面的例子:

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
    }
于 2013-05-02T06:01:37.373 回答