2014-11-21 69 views
4

我正在创建Web Api方法,该方法应该通过XML或JSON接受对象列表并将它们添加到数据库中。JSON数组对象在WebAPI中使用FromBody进行建模

这里是什么,我现在有一个非常基本的版本:

[HttpPost] 
public HttpResponseMessage Put([FromBody]ProductAdd productAdd) 
{ 
    //do stuff with productadd object 
    return Request.CreateResponse(HttpStatusCode.OK); 
} 

它接受对象的列表的模型结构如下:

public class ProductAdd 
{ 
    public List<ProductInformation> Products { get; set; } 
} 

public class ProductInformation 
{ 
    public string ProductName { get; set; } 
} 

上述作品完美,当我正在使用XML - (Content-Type:application/xml)

<?xml version="1.0" encoding="utf-8"?> 
<ProductAdd> 
    <Products> 
     <ProductInformation> 
      <ProductName>Seahorse Necklace</ProductName> 
     </ProductInformation> 
    </Products> 
    <Products> 
     <ProductInformation> 
      <ProductName>Ping Pong Necklace</ProductName> 
     </ProductInformation> 
    </Products> 
</ProductAdd> 

Products has 2 Items

但是,当我试图喂同样的事情在使用JSON(内容类型:应用程序/ JSON),产品列表是空

{ 
    "ProductAdd": { 
    "Products": [ 
     { 
     "ProductInformation": { "ProductName": "Seahorse Necklace" } 
     }, 
     { 
     "ProductInformation": { "ProductName": "Ping Pong Necklace" } 
     } 
    ] 
    } 
} 

Products is null

是否存在与JSON的问题序列化的时候,有另一个对象内的对象数组?

任何想法可以解决这个问题?

感谢

编辑: 您使用的XML和JSON序列化是什么? XML:XmlSerializer JSON:Newtonsoft

回答

3

您发送到Web API方法的JSON与您要反序列化的结构不匹配。与XML不同,JSON中的根对象没有名称。您需要从您的JSON去除包装对象,以得到它的工作:

{ 
    "Products": [ 
     { 
     "ProductInformation": { "ProductName": "Seahorse Necklace" } 
     }, 
     { 
     "ProductInformation": { "ProductName": "Ping Pong Necklace" } 
     } 
    ] 
    } 

或者,你可以改变你的类结构要添加包装类,但你还需要改变你的XML相匹配。

public class RootObject 
{ 
    public ProductAdd ProductAdd { get; set; } 
} 
2

在反序列化失败神秘的情况下,我发现它有助于连载测试对象和比较所需输入的实际输出。如果输出与期望的输入不同,那可能是错误的原因。在你的情况,如果我反序列化的XML,它重新序列化到JSON,我得到:

{ 
    "Products": [ 
    { 
     "ProductName": "Seahorse Necklace" 
    }, 
    { 
     "ProductName": "Ping Pong Necklace" 
    } 
    ] 
} 

正如你所看到的,也有你的JSON间接的两个额外的水平相比reserialized XML:有是一个根对象名称,它不应该出现在JSON中,并且有集合元素类型名称,这也不应该存在。 (但这些都是XML中的常见功能。)

是否可以更改JSON,使其不具有这些额外的级别(如果是间接的)? (例如,为了测试的目的,这个JSON是否通过脚本从XML转换而来,因此并不反映真正的需求?)如果是这样,那么你的问题就解决了。

如果不是,那么这里是反序列化它的一些选项:

  1. 要读&写一个根对象的名字与你JSON,看到的解决方案herehere

    或者,滚你自己代理包装:

    public sealed class ProductAddWrapper 
    { 
        public ProductAddWrapper() 
        { 
        } 
    
        public ProductAddWrapper(ProductAdd product) 
        { 
         this.ProductAdd = product; 
        } 
    
        public ProductAdd ProductAdd { get; set; } 
    
        public static implicit operator ProductAdd(ProductAddWrapper wrapper) { return wrapper.ProductAdd; } 
    
        public static implicit operator ProductAddWrapper(ProductAdd product) { return new ProductAddWrapper(product); } 
    } 
    
  2. 向您的列表中注入额外的间接级别是有点困难。你需要做的是在你读写时重构JSON,增加或删除额外的人工嵌套层次。这可以用JsonConverter来完成:

    public class ProductAdd 
        { 
         [JsonConverter(typeof(CollectionWithNamedElementsConverter))] 
         public List<ProductInformation> Products { get; set; } 
        } 
    

    class CollectionWithNamedElementsConverter : JsonConverter 
    { 
        static Type GetEnumerableType(Type type) 
        { 
         foreach (Type intType in type.GetInterfaces()) 
         { 
          if (intType.IsGenericType 
           && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
          { 
           return intType.GetGenericArguments()[0]; 
          } 
         } 
         return null; 
        } 
    
        public override bool CanConvert(Type objectType) 
        { 
         return typeof(IEnumerable).IsAssignableFrom(objectType) 
          && !typeof(string).IsAssignableFrom(objectType) 
          && GetEnumerableType(objectType) != null; 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         JArray originalArray = JArray.Load(reader); 
         if (originalArray == null) 
          return null; 
         JArray array = new JArray(); 
         foreach (var item in originalArray) 
         { 
          var child = item.Children<JProperty>().FirstOrDefault(); 
          if (child != null) 
          { 
           var value = child.Value; 
           array.Add(child.Value); 
          } 
         } 
         return serializer.Deserialize(new StringReader(array.ToString()), objectType); 
        } 
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         var objectType = value.GetType(); 
         var itemType = GetEnumerableType(objectType); 
    
         IEnumerable collection = value as IEnumerable; 
    
         writer.WriteStartArray(); 
    
         foreach (object item in collection) 
         { 
          writer.WriteStartObject(); 
          writer.WritePropertyName(itemType.Name); 
          serializer.Serialize(writer, item); 
          writer.WriteEndObject(); 
         } 
    
         writer.WriteEndArray(); 
        } 
    } 
    

然后通过与项目类型名称应用[JsonConverter(typeof(CollectionWithNamedElementsConverter))]属性集合使用它

相关问题