Datacontract object and string - c#

I'm trying to parse some results from a web service in C# visual studio 2010 that are coming back in JSON but the field named data is sometime a string and sometimes an object. I'm not sure how to get the data contracts to handle that. When it runs through the deserialization it just returns a null result for the everything. If i try a web request that doesn't have any profile_results then works OK.
The JSON looks like this
{
"ListSingleOrganization": {
"id": 86270,
"short_name": "someshort name",
"long_name": "Long name",
"created_at": "2014-05-02T14:21:06Z",
"is_disabled": false,
"description": "Verbose description",
"renewed_at": "2014-05-02T14:21:07Z",
"alternate_id": null,
"website_url": "http://www.url.com",
"member_count": 50,
"pic_url": "https://www.somepicture.com/1.jpg",
"umbrella_id": 36016,
"keywords": "Fraternity, Leadership, Human Service, Scholarship",
"category": {
"id": 53282,
"name": "Fraternities"
},
"profile_responses": [
{
"element": {
"id": 51350,
"name": "Group Email Address",
"type": "Email"
},
"data": "groupsemail#gmail.com"
},
{
"element": {
"id": 1239634,
"name": "Please list your organization's Twitter handle so we may follow you with our office's account. (#something)",
"type": "TextField"
},
"data": "#handle"
},
{
"element": {
"id": 1192652,
"name": "Is this a new organization?",
"type": "Radio"
},
"data": {
"id": 2003570,
"name": "No"
}
}
]
}
}
the difference is based on the element type but i don't know how to account for that with them having the same name.
right now i have
[DataContract]
class ListSingleOrganization
{
//other members
[DataMember(Name = "profile_responses")]
public List<profile_responses> profile_responses { get; set; }
}
[DataContract]
class profile_responses
{
[DataMember(Name = "element")]
public element element { get; set; }
[DataMember(Name="data")]
public data data {get; set; }
}
[DataContract]
class element
{
[DataMember(Name = "id")]
public int id { get; set; }
[DataMember(Name = "name")]
public string name { get; set; }
[DataMember(Name = "type")]
public string type { get; set; }
}
[DataContract]
class data
{
[DataMember(Order=1)]
public string raw { get; set; }
[DataMember(Name = "file_name")]
public string file_name { get; set; }
[DataMember(Name = "url")]
public string url { get; set; }
[DataMember(Name = "id")]
public int id { get; set; }
[DataMember(Name = "name")]
public string name { get; set; }
}

You can create a custom formatter to read the property, check if it a string. If it's a string then create a new instance of your data class and set one of the properties to the string value. Otherwise, deserialize it to a your data object.
public class JsonDataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(data));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
data returnVal = null;
// You may need to debug this and see which token type is being returned
// per data element and adjust, but the principle stands.
if (reader.TokenType == JsonToken.String)
{
returnVal = new data();
returnVal.raw = reader.ReadAsString();
}
else
{
returnVal = serializer.Deserialize<data>(reader);
}
return returnVal;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Assuming you only need to deserialize
throw new NotImplementedException();
}
}
Associate the JsonConverter with your property:
[DataMember(Name = "data")]
[JsonConverter(typeof(JsonDataConverter))]
public data data { get; set; }
EDIT: (answering follow up question)
Set this up in an isolated unit test and get it to work there first before trying to put this in a SSIS package. If you are using the DataContractSerializer then the JsonDataConverter class will not be invoked. You want to deserialize using Json.NET:
using Newtonsoft.Json;
. . .
var orgList JsonConvert.DeserializeObject<ListSingleOrganization>(webServiceResultString);

Couldn't get the DataContract Serializes to work with these irregularities so I went the dynamic object route and that worked.
Deserialize JSON into C# dynamic object?

Related

How to deserialize Json into an C# object and fill the components into a dictionary

