c# - DataMember Name attribute ignored when deserializing a JSON object - Stack Overflow

admin2025-05-01  1

I have an issue deserializing a JSON object into my class.

I have a class DocumentListByPolicy that is used as a List<> in another class. For the document list, this is my code:

namespace MyNameSpace
{
    [DataContract]
    public class DocumentListByPolicy
    {
        [DataMember(Name = "documentCreatedDate")]
        public DateTime DocumentCreatedDate { get; set; }

        [DataMember(Name = "comment")]
        public string VehicleVinNumber { get; set; }
         
        // ..... more properties here
    }
}

What I am trying to do is reference the "comment" property as VehicleVinNumber which I am doing in a LINQ statement:

DocIDsByVIN = resp.LevelDocumentList.GroupBy(d => d.VehicleVinNumber.Trim())
    .Select(l => l.OrderByDescending(d => d.DocumentCreatedDate).FirstOrDefault(d => d.DocumentId > 0))
    .Where(r => r != null)
    .ToDictionary(r => r.VehicleVinNumber.Trim(), r => r.DocumentId);

It compiles and runs but throws an error in the LINQ code because it says VehicleVinNumber is null. If I change the name in the model back to "comment" or "Comment" the code works as expected. My impression with the DataMember attribute was to be able to map the values coming back to my model property names, but this does not seem to happen. The mapping is not occurring.

Can anyone please tell me what I am doing wrong?

Thanks

The deserialization is being done by RestSharp extension methods.

public static partial class RestClientExtensions {
    [PublicAPI]
    public static RestResponse<T> Deserialize<T>(this IRestClient client, RestResponse response)
        => client.Serializers.Deserialize<T>(response.Request!, response, client.Options);

I have an issue deserializing a JSON object into my class.

I have a class DocumentListByPolicy that is used as a List<> in another class. For the document list, this is my code:

namespace MyNameSpace
{
    [DataContract]
    public class DocumentListByPolicy
    {
        [DataMember(Name = "documentCreatedDate")]
        public DateTime DocumentCreatedDate { get; set; }

        [DataMember(Name = "comment")]
        public string VehicleVinNumber { get; set; }
         
        // ..... more properties here
    }
}

What I am trying to do is reference the "comment" property as VehicleVinNumber which I am doing in a LINQ statement:

DocIDsByVIN = resp.LevelDocumentList.GroupBy(d => d.VehicleVinNumber.Trim())
    .Select(l => l.OrderByDescending(d => d.DocumentCreatedDate).FirstOrDefault(d => d.DocumentId > 0))
    .Where(r => r != null)
    .ToDictionary(r => r.VehicleVinNumber.Trim(), r => r.DocumentId);

It compiles and runs but throws an error in the LINQ code because it says VehicleVinNumber is null. If I change the name in the model back to "comment" or "Comment" the code works as expected. My impression with the DataMember attribute was to be able to map the values coming back to my model property names, but this does not seem to happen. The mapping is not occurring.

Can anyone please tell me what I am doing wrong?

Thanks

The deserialization is being done by RestSharp extension methods.

public static partial class RestClientExtensions {
    [PublicAPI]
    public static RestResponse<T> Deserialize<T>(this IRestClient client, RestResponse response)
        => client.Serializers.Deserialize<T>(response.Request!, response, client.Options);
Share Improve this question edited Jan 2 at 22:39 dbc 118k26 gold badges264 silver badges388 bronze badges asked Jan 2 at 20:44 JimboJonesJimboJones 1418 silver badges18 bronze badges 6
  • Can you please share the deserialization code too? – Guru Stron Commented Jan 2 at 20:46
  • I have edited the original post and added the code – JimboJones Commented Jan 2 at 20:48
  • Edited: This is the deserialization code being called: The code shown is serialization code. Can you please share a minimal reproducible example, specifically sample JSON, root model + deserialization code? Thanks! – dbc Commented Jan 2 at 21:52
  • Sorry, my mistake on that one. I see no specific deserialization code just a call to an external API and gets the response back var response = .... call to API – JimboJones Commented Jan 2 at 22:06
  • Can you provide a full minimal reproducible example by sharing a JSON sample? One thing to keep in mind is that, if I recall correctly, DataContractJsonSerializer is case-sensitive so if your JSON property names differ in case, deserialization may fail. See e.g. Can not Deserialize json string to class. Make sure your JSON property case names match. – dbc Commented Jan 2 at 22:31
 |  Show 1 more comment

1 Answer 1

Reset to default 3

RestSharp does not use or support DataContractJsonSerializer out of the box, so the default serializer does not recognise [DataContract] or [DataMember]. See the documentation for how to configure serialization in RestSharp.

DataContract Serialization was designed for use in WCF projects and is no longer commonly supported by 3rd party libraries, for JSON projects in .Net Framework Json.NET (Newtonsoft.Json) is the community default, RestSharp has support for this Json.NET serializer

If you change over to Json.NET serializer then you can use JsonPropertyAttribute to annotate your properties and specify the name in the json content to map to:

[JsonProperty("comment")]
public string VehicleVinNumber { get;set; }

In Json.NET it is not necessary to annotate all properties to go from camel case to Pascal case as the serializer by default is case insensitive, so your class only needs this minimal representation:

using Newtonsoft.Json;

public class DocumentListByPolicy
{
    public DateTime DocumentCreatedDate { get; set; }

