I'm using Json.NET to serialize validation data for data field. On the .NET side, validation data is a list of ValidationAttribute objects. However, I'd like to serialize them in a special form like this:
[
{ Type: 'Required', ErrorMessage: '{FieldName} is required' },
{ Type: 'RegularExpression', Pattern: '^\d+$', ErrorMessage: '...'
]
In an ideal solution I could simply intercept the object before serialization and, I could create a corresponding Dictionary<string, object> object to serialize instead of the original one.
Are there any solutions for this scenario?
You can implement your own JsonConverter class and convert your collection as you wish.
You just need to create you class and inherit it from JsonConverter
public class YourSerializer : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return typeof(YourClassName).IsAssignableFrom(objectType);
}
}
and then you need to decorate your class which will be serialized with the attribute (looks like it's not what you want)
[JsonConverter(typeof(YourSerializer))]
public class YourClassName
{
public string Name { get; set; }
public string Value { get; set; }
}
or, pass an instance of your serializer to Serialize methos:
string json = JsonConvert.SerializeObject(sourceObj, Formatting.Indented, new YourSerializer(typeof(yourClassName)));
Here is a few links:
http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm
http://blog.maskalik.com/asp-net/json-net-implement-custom-serialization/
Hope, it will help.
Related
Suppose I have these classes:
public class Bar
{
public Foo MyFoo { get; set; }
}
public class Foo
{
public string[] Stuff { get; set; }
}
And I have this JSON structure:
{
"MyFoo":
{
"Stuff":"those,are,my,stuff"
}
}
And I have a code path where a JObject is being converted to Bar using code like below:
myJObject.ToObject(typeof(Bar))
Now what I need to do is to supply the ToObject with a custom serializer to convert the string property Stuff into an array of string (using string.Split(...).ToArray())
I was asked not to add attributes on the client class 'Bar' so after looking around it seemed like a ContractResolver is in order but the issue is that the resolver only lets me handle direct properties of the root Type, that is Bar in my example, and I can't register a JsonConverter on a nested property.
So my question to you guys is, is this even achievable using Json.net?
Note that I need to do this not only for the Bar class but to an unlimited amount of classes with unknown structure so I can't hard-code a solution that will work for one type of class.
Based on your description, I don't see why you would need a ContractResolver. You know that the properties you want to deserialize specially will always be of type string[], so just make a converter that handles that type. Maybe something like this:
public class CsvStringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Null)
return null;
if (token.Type == JTokenType.String)
return ((string)token).Split(',');
if (token.Type == JTokenType.Array)
return token.ToObject<string[]>(serializer);
throw new JsonException("Unexpected token type: " + token.Type);
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Then, to use it with your JObject, create a new JsonSerializer instance, add the converter to it, and pass the serializer to the ToObject() method like this:
var serializer = new JsonSerializer();
serializer.Converters.Add(new CsvStringConverter());
var bar = myJObject.ToObject<Bar>(serializer);
Working demo here: https://dotnetfiddle.net/qmeBoh
I have a table with a SqlHierarchyId field type.
The default JSON serialization returns a javascript object that looks like this: {isNull: false} instead of a string like this /1/
Is there some way to set the serialization properly?
public class MyClass
{
[SerializeToString]
public SqlHierarchyId NodeId { get; set; }
}
According to the MSDN documentation, SqlHierarchyId implements both a ToString() method and a static Parse() method to facilitate converting it to a canonical string representation and back. So, assuming you are using Json.Net for serialization, you should be able to make a straightforward JsonConverter class to bridge the gap. Here is what it would look like:
public class SqlHierarchyIdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(SqlHierarchyId));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string id = (string)reader.Value;
return (id == null || id == SqlHierarchyId.Null.ToString()) ? SqlHierarchyId.Null : SqlHierarchyId.Parse(id);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
}
To use it, you can either mark the SqlHierarchyId properties in your classes with a [JsonConverter] attribute like this:
class MyClass
{
[JsonConverter(typeof(SqlHierarchyIdConverter))]
public SqlHierarchyId NodeId { get; set; }
}
Or, alternatively, you can pass an instance of the converter as a parameter to SerializeObject or DeserializeObject:
string json = JsonConvert.SerializeObject(myClass, new SqlHierarchyIdConverter());
Here is a round-trip demo: https://dotnetfiddle.net/7h7E82
I want my Guids to be serialized into a short form of Guid (as seen here). For full compatibility, I want the ShortGuid class to serialize into the short form, and not the long form.
I've tried using custom serialization, but I can't seem to make the whole object serialize into the short string, only into an object which contains the string. This is what I've tried:
[Serializable]
public class ShortGuid : ISerializable
{
public Guid Guid { get; }
protected ShortGuid(SerializationInfo info, StreamingContext context)
{
Guid = Decode(info.GetString("Guid"));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Guid", Encode(Guid));
}
}
Which works, but if I serialize it:
var guid = new ShortGuid(Guid.NewGuid());
var str = JsonConvert.Serialize(guid);
The serialized string I get looks like this:
{ Guid: "xxxxxxxxxxxxxxxxxx" }
While the serialized string I WANT is just
xxxxxxxxxxxxxxxxxx
I've turned everything around, but can't get this to work. How can this be done?
NOTE: I don't want this to work only on JsonConvert, this is only an example. I would like the class the always be serialized correctly.
this work perfectly for me:
public class GuidShortGuidConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Guid);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var shortGuid = new ShortGuid(reader.Value.ToString());
return shortGuid.Guid;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var customValue = new ShortGuid((Guid) value);
writer.WriteValue(customValue.ToString());
}
}
What you want is not about serialization but implicit casting.
Serialization works on structured key/value base depending on serialization type.
With implicit string casting
public static implicit operator string(ShortGuid shortGuid)
{
return Encode(sh.Guid);
}
You can use
var guid = new ShortGuid(Guid.NewGuid());
string str = guid;
I'm using the official Mongo C# Driver, and RestSharp to call a Rest Api with Json.NET to perform my serialization/deserialization. Say I have a Person class as follows, which I'd like to POST & GET:
public class Person
{
[JsonProperty("_id"),JsonConverter(typeof(ObjectIdConverter))]
public ObjectId Id {get;set;}
public string Name {get;set;}
}
I create a new Person object:
var person = new Person{Id = ObjectId.GenerateId(),Name='Joe Bloggs'};
POST it, and on the server I see the following which is correct:
{ _id: 52498b56904ee108c99fbe88, name: 'Joe Bloggs'}
The problem, is when I perform a GET the ObjectId I get on the client is {0000000000000...}
i.e. not the {5249.....} I'd expect. The raw response is showing the correct value, but once I deserialize I loose it.
The ObjectIdConverter code is :
public class ObjectIdConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var objectId = (ObjectId)existingValue; // at this point existingValue is {000...}
return objectId;
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof (ObjectId));
}
}
Any help would be appreciated.
You are implementing the ReadJson method of the converter incorrectly. The existingValue parameter does not give you the deserialized value read from the JSON, it gives you the existing value of the object that you will be replacing. In most cases this will be null or empty. What you need to do is use the reader to get the value from the JSON, convert it as needed, then return the converted value.
Assuming your ObjectId class has a constructor that accepts a hex string, here is how you would implement the ReadJson method:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
return new ObjectId(token.ToObject<string>());
}
I'm using JSON.Net in the trial to serialize/deserialize a not-so-well-formed JSON.
Specifically I'm trying to serialize an attribute with a js variable as value, something like this:
{ ..., mapTypeId: google.maps.MapTypeId.ROADMAP, ... }
My c# classes are
public enum MapTypeId
{
HYBRID, ROADMAP, SATELLITE, TERRAIN
}
[JsonObject]
public class MapOptions
{
...
[JsonProperty]
[JsonConverter(typeof(MapTypeConverter))]
public MapTypeId mapTypeId { get; set; }
...
}
With a custom JsonConverter I've been able to control the serialization:
public class MapTypeConverter : JsonConverter
{
...
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue("google.maps.MapTypeId." + ((MapTypeId)value).ToString());
}
...
}
And the serialization works. But when I'm trying to deserialize the string with:
JsonConvert.DeserializeObject<MapOptions>(ser);
I get the error: Unexpected character encountered while parsing value: g. Path 'mapTypeId', line 1, position 169.
In my MapTypeConverter I've also tryed to override the ReadJson method:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// no parse by now, just a try
return MapTypeId.TERRAIN;
}
without luck.
Suggestions?