{
"success": true,
"data": [{
"type": "Employee",
"attributes": {
"id": {
"label": "ID",
"value": 8556527,
"type": "integer",
"universal_id": "id"
},
"email": {
"label": "Email",
"value": "exapmle#gmail.com",
"type": "standard",
"universal_id": "email"
},
"dynamic_2682839": {
"label": "DATEV Personalnumber",
"value": "31604",
"type": "standard",
"universal_id": "staff_number"
}
}
},
public class Id
{
[JsonPropertyName("label")]
public string Label { get; set; }
[JsonPropertyName("value")]
public int Value { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("universal_id")]
public string UniversalId { get; set; }
}
public class Email
{
[JsonPropertyName("label")]
public string Label { get; set; }
[JsonPropertyName("value")]
public string Value { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("universal_id")]
public string UniversalId { get; set; }
}
public class Dynamic2682839
{
[JsonPropertyName("label")]
public string Label { get; set; }
[JsonPropertyName("value")]
public string Value { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("universal_id")]
public string UniversalId { get; set; }
}
public class Attributes
{
[JsonPropertyName("id")]
public Id Id { get; set; }
[JsonPropertyName("email")]
public Email Email { get; set; }
[JsonPropertyName("dynamic_2682839")]
public Dynamic2682839 Dynamic2682839 { get; set; }
}
public class Datum
{
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("attributes")]
public Attributes Attributes { get; set; }
}
public class Root
{
[JsonPropertyName("success")]
public bool Success { get; set; }
[JsonPropertyName("data")]
public List<Datum> Data { get; set; }
}
I know it is probably are very simple solution behind it but i cant get to it. My Problem is that I want to deserialize this type of data into an object for example. This json file goes on forever but the only thing I'm interested in are the "ID" and the "Personalnumber" so I can create a dictionary for further processing with my code.
I mean I could just sit there for two days and add everything to the dictionary but first of all it would drive me crazy and second of all the dictionary should add new members automatically to the dictionary and shouldn't be static. I already converted the Json into class objects and downloaded Newtonsoft for my IDE and with this comand:
Id ids = JsonConvert.DeserializeObject<Id>(json);
Console.WriteLine(ids.Value);
I try to get all the values from the ID´s but all i get is a 0.
The thing is i tested everything so far and it works perfectly but my deserialization dont work as planned.
If anyone could help a newbie I would appreciate it.
This looks wrong
Id ids = JsonConvert.DeserializeObject<Id>(json);
You should probably be deserializing to Root instead.
Root root = JsonConvert.DeserializeObject<Root>(json);
From there you can get all the IDs with
List<Id> ids = root.Data.Select(datum => datum.Attributes.Id);
This json file goes on forever but the only thing I'm interested in are the "ID" and the "Personalnumber" ... the dictionary should add new members automatically ... and shouldn't be static.
Phuzi's answer seizes onto the wrong thing, giving you the contents of the "id" object, which does get you the ID, but ignores the Personalnumber..
..which also looks like it might not always be in a dynamic_2682839
We need a different strategy for getting the data; we can look to see if the label contains ID or Personalnumber but we could really do with the serializes deser'ing this data to a common set of objects, not a different Type (with the same properties) each time
I don't know if you used QuickType.IO for generating your JSON classes but, if you didn't, I would recommend it; it's a bit more sophisticated than other generators. You can trick it into helping you more by modifying your JSON..
Take this:
{
"success": true,
"data": [
{
"type": "Employee",
"attributes": {
"id": {
"label": "ID",
"value": 8556527,
"type": "integer",
"universal_id": "id"
},
"email": {
"label": "Email",
"value": "exapmle#gmail.com",
"type": "standard",
"universal_id": "email"
},
"dynamic_2682839": {
"label": "DATEV Personalnumber",
"value": "31604",
"type": "standard",
"universal_id": "staff_number"
}
}
}
]
}
And make it into this (put some more objects in "attributes", and make the keys of the dictionary into sequential numbers):
{
"success": true,
"data": [{
"type": "Employee",
"attributes": {
"1": {
"label": "ID",
"value": 8556527,
"type": "integer",
"universal_id": "id"
},
"2": {
"label": "Email",
"value": "exapmle#gmail.com",
"type": "standard",
"universal_id": "email"
},
"3": {
"label": "DATEV Personalnumber",
"value": "31604",
"type": "standard",
"universal_id": "staff_number"
},
"4": {
"label": "DATEV Personalnumber",
"value": "31604",
"type": "standard",
"universal_id": "staff_number"
},
"5": {
"label": "DATEV Personalnumber",
"value": "31604",
"type": "standard",
"universal_id": "staff_number"
}
}
}]
}
which will help QT see more easily that a Dictionary<string, Attribute> is suitable for "attributes", and a custom converter is needed for the varying type of "value"...
Otherwise you'll just get multiple identical classes (your Id, Email and Dynamic_123 classes) and a property for every member of "attributes" even though they're all the same:
You thus get these classes out of QT:
namespace SomeNamespace
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class SomeRoot
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("data")]
public Datum[] Data { get; set; }
}
public partial class Datum
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("attributes")]
public Dictionary<string, Attribute> Attributes { get; set; }
}
public partial class Attribute
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("value")]
public Value Value { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("universal_id")]
public string UniversalId { get; set; }
}
public partial struct Value
{
public long? Integer;
public string String;
public static implicit operator Value(long Integer) => new Value { Integer = Integer };
public static implicit operator Value(string String) => new Value { String = String };
}
public partial class SomeRoot
{
public static SomeRoot FromJson(string json) => JsonConvert.DeserializeObject<SomeRoot>(json, SomeNamespace.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this SomeRoot self) => JsonConvert.SerializeObject(self, SomeNamespace.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
ValueConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ValueConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(Value) || t == typeof(Value?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.Integer:
var integerValue = serializer.Deserialize<long>(reader);
return new Value { Integer = integerValue };
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new Value { String = stringValue };
}
throw new Exception("Cannot unmarshal type Value");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (Value)untypedValue;
if (value.Integer != null)
{
serializer.Serialize(writer, value.Integer.Value);
return;
}
if (value.String != null)
{
serializer.Serialize(writer, value.String);
return;
}
throw new Exception("Cannot marshal type Value");
}
public static readonly ValueConverter Singleton = new ValueConverter();
}
}
and you can get your ID/Personalnumber attributes like this:
var someRoot = SomeRoot.FromJson(File.ReadAllText("a.json"));
var attribs = someRoot.Data.SelectMany(d => d.Attributes.Where(a => a.Value.Label == "ID" || a.Value.Label.Contains("Personalnumber"))).ToArray();
or some other LINQ of your choosing on the Dictionary at the path "data"."attributes" - here I've chosen to SelectMany; if Data had 10 elements, and each element had 4 Attributes, 2 of which were ID or Personalnumber, you'd get a single array of 20 long, of the ID/Personalnumber Attributes. You might not want to SelectMany, if you want to keep them together (they're only loosely related by ordering in the array after a SelectMany)

How to avoid incompatible during deserializing polymorphic properties in MassTransit?

When using the request/response pattern, during the deserialization of the response, an incompatibility error occurs. Apparently, the publisher serializer configuration is causing this issue, although the message is as expected.
Using the JsonProperty feature could isolate the problem, however, it does not reflect what was expected.
Versions
.NET: 6.0;
MassTRansit: 7.3.0;
Newtonsoft: 13.0.1
Type specified in JSON 'Messages.Models+CreditCard, Messages'
is not compatible with 'GreenPipes.DynamicInternal.Models\+Messages.Models\+IPaymentMethod'
Resource:
_bus.CreateRequestClient<TMessage>().GetResponse<TResponse>(message, cancellationToken);
Publisher serializer configuration:
bus.ConfigureJsonSerializer(settings =>
{
settings.TypeNameHandling = TypeNameHandling.Objects;
return settings;
});
Message response serialization:
{
"message": {
"$type": "Messages.Services.ShoppingCarts.Responses+CartDetails, Messages",
"cartItems": [
{
"$type": "Messages.Models+Item, Messages",
"productId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"productName": "string",
"unitPrice": "10.0",
"quantity": 30,
"pictureUrl": "string"
}
],
"paymentMethods": [
{
"$type": "Messages.Models+CreditCard, Messages",
"id": "be7c40ac-1cd1-4e35-bccf-a1a2f4efecfd",
"expiration": "01/22",
"holderName": "string",
"number": "374245455400126",
"securityNumber": "string"
},
{
"$type": "Messages.Models+PayPal, Messages",
"id": "9465cf12-a322-477d-94c8-116d03a8399e",
"Password": "123",
"UserName": "string"
}
],
...
}
}
Consumer deserializer configuration:
bus.ConfigureJsonDeserializer(settings =>
{
settings.TypeNameHandling = TypeNameHandling.Objects; // or Auto, All, etc...
return settings;
});
Error:
System.Runtime.Serialization.SerializationException: A JSON serialization exception occurred while deserializing the message envelope
---> Newtonsoft.Json.JsonSerializationException: Type specified in JSON 'Messages.Models+CreditCard, Messages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
is not compatible with 'GreenPipes.DynamicInternal.Models\+Messages.Models\+IPaymentMethod, MessagesGreenPipes.DynamicInternale7ccc67139ad479db488c4fa6310335a, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
Path 'message.paymentMethods[0].$type', line 30, position 55.
JsonProperty does not work:
public record CartDetails : Response
{
[JsonProperty(TypeNameHandling = TypeNameHandling.Objects)]
public IEnumerable<Models.IPaymentMethod> PaymentMethods { get; init; }
}
{
"message": {
"cartItems": [
{
"productId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"productName": "string",
"unitPrice": "10.0",
"quantity": 30,
"pictureUrl": "string"
}
],
"paymentMethods": [
{
"id": "be7c40ac-1cd1-4e35-bccf-a1a2f4efecfd",
"expiration": "01/22",
"holderName": "string",
"number": "374245455400126",
"securityNumber": "string"
},
{
"id": "9465cf12-a322-477d-94c8-116d03a8399e",
"Password": "123",
"UserName": "string"
}
],
...
}
}
Response
public record CartDetails : Response
{
// [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)]
public IEnumerable<Models.IPaymentMethod> PaymentMethods { get; init; }
public IEnumerable<Models.Item> CartItems { get; init; }
public Guid UserId { get; init; }
public decimal Total { get; init; }
public Guid Id { get; init; }
public bool IsDeleted { get; init; }
}
Types:
public interface IPaymentMethod
{
Guid Id { get; }
decimal Amount { get; }
}
public record CreditCard : IPaymentMethod
{
public Guid Id { get; init; }
public decimal Amount { get; init; }
[property: JsonConverter(typeof(ExpirationDateOnlyJsonConverter))]
public DateOnly Expiration { get; init; }
public string HolderName { get; init; }
public string Number { get; init; }
public string SecurityNumber { get; init; }
}
public record PayPal : IPaymentMethod
{
public Guid Id { get; init; }
public decimal Amount { get; init; }
public string UserName { get; init; }
public string Password { get; init; }
}
Thanks Wiktor Zychla, the issue led me to Nkot's workaround, which served me very well:
TypeNameHandlingConverter:
internal class TypeNameHandlingConverter : JsonConverter
{
private readonly TypeNameHandling _typeNameHandling;
public TypeNameHandlingConverter(TypeNameHandling typeNameHandling)
{
_typeNameHandling = typeNameHandling;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> new JsonSerializer { TypeNameHandling = _typeNameHandling }.Serialize(writer, value);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> new JsonSerializer { TypeNameHandling = _typeNameHandling }.Deserialize(reader, objectType);
public override bool CanConvert(Type objectType)
=> IsMassTransitOrSystemType(objectType) is false;
private static bool IsMassTransitOrSystemType(Type objectType)
=> objectType.Assembly == typeof(IConsumer).Assembly ||
objectType.Assembly.IsDynamic ||
objectType.Assembly == typeof(object).Assembly;
}
Consumer deserializer configuration:
bus.ConfigureJsonDeserializer(settings =>
{
settings.Converters.Add(new TypeNameHandlingConverter(TypeNameHandling.Objects));
return settings;
});

Convert nested Firebase database object to C# object using Json.NET

I need to convert firebase-ish data structure to C# object using JSON.Net library.
I store my data on Firebase Database like following;
{
"PoolDatas": {
"-LGGJGTAv_DPtzkmjIbl": {
"CoinType": 2,
"PoolType": 4,
"Alias": "First Alias",
"Address": "0xAE12EF212",
"Alarms": {
"-LGsdsdv_DPtzkmjIbl": {
"Threshold": {
"Type": 2,
"Val": 100
},
"AlarmType": 3
},
"-LBAsdsdv_DPtzkmjIbl": {
"Threshold": {
"Type": 1,
"Val": 1
},
"AlarmType": 2
}
}
},
"-LEAJGTAv_DPtzkmjIbl": {
"CoinType": 1,
"PoolType": 1,
"Alias": "Second Alias",
"Address": "0xAeeeEF212",
"Alarms": {
"-LGsdsdv_DPtzkmjIbl": {
"Threshold": {
"Type": 10,
"Val": 120
},
"AlarmType": 1
},
"-LBAsdsdv_DPtzkmjIbl": {
"Threshold": {
"Type": 1,
"Val": 250
},
"AlarmType": 2
}
}
}
}
}
All list objects have firebase generated ID. I cannot map this data to C# class because firebase IDs don't comply with the list structure.
Please see my model in C# side;
public class PoolData
{
public string FirebaseId{ get; set; }
public string Alias { get; set; }
public PoolType PoolType { get; set; } //enum
public CoinType CoinType { get; set; } //enum
public string Address { get; set; }
public List<Alarm> Alarms { get; set; }
}
public class Alarm
{
public string FirebaseId{ get; set; }
public AlarmType AlarmType{ get; set; } //enum
public Threshold Threshold { get; set; } //object
}
public class Threshold
{
public ThresholdType Type{ get; set; } //enum
public int Value { get; set; }
}
In order to be able to convert Firebase-ish json into C# object I need a json like this;
{
"PoolDatas": [
{
"FirebaseId": "-LGGJGTAv_DPtzkmjIbl",
"CoinType": 1,
"PoolType": 1,
"Alias": "First Alias",
"Alarms": [
{
"FirebaseId": "-LGsdsdv_DPtzkmjIbl",
"Threshold": {
"Type": 1,
"Val": 1
},
"AlarmType": 1
},
{
"FirebaseId": "-LBAsdsdv_DPtzkmjIbl",
"Threshold": {
"Type": 1,
"Val": 1
},
"AlarmType": 2
}
],
"Address": "0xAE12EF212"
},
{
"FirebaseId": "-LEAJGTAv_DPtzkmjIbl",
"CoinType": 1,
"PoolType": 1,
"Alias": "First Alias",
"Alarms": [
{
"FirebaseId": "-LGsdsdv_DPtzkmjIbl",
"Threshold": {
"Type": 1,
"Val": 1
},
"AlarmType": 1
},
{
"FirebaseId": "-LBAsdsdv_DPtzkmjIbl",
"Threshold": {
"Type": 1,
"Val": 1
},
"AlarmType": 2
}
],
"Address": "0xAE12EF212"
}
]
}
How can I obtain this json from the first one?
I tried several recursive processes using JObject loops but it didn't work.
Thanks in advance!
You can deserialize the JSON to a Dictionary<string, PoolData>, change each value so the key of the dictionary goes into the FirebaseId property, and then put it into an array, something like this:
class Origin
{
public Dictionary<string, PoolData> PoolDatas { get; set; }
}
class Destination
{
public PoolData[] PoolDatas { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("data.json");
var data = JsonConvert.DeserializeObject<Origin>(json);
var destination = new Destination();
destination.PoolDatas = data.PoolDatas.Select(i =>
{
i.Value.FirebaseId = i.Key;
return i.Value;
}).ToArray();
}
}
You will need to install and import the Json.Net package using Newtonsoft.Json;.
EDIT: as mentioned in the comments, this will not work for nested objects. For that scenario, maybe you could use a custom serializer, something like this:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ConsoleApp1
{
public interface IFirebaseObject
{
string FirebaseId { get; set; }
}
public class PoolData
{
public string FirebaseId { get; set; }
public string Alias { get; set; }
public string Address { get; set; }
[JsonConverter(typeof(MapToArrayConverter<Alarm>))]
public List<Alarm> Alarms { get; set; }
}
public class Alarm: IFirebaseObject
{
public string FirebaseId { get; set; }
public Threshold Threshold { get; set; } //object
}
public class Threshold
{
public int Value { get; set; }
}
class Origin
{
public Dictionary<string, PoolData> PoolDatas { get; set; }
}
class Destination
{
public PoolData[] PoolDatas { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText("data.json");
var data = JsonConvert.DeserializeObject<Origin>(json);
var destination = new Destination();
destination.PoolDatas = data.PoolDatas.Select(i =>
{
i.Value.FirebaseId = i.Key;
return i.Value;
}).ToArray();
}
}
public class MapToArrayConverter<T> : JsonConverter where T : IFirebaseObject
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject item = JObject.Load(reader);
Dictionary<string, T> value = JsonConvert.DeserializeObject<Dictionary<string, T>>(item.ToString());
// TODO also consider single values instead of lists
return value.Select(i =>
{
i.Value.FirebaseId = i.Key;
return i.Value;
}).ToList();
} else
{
return null;
}
}
public override bool CanConvert(Type objectType)
{
// TODO validate the object type
return true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// TODO implement the reverse method to also write
throw new NotImplementedException();
}
}
}
But as you can see the solution starts to get somewhat complex. Unless you need to do this for many types, maybe manually converting would be less time consuming and simpler to maintain.

