Using JSON.net control serialization of final output - c#

using the code...
[Test]
public void test()
{
var entity = new Foo();
var json = Newtonsoft.Json.JsonConvert.SerializeObject(entity);
}
against the following trivial class structure...
public class Foo
{
public Foo() { FooDate = new DateTimeWrapper(); }
public DateTimeWrapper FooDate { get; set; }
}
public class DateTimeWrapper
{
public DateTimeWrapper() { DateTime = DateTime.Now; }
public DateTime DateTime { get; set; }
}
...sets the json variable to...
{"FooDate":{"DateTime":"2013-08-30T13:36:15.4862093-05:00"}}
The JSON I want to return is...
{"FooDate":"2013-08-30T13:36:15.4862093-05:00"}
without the embedded DateTime part. How can JSON.net be used to serialize to this custom JSON and subsequently deserialize the above string to the original object?
EDIT
I am aware the object structure can be simplified to produce the desired output. However, I want to produce the output with the given object structure. This code is boiled down to highlight the problem. I didn't put all the code nor a lengthy explanation of it b/c it isn't pertinent to the question.

As I said in comments, It can easily be done by creating a custom JsonConverter
var entity = new Foo();
var json = JsonConvert.SerializeObject(entity, new DateTimeWrapperConverter());
public class DateTimeWrapperConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTimeWrapper);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//Left as an exercise to the reader :)
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var obj = value as DateTimeWrapper;
serializer.Serialize(writer, obj.DateTime);
}
}

Related

JSonConverter how to make generic deserialization

