Search code examples
c#jsondeserializationdatacontractserializerdatacontractjsonserializer

Partial deserialization of JSON object by using DataContractJsonSerializer


As a response from a Bitbucket REST API I'm getting the following JSON object (simplified version):

{
    "repositories": [
        {
            "scm": "hg",
            "has_wiki": false,            
            "language": "c#",
            "slug": "Repo1"
        },
        {
            "scm": "hg",
            "has_wiki": false,            
            "language": "java",
            "slug": "Repo2"
        },
        {
            "scm": "hg",
            "has_wiki": true,            
            "language": "c#",
            "slug": "Repo3"
        }
    ],
    "user": {
        "username": "someuser",
        "first_name": "Some",
        "last_name": "User",
        "display_name": "Some User",
        "is_team": false,
        "avatar": "https://someuseravatar.com",
        "resource_uri": "/1.0/users/someuser"
    }
}

The only part from this JSON object I need to be deserialized is a user part. For that purposes I created the following class:

[DataContract(Name="user")]
public class BitbucketUser
{
    [DataMember(Name = "username")]
    public string Username { get; set; }

    [DataMember(Name = "first_name")]
    public string FirstName { get; set; }

    [DataMember(Name = "last_name")]
    public string LastName { get; set; }

    [DataMember(Name = "display_name")]
    public string DisplayName { get; set; }

    [DataMember(Name = "is_team")]
    public bool IsTeam { get; set; }

    [DataMember(Name = "avatar")]
    public string Avatar { get; set; }

    [DataMember(Name = "resource_uri")]
    public string ResourceUri { get; set; }
}

And a helper method to deserialize json:

public static T Deserialize<T>(string json)
{
    DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
    using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
    {
        T result = (T)deserializer.ReadObject(stream);
        return result;
    }
}

So, when I'm trying to get deserialized User object by using this code:

User user = JsonHelper.Deserialize<User>(jsonResponse);

Then I'm getting user object created containing all properties as null. I have tried to find right attributes to use on class header, but the result is same. And also I'm not using a Json.NET library just to avoid extra library reference as well as I'm not creating wrapper class to hold that user object as property of User type and repositores object as a array of the Repositories[] type. Is there a solution for this issue to get deserialized user object without null fields ?


Solution

  • Your code doesn't work, because the JSON object you're deserializing doesn't have any of the User properties. The deserializer certainly won't try looking into children of the current object to see if something matches.

    What you should do is to create a type that represents the whole response object. If you're not interested in the repositories part, then just omit it.

    The following code works for me:

    [DataContract]
    public class BitbucketResponse
    {
        [DataMember(Name="user")]
        public BitbucketUser User { get; set; }
    }
    
    [DataContract]
    public class BitbucketUser
    {
        [DataMember(Name = "username")]
        public string Username { get; set; }
    
        // etc.
    }
    
    …
    
    var serializer = new DataContractJsonSerializer(typeof(BitbucketResponse));
    using (var stream = …)
    {
        var response = (BitbucketResponse)serializer.ReadObject(stream);
        var user = response.User;
    }