如果Model类标记为Serializable,则不在Web API中映射参数值

时间:2015-10-19 13:03:41

标签: c# serialization asp.net-web-api

我有一个Web Api控制器,如下所示

public class HomeController : ApiController
{
    ....
    [HttpPost]
    [Route("api/Add")]
    public IHttpActionResult Add(Employee emp)
    {
        ...
    }
}

 [Serializable]
 public class Employee
 {
     public string Name { get; set; }
 }

仅当从Employee类中删除[Serializable]属性时,Http Post请求中发送的参数才会在Controller中映射。如果我添加该属性,则Name类中的属性Employee的值始终为null

当模型类标记为[Serializable]时,有人可以解释什么是错误的吗?

1 个答案:

答案 0 :(得分:2)

要理解为什么会发生这种情况,您需要了解SerializableAttribute的确切含义。这意味着可以通过序列化其公共和私有字段 (即,不是其属性)来序列化此类。该属性的日期来自c#1.0,​​当所有属性都有明确的支持字段时,该属性最初由BinaryFormatter使用。因此,当在c#3.0中引入自动实现的属性时,它们是如何序列化的?

并非所有序列化程序都支持[Serializable],而是通过按名称和值序列化hidden backing fields来序列化自动实现的属性的序列化程序。您没有说出您正在使用的Web API版本,也没有说明您可能正在使用的数据格式(XML或JSON):

  • DataContractSerializer。数据合同序列化程序支持[Serializable],如Types Supported by the Data Contract Serializer中所述。 XML数据协定序列化程序按如下方式序列化您的Employee类:

    <Employee>
        <_x003C_Name_x003E_k__BackingField>My Name</_x003C_Name_x003E_k__BackingField>
    </Employee>
    
  • DataContractJsonSerializer还序列化了支持字段,生成:

    {"<Name>k__BackingField":"My Name"}
    
  • Json.NET仅在DefaultContractResolver.IgnoreSerializableAttribute = false

    时序列化后备字段
        var employee = new Employee { Name = "My Name" };
        var json1 = JsonConvert.SerializeObject(employee, new JsonSerializerSettings { ContractResolver = new DefaultContractResolver { IgnoreSerializableAttribute = false } });
        Console.WriteLine(json1);
    

    还产生{"<Name>k__BackingField":"My Name"}。如果没有设置,Json.NET将忽略该属性。

  • XmlSerializer忽略[Serializable]

  • JavaScriptSerializer也会忽略[Serializable]

Web {的current version使用Json.NET和XmlSerializer,但这是可配置的。早期版本use the data contract serializers或有时甚至JavaScriptSerializer

因此,您的Name属性为null的原因是您正在使用其中一个支持[Serializable]的序列化程序,并且您发布的JSON或XML没有愚蠢的支持字段属性名称

要解决此问题,您有以下选择:

  1. 使用data contract attributes为您的班级添加注释。对于支持它的所有序列化程序,这些取代[Serializable]

    [Serializable]
    [DataContract]
    public class Employee
    {
        [DataMember]
        public string Name { get; set; }
    }
    
  2. 如果您使用的是XML,请确保使用here中指定的XmlSerializer

  3. 如果您在MVC 4 Web API中使用JSON和Json.NET,则可以在Application_Start中的Global.asax.cs中设置IgnoreSerializableAttribute = true

    protected void Application_Start()
    {
        HttpConfiguration config = GlobalConfiguration.Configuration;
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
            new DefaultContractResolver { IgnoreSerializableAttribute = true };
    }
    
  4. 或者,只需删除[Serializable],除了BinaryFormatter之外,你真的不需要它。