JsonConverter byte[]

I have the following code:
//Models
public class Home{
public Guid HomeId { get; set; }
public Guid UserId { get; set; }
public string Name { get; set; }
public byte[] Description1 { get; set; }
public virtual User User { get; set; }
}
public class User
{
public Guid UserId { get; set; }
public string Email { get; set; }
public virtual Perfil Perfil { get; set; }
}
public class Perfil
{
public Guid UserId { get; private set; }
public string Name { get; private set; }
public byte[] Description2 { get; set; }
}
// JsonConverter
public class ByteArrayConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(byte[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var m = Convert.FromBase64String((string)reader.Value);
return m;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
byte[] bytes = (byte[])value;
writer.WriteValue(Convert.ToBase64String(bytes));
}
}
// Serialize (Calls the WriteJson function of the ByteArrayConverter, OK)
var serialized = JsonConvert.SerializeObject(obj, settings);
{
"HomeId": "2925362b",
"UserId": "9ea43c30",
"Name": "Name 1",
"Description1": "VABlAHMAdABlAA==", //===> Converts to Base64 (OK)
"User": {
"UserId": "9ea43c30",
"Email": "aaaa#aaaa.com",
"Perfil": {
"UserId": "9ea43c30",
"Name": "Name 2",
"Description2": "dABlAHMAdABlAA==", //===> Converts to Base64 (OK)
}
}
}
// Deserialize
var deserialized = JsonConvert.DeserializeObject<T>(serialized, settings); // T is class Home
{
"HomeId": "2925362b",
"UserId": "9ea43c30",
"Name": "Name 1",
"Description1": "VABlAHMAdABlAA==", //===> Don't Convert from Base64, (**Does not call the ReadJson function of ByteArrayConverter**)
"User": {
"UserId": "9ea43c30",
"Email": "aaaa#aaaa.com",
"Perfil": {
"UserId": "9ea43c30",
"Name": "Name 2",
"Description2": "dABlAHMAdABlAA==", //===> Convert from Base64 (OK)
}
}
}
Settings
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented
};
settings.Converters.Add(new ByteArrayConverter());
The Description1 property does not get into the ReadJson function of the ByteArrayConverter class, so it does not convert back the byte [], generating another invalid [] byte, ....
Any idea of this problem?
Old question, but need clarification
when I do not use as above, it serializes a byte[] type with the information: $ type: "System.Byte [], mscorlib" $ Value: "VABlAHMAdABlAA ==", but when I go deserialize it shows an error: Unexpected character encountered while parsing value
To avoid the above error in deserialization, use the following json setting in deserialization.
TypeNameHandling = TypeNameHandling.None
TypeNameHandling setting include type information when serializing JSON and read type information so that the create types are created when deserializing JSON
For more details read: TypeNameHandling Enumeration
The serialization of byte[] is Base-64 string, and when deserialized it generate byte[] again.
You need not ByteArrayConverter as given in the comments of #Brian Rogers and #dbc
You can find a complete working example using your code with modification online