    [JsonProperty("comment")]
    public string VehicleVinNumber { get; set; }
    
    // ..... more properties here
}

If converting to Json.NET is not a viable option, you can add support for [DataContract] using a custom serializer

public class RestDataContractJsonSerializer : IRestSerializer, ISerializer, IDeserializer
{
    public string Serialize(object obj)
    {
        if (obj == null) return null;
        var serializer = new DataContractJsonSerializer(obj.GetType());
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, obj); 
            return Encoding.UTF8.GetString(ms.ToArray());
        }
    }

    public string Serialize(Parameter bodyParameter) => Serialize(bodyParameter.Value);
    public T Deserialize<T>(RestResponse response)
    {
        if (response.Content == null) return default;
        var serializer = new DataContractJsonSerializer(typeof(T));
        using (var ms = new MemoryStream())
        {
            ms.Write(response.RawBytes, 0, response.RawBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);
            return (T)serializer.ReadObject(ms);
        }
    }
    public ContentType ContentType { get; set; } = ContentType.Json;
    public ISerializer Serializer => this;
    public IDeserializer Deserializer => this;
    public DataFormat DataFormat => DataFormat.Json;
    public string[] AcceptedContentTypes => ContentType.JsonAccept;
    public SupportsContentType SupportsContentType
        => contentType => contentType.Value.EndsWith("json", StringComparison.InvariantCultureIgnoreCase);
}

This is an example implementation:

namespace RestSharpDemo
{
    using System.Text;
    using RestSharp;
    using RestSharp.Serializers;

    internal class Program
    {
        static void Main(string[] args)
        {
            var client = new RestClient("https://northwind.vercel.app/api/",
                configureSerialization: s => s.UseSerializer<RestDataContractJsonSerializer>());
            var request = new RestRequest("categories/3");

            var response = client.ExecuteGet<NorthWindCategory>(request);
            Console.WriteLine(response.Content);
            Console.WriteLine("Id:           {0}", response.Data.Id);
            Console.WriteLine("Description:  {0}", response.Data.Description);
            Console.WriteLine("CategoryName: {0}", response.Data.CategoryName);
        }
    }
    [DataContract]
    public class NorthWindCategory
    {
        [DataMember(Name = "id")]
        public int Id { get; set; }
        [DataMember(Name = "description")]
        public string Description { get; set; }
        [DataMember(Name = "name")]
        public string CategoryName { get; set; }
    }

    public class RestDataContractJsonSerializer : IRestSerializer, ISerializer, IDeserializer
    {
        public string Serialize(object obj)
        {
            if (obj == null) return null;
            var serializer = new DataContractJsonSerializer(obj.GetType());
            using (var ms = new MemoryStream())
            {
                serializer.WriteObject(ms, obj); 
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }

        public string Serialize(Parameter bodyParameter) => Serialize(bodyParameter.Value);
        public T Deserialize<T>(RestResponse response)
        {
            if (response.Content == null) return default;
            var serializer = new DataContractJsonSerializer(typeof(T));
            using (var ms = new MemoryStream())
            {
                ms.Write(response.RawBytes, 0, response.RawBytes.Length);
                ms.Seek(0, SeekOrigin.Begin);
                return (T)serializer.ReadObject(ms);
            }
        }
        public ContentType ContentType { get; set; } = ContentType.Json;
        public ISerializer Serializer => this;
        public IDeserializer Deserializer => this;
        public DataFormat DataFormat => DataFormat.Json;
        public string[] AcceptedContentTypes => ContentType.JsonAccept;
        public SupportsContentType SupportsContentType
            => contentType => contentType.Value.EndsWith("json", StringComparison.InvariantCultureIgnoreCase);
    }
}

Producing the following output:

转载请注明原文地址:http://anycun.com/QandA/1746097249a91627.html