I have been able to do a custom Converter that transforms to a list of interfaces.
Here my custom converter:
public class InvoiceDetailConverter : JsonConverter {
public override bool CanConvert(Type objectType) {
//assume we can convert to anything for now
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
List<InvoiceDetail> data = serializer.Deserialize<List<InvoiceDetail>>(reader);
// now loop to make the proper list
List<IInvoiceDetail> result = new List<IInvoiceDetail>();
foreach (IInvoiceDetail d in data) {
result.Add(d);
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
//use the default serialization - it works fine
serializer.Serialize(writer, value);
}
}
What I would like is to make this generic like
public class InvoiceDetailConverter <TConcrete, TInterface> : JsonConverter {
public override bool CanConvert(Type objectType) {
//assume we can convert to anything for now
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
List<TConcrete> data = serializer.Deserialize<List<TConcrete>>(reader);
// now loop to make the proper list
List<TInterface> result = new List<TInterface>();
foreach (TInterface d in data) {
result.Add(d);
}
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
//use the default serialization - it works fine
serializer.Serialize(writer, value);
}
}
At the End in my object it will be used like this:
public class test{
[JsonConverter(typeof(InvoiceDetailConverter<InvoiceDetail, IInvoiceDetail>))]
public List<IInvoiceDetail> InvoiceDetail { get; set; }
}
Is it possible to convert like this, as the above code won't compile. I'm using .NET Core.
I believe you're almost there, just specify dependency between TConcrete and TInterface:
public class InvoiceDetailConverter<TConcrete, TInterface> : JsonConverter
where TConcrete : TInterface // <------------------------------------------ add this
{
// ..........
}
Here you can find a demo of successful deserialization using the generic converter class for the following object:
public class test
{
[JsonConverter(typeof(InvoiceDetailConverter<InvoiceDetail, IInvoiceDetail>))]
public List<IInvoiceDetail> InvoiceDetail { get; set; }
[JsonConverter(typeof(InvoiceDetailConverter<VatDetail, IVatDetail>))]
public List<IVatDetail> VatDetail { get; set; }
}

Deserialization fails when converter property is missing

Im using restsharp 105.2.3 and I have a model class's property (CalcDate) bound to a DateTime type but I am using a converter to parse the incoming rest response to build the timestamp. This works well, unless the svc doesn't return "calcDate"; When it's missing, the model fails to deserialized. The error that i get from IRestResponse.ErrorMessage is:
"Value to add was out of range.\r\nParameter name: value"
Interestingly if I use the raw json (with the missing calcDate) and try to construct it using jsonConvert, then it works as expected and the model is built with nulled calcDate.
> Newtonsoft.Json.JsonConvert.DeserializeObject<MyModel>(json) // works
Code:
public class MyModel {
[JsonProperty("id")]
public int Id { get; set; }
[JsonConverter(typeof(TimestampConverter))]
[JsonProperty("calcDate")]
public DateTime? CalcDate { get; set; }
}
public class TimestampConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jvalue = JValue.Load(reader);
if (jvalue.Type == JTokenType.String)
{
long val = 0;
if (long.TryParse(jvalue.ToString(), out val)) {
DateTimeOffset dto = DateTimeOffset.FromUnixTimeMilliseconds(Convert.ToInt64(val));
return dto.DateTime;
}
}
return DateTime.MinValue;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Question: How can i make restsharp use jsonConvert to deserialize the json?

Object cannot by deserialized, because 'Collection was of a fixed size.'

I have easy example of my real code. I need serialize to JSON and deserialize back object of class TestClass, which is derived from Letters. Both classes have constructor with parameter.
public class TestClass : Letters
{
public string[] Names { get; private set; }
public TestClass(string[] names)
: base(names)
// : base(new [] { "A", "B", })
// : base(names.Select(a => a.Substring(0, 1)).ToArray())
{
Names = names;
}
}
public abstract class Letters
{
public string[] FirstLetters { get; private set; }
protected Letters(string[] letters)
{
FirstLetters = letters;
}
}
Object of TestClass is serialized to valid JSON, but when I try it deserialize back to object, NotSupportedException is throw with message Collection was of a fixed size.
Here is my test
[Fact]
public void JsonNamesTest()
{
var expected = new TestClass(new [] { "Alex", "Peter", "John", });
var serialized = JsonConvert.SerializeObject(expected);
Console.WriteLine(serialized);
Assert.False(string.IsNullOrWhiteSpace(serialized));
var actual = JsonConvert.DeserializeObject<TestClass>(serialized);
AssertEx.PrimitivePropertiesEqual(expected, actual);
}
Json.Net needs all classes to have a parameterless constructor in order to deserialize them, otherwise it doesn't know how to call the constructor. One way to get around this without changing your classes is to make a custom JsonConverter that will create the object instance from the JSON. For example:
class TestClassConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(TestClass) == objectType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
string[] names = jo["Names"].ToObject<string[]>();
return new TestClass(names);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
Then, deserialize your class like this and it should work:
var actual = JsonConvert.DeserializeObject<TestClass>(serialized, new TestClassConverter());
Thank, it works! I modified your code for more general usage in my example.
I suppose
is only one public constructor
serialized parameters have same name as constructor parameters (ignore case)
public class ParametersContructorConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Letters).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jo = JObject.Load(reader);
var contructor = objectType.GetConstructors().FirstOrDefault();
if (contructor == null)
{
return serializer.Deserialize(reader);
}
var parameters = contructor.GetParameters();
var values = parameters.Select(p => jo.GetValue(p.Name, StringComparison.InvariantCultureIgnoreCase).ToObject(p.ParameterType)).ToArray();
return contructor.Invoke(values);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}

Serialize property that throws NotImplementedException

Is there any way to serialize objects of the following class and somehow ignore the exception being thrown?
public class HardToSerialize
{
public string IAmNotTheProblem { get; set; }
public string ButIAm { get { throw new NotImplementedException(); } }
}
Not suprisingly Newtonsoft throws an error when it tries to serialize the value of the ButIAm property.
I don't have access to the class so I can't decorate it with any attributes.
Clarification: I want this to work for any object that has properties that throws a NotImplementedException. The HardToSerialize class is just one example.
I found a solution that worked for me. Is there any major problems doing it like this?
var settings = new JsonSerializerSettings();
settings.Error += (o, args) => {
if(args.ErrorContext.Error.InnerException is NotImplementedException)
args.ErrorContext.Handled = true;
};
var s = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented, settings);
I would go for a surrogate class and a custom JsonConverter :
public class HardToSerializeSurrogate
{
public string IAmNotTheProblem { get; set; }
public string ButIAm { get; set; }
}
public class HardToSerializeConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(HardToSerialize);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var item = (HardToSerialize)value;
// fill the surrogate with the values of the original object
var surrogate = new HardToSerializeSurrogate();
surrogate.IAmNotTheProblem = item.IAmNotTheProblem;
serializer.Serialize(writer, surrogate);
}
}
Usage:
static void Main(string[] args)
{
var hardToSerialize = new HardToSerialize() { IAmNotTheProblem = "Foo" };
var s = JsonConvert.SerializeObject(hardToSerialize,
new HardToSerializeConverter());
}
Of course implementing a custom JsonConverter is really worth if you must serialize a list of HardToSerialize objects, or an object that contains this type.
On the other hand, if you just want to serialize one HardToSerialize object each time, just create a surrogate copy of the object and serialize that without implementing a custom JsonConverter.
A possible workaround would be to create another object from EasyToSerialize and then serialize it.
[Serializable]
public class EasyToSerialize
{
public string IAmNotTheProblem { get; set; }
// other serializable properties
}
HardToSerialize x = ...;
var foo2 = new EasyToSerialize {
IAmNotTheProblem = x.IAmNotTheProblem
// other properties here
};