Newtonsoft JSON Deserialize AND jsonfreeze

I have a two simple PHP class
class Order{
public $orderNo;
public $lines = array();
public $paid = false;
public function addLine(OrderLine $line) {
$this->lines[] = $line;
}
public function setPaid($paid = true) {
$this->paid = true;
}
}
class OrderLine{
public function __construct($item, $amount){
$this->item = $item;
$this->amount = $amount;
}
public $item;
public $amount;
public $options;
}
Serialize object uses https://github.com/mindplay-dk/jsonfreeze
...
$json = new JsonSerializer;
$data = $json->serialize($order);
Have output:
{
"#type": "Order",
"orderNo": 123,
"lines": [{
"#type": "OrderLine",
"item": "milk \"fuzz\"",
"amount": 3,
"options": null
},{
"#type": "OrderLine",
"item": "cookies",
"amount": 7,
"options": {
"#type": "#hash",
"flavor": "chocolate",
"weight": "1\/2 lb"
}
}],
"paid": true
}
Send the string XMLRPC in VB.NET
As using Newtonsoft JSON get a live object?
As well as how to create a compatible format by analogy with the json string of living VB.net OR C# object?
Here's something you could start with. You create some classes with properties which represent the JSON Format (untested code, just as idea):
public class MyData
{
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("#orderNo")]
public int OrderNo { get; set;
[JsonProperty("paid")]
public bool Paid { get; set; }
[JsonProperty("lines")]
public List<MyDataLine> Lines { get; set; }
}
public class MyDataLines
{
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("options")]
public MyDataLinesOptions Options { get; set; }
// ... more
}
public class MyDataLinesOptions
{
// ... more
}
Then you can serialize and deserialize the the data like this:
string json = "the json data you received";
MyData myData = JsonConvert.DeserializeObject<MyData>(json);
// ...
json = JsonConvert.SerializeObject(myData);
"#type": "Order"
and
"#type": "OrderLine",
this is not a property, this is an indication of the type of the object

Categories