从web api响应中反序列化对象

时间:2016-03-23 07:50:47

标签: c# vb.net json.net

我正在努力对象的反序列化...我在我的应用程序和web api中创建了相同的对象模型......它看起来像下面

public class Project
{
    // some propeties of project object..
    public SpecificationCollection Specs { get; set; }
    public Project()
    {
       Specs = new SpecificationCollection();
     }
}

[Serializable()]
public class SpecificationCollection : CollectionBase
{
    public ProjectSpec this[int index]
    {
        get { return (ProjectSpec)List[index]; }
        set { List[index] = value; }
    }
    //other implemented methods
}

public class ProjectSpec
{
   //Properties
   //Some other class object is also in this class but as of now i am not      
  //getting ProjectSpec
}

我尝试了以下内容:

{using newtonsoft refrence here}
Dim settings As New JsonSerializerSettings() 
settings.TypeNameHandling = TypeNameHandling.All //asme in auto typenamehandling
Dim str As Object = Await response.Content.ReadAsStringAsync()
Dim deserializedList As Project = JsonConvert.DeserializeObject(Of Project)(str, settings)

这也是:

Await response.Content.ReadAsAsync(Of Project)()

我将Project对象转换为精细但不是集合。请建议如何评估这种情况。感谢

SAMPLE JSON

 {"ProjectID":134,"ProjectName":"ABC","LPID":"","DNumber":0,"OrgnCode":"SPt","OrgnDesc":null,"SRatingCode":"AANSub","SRatingDesc":"AASub","ProjectConCode":"","ProjectCon":"desc","OrTCode":"Csity","OrTDesc":"Corsity","Projectsdf":"Miscld","ProjectType":"Miscellaneous","ProjectStatus":"","Street1":"","Street2":"","Street3":"","City":"Princeton","State":"NJ","StateName":"NY","PostalCode":"081","CountyCode":null,"CountyName":null,"CountryCode":"USA            ","CountryName":"UNITED STATES","TCode":"AA03","TName":"A03","IsA":false,"IsF1":false,"IsF2":false,"IsBacked":false,"IsMeeting":false,"IsVerified":true,"HSpec":false,"NumSpecs":0,"BidDate":"1901-01-01T00:00:00","BidStartDate":"0001-01-01T00:00:00","BidEndDate":"0001-01-01T00:00:00","EnteredBy":"User","EnteredDate":"2014-02-26T14:39:00","LockedBy":null,"LockedDate":"0001-01-01T00:00:00","CreatedBy":"dfg","CreatedDate":"2014-02-26T14:39:00","ModifiedBy":"dfgl","ModifiedDate":"2014-05-07T15:03:00","DeletedDate":null,"SysDate":"2016-01-07T07:11:00","TotalRows":0,"MonthsBack":"0001-01-01T00:00:00","SkID":-2147483648,"ArchID":"dfgdfg","AuthoredBy":"0","DModifiedDate":"1901-01-01T00:00:00","DVersion":0,"Flag":0,"OClassCode":null,"ProjectOrClass":null,"StCode":"DEFAULT","StDesc":null,"Specs":[{"SpecId":51993,"ESpecID":"558","Origin":"OS","OrName":"Openings Studio","WriterID":null,"WriterName":null,"DistName":"","ArchitectName":null,"SpecDate":"0001-01-01T00:00:00","SpecEstBidDate":"0001-01-01T00:00:00","ContractorName":null,"ProductLines":null,"CreatedDate":"2014-03-10T11:34:00","CreatedBy":"dfgdfg","ModifiedDate":"2014-03-10T11:34:00","ModifiedBy":"dfgdfg","STProjectName":null,"OwnerType":null,"SRating":null,"StickRating":null,"ProjectValue":0.0},{"SpecId":52000,"ESpecID":"635","Origin":"dfgdfg","OrName":"dfgdfg","WriterID":null,"WriterName":null,"DistName":"","ArchitectName":null,"SpecDate":"0001-01-01T00:00:00","SpecEstBidDate":"0001-01-01T00:00:00","ContractorName":null,"ProductLines":null,"CreatedDate":"2014-03-10T14:08:00","CreatedBy":"SpecTrak","ModifiedDate":"2014-03-10T14:08:00","ModifiedBy":"dfgdfgdfg","STProjectName":null,"OwnerType":null,"SRating":null,"StickRating":null,"ProjectValue":0.0}]}