Send javascript function over json using Json.NET lib

I am attempting to send a javascript function over json in .Net and I am having trouble serializing the object.
The javascript library Highcharts uses the following function on their json object to customize the chart tooltip.
tooltip: {
formatter: function() {
var s;
if (this.point.name) { // the pie chart
s = ''+
this.point.name +': '+ this.y +' fruits';
} else {
s = ''+
this.x +': '+ this.y;
}
return s;
}
},
I am attempting to use the popular Json.NET library using an anonymous type to create such object but all my efforts serialize to a string in the end. Any help is appreciated. Thanks!
I like the answer from ObOzOne, but it can be a little simpler by just using the WriteRawValue. For example:
public class FunctionSerializer : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(string));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
string valueAsString = Convert.ToString(value);
if (!string.IsNullOrWhiteSpace(valueAsString))
writer.WriteRawValue(valueAsString);
}
}
And then on your property that you want to serialize:
[JsonConverter(typeof(FunctionSerializer))]
public string HideExpression { get; set; }
JSON as the name implies, is only an object notation and suitable for transferring state as object.
If you need to send JavaScript code itself, you can use a JavaScriptResult in ASP NET MVC if you are using it.
If you are using ASP NET Web Forms, have an ASPX file which writes the JavaScript straight to the response. Make sure you change the ContentType to text/javascript.
As of Newtonsoft.Json 12.0.1 (11/27/2018), the standard solution for this is to use JRaw type.
public class JavaScriptSettings
{
public JRaw OnLoadFunction { get; set; }
public JRaw OnUnloadFunction { get; set; }
}
JavaScriptSettings settings = new JavaScriptSettings
{
OnLoadFunction = new JRaw("OnLoad"),
OnUnloadFunction = new JRaw("function(e) { alert(e); }")
};
string json = JsonConvert.SerializeObject(settings, Formatting.Indented);
Console.WriteLine(json);
// {
// "OnLoadFunction": OnLoad,
// "OnUnloadFunction": function(e) { alert(e); }
// }
Source
A bit of a hack but I solved it this way:
string linkUrl = "http://www.google.com";
dynamic result = new ExpandoObject();
result.render = "FUNCfunction (data) { return '' + data + ''; }FUNC";
var json = Newtonsoft.Json.JsonConvert.SerializeObject(result).Replace("\"FUNC", "").Replace("FUNC\"", "")
By surrounding my function with the FUNC placeholders and then replacing "FUNC and FUNC" with emtpy string in the generated json I get the function in my json object.
I was inspired by the example above by generic methods :
public class FunctionConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(String));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, String.Concat("<Function>", value, "</Function>"));
}
}
public static class JsonObjectExtensions
{
public static String CleanJson(this String s)
{
return s.Replace("\"<Function>", "").Replace("</Function>\"", "");
}
}
public partial class JsonObject
{
public String ToJson()
{
return JsonConvert.SerializeObject(this).CleanJson();
}
}
And the model data :
public class ConfigModel : JsonObject
{
[JsonProperty("altFormat", NullValueHandling = NullValueHandling.Ignore)]
public String altFormat { get; set; }
[JsonProperty("onClose", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(FunctionConverter))]
public String onClose { get; set; }
}

Categories