1 个答案:

答案 0 :(得分:2)

问题是CollectionBase是非通用的无类型集合,因此除非传入中存在$type元数据属性,否则Json.NET无法知道如何反序列化其项目。 JSON - 他们显然不是。实际上,这个班级是considered to be obsolete。 Microsoft的准则When to Use Generic Collections声明:

  

通常建议使用泛型集合,因为您可以获得类型安全的直接好处,而无需从基本集合类型派生并实现特定于类型的成员。当集合元素是值类型时,泛型集合类型通常也比相应的非泛型集合类型(并且优于从非泛型集合类型派生的类型)执行得更好,因为使用泛型不需要对元素进行封装。

因此建议您继承System.Collections.ObjectModel.Collection<T>

public class SpecificationCollection : Collection<ProjectSpec>
{
}

话虽如此,如果您必须继续使用CollectionBase,您可以让SpecificationCollection 实施ICollection<ProjectSpec> 在下面打字。如果你这样做,Json.NET将能够成功反序列化它:

[Serializable()]
public class SpecificationCollection : TypedCollectionBase<ProjectSpec>
{
}

[Serializable()]
public class TypedCollectionBase<TItem> : CollectionBase, IList<TItem>
{
    #region IList<TItem> Members

    public int IndexOf(TItem item)
    {
        return List.IndexOf(item);
    }

    public void Insert(int index, TItem item)
    {
        List.Insert(index, item);
    }

    public TItem this[int index]
    {
        get { return (TItem)List[index]; }
        set { List[index] = value; }
    }

    #endregion

    #region ICollection<TItem> Members

    public void Add(TItem spec)
    {
        List.Add(spec);
    }

    public bool Contains(TItem item)
    {
        return List.Contains(item);
    }

    public void CopyTo(TItem[] array, int arrayIndex)
    {
        foreach (var item in this)
            array[arrayIndex++] = item;
    }

    public bool IsReadOnly { get { return List.IsReadOnly; } }

    public bool Remove(TItem item)
    {
        int index = IndexOf(item);
        if (index >= 0)
            RemoveAt(index);
        return index >= 0;
    }

    #endregion

    #region IEnumerable<TItem> Members

    public new IEnumerator<TItem> GetEnumerator()
    {
        return List.Cast<TItem>().GetEnumerator();
    }

    #endregion
}

如果您无法以任何方式修改SpecificationCollection的设计,则需要编写自己的JsonConverter进行反序列化:

public class CollectionBaseConverter<TCollection, TItem> : JsonConverter where TCollection : CollectionBase
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(TCollection).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        TCollection collection = (TCollection)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
        var wrapper = new CollectionBaseWrapper<TCollection, TItem>(collection);
        serializer.Populate(reader, wrapper);
        return collection;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var collection = (TCollection)value;
        serializer.Serialize(writer, collection.Cast<TItem>());
    }
}

class CollectionBaseWrapper<TCollection, TItem> : ICollection<TItem> where TCollection : CollectionBase
{
    readonly IList collection;

    public CollectionBaseWrapper(TCollection collection)
    {
        if (collection == null)
            throw new ArgumentNullException();
        this.collection = collection;
    }

    public void Add(TItem item)
    {
        collection.Add(item);
    }

    public void Clear()
    {
        collection.Clear();
    }

    public bool Contains(TItem item)
    {
        return collection.Contains(item);
    }

    public void CopyTo(TItem[] array, int arrayIndex)
    {
        foreach (var item in this)
            array[arrayIndex++] = item;
    }

    public int Count { get { return collection.Count; } }

    public bool IsReadOnly { get { return collection.IsReadOnly; } }

    public bool Remove(TItem item)
    {
        bool found = collection.Contains(item);
        if (found)
            collection.Remove(item);
        return found;
    }

    public IEnumerator<TItem> GetEnumerator()
    {
        return collection.Cast<TItem>().GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

然后在设置中使用它,如下所示:

var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, Converters = new[] { new CollectionBaseConverter<SpecificationCollection, ProjectSpec>() } };
var deserializedList = JsonConvert.DeserializeObject<Project>(str, settings);