JSON.NET deserializing derived classes does not work as expected - json

I have been searching the forums and the JSON.NET website on this issue and from what I can see I'm correctly following the guidelines but it is not working correctly.
I'm trying to deserialize object from derived classes.
Serializing works fine, but when deserializing it tries to deserialize in to the wrong type.
I'm trying to do this with Windows Phone 8 and JSON.NET 4.5.11
I have the following classes which I am serializing:
public class MyClass : ModelBase
{
public string Title { get; set; }
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public MyAction Action {get; set; }
}
public abstract class MyAction : ModelBase
{
[JsonIgnore()]
public abstract ActionType ActionType { get; }
public abstract void Execute();
}
public class SettingsAction : MyAction
{
public override ActionType ActionType
{
get { return ActionType.Settings; }
}
public SettingsType SettingsType {get; set; }
public override void Execute()
{
}
}
public class NoneAction : MyAction
{
public override ActionType ActionType
{
get { return ActionType.None; }
}
public override void Execute()
{
return;
}
}
I serialize it like this:
MyClass obj = new MyClass
{
Action = new SettingsAction()
};
string json = JsonConvert.SerializeObject(
obj,
Formatting.Indented,
new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(json);
}
And it gives me the following JSON:
{
"$type": "Model.MyClass, Model",
"Title": null,
"Action": {
"$type": "Model.SettingsAction, Model",
"SettingsType": 0
}
}
As far as I can see, this is correct, I told it to include the type information and it's correctly included.
The I deserialize it like this:
using (StreamReader r = new StreamReader(stream))
{
string json = r.ReadToEnd();
MyClass obj = JsonConvert.DeserializeObject<MyClass>(json);
}
And I get the following error:
JsonSerializationException: Error setting value to 'SettingsType' on 'Model.NoneAction'
So, although the type is contained in the JSON, on serializing it's ignoring it and of course deserializing it into a different type fails.
Does anyone have an idea why it's not taking the information into account and deserialize to the correct type?

I have found the culprit:
In one of my properties I was doing this:
public MyAction Action
{
get
{
if (_Action == null) {
Action = new NoneAction();
}
return _Action;
}
set
{
if (value != _Action)
{
_Action = value;
NotifyPropertyChanged("Action");
}
}
}
The problem is in the getter, where I create a NoneAction if the obejct is null.
Apparently Json.NET calls into the getter at some point between creating the MyClass object and setting the values of the MyAction object. When it sees that the Action-property is not null, it tries to assign the values instead of overwrite the whole object.

Related

Formatting Json for WebAPI 2 from Ember-Data

I've been struggling with this problem for a few days now and was hoping someone could help me out. I've got an ember front end which communicates with an API written in C#.
I'm making a an update (PUT) request but the model comes through with all the properties as null. The reason for this is because the API expects
{
"Type":1,
"Name":"Hello World"
}
but ember sends it in the format of
{
"Object":
{
"Type":1,
"Name":"Hello World"
}
}
I've seen solutions where you can add a custom JsonConverter onto the API Model, but this has to have it's own converter for each model. I'd like to know if someone help me with a generic one that I can apply to any model.
Here's an example of one that is specific for the profile model, I can't seem to get it to work as a generic though.
[JsonConverter(typeof(ProfileConverter))]
public class Profile
{
public string LoginId { get; set; }
public bool NewProfileOptIn { get; set; }
}
and the converter
public class ProfileConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Profile).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
Log.Information("Reading Json from ProfileSetting");
JToken token = JToken.Load(reader);
if (token["ProfileSetting"] != null)
{
JObject inner = token["ProfileSetting"].Value<JObject>();
if (CheckJsonProperty(inner, "login_id") && CheckJsonProperty(inner, "new_profile_opt_in"))
{
Profile model = new Profile
{
LoginId = inner["login_id"].ToString(),
NewProfileOptIn = (bool)inner["new_profile_opt_in"]
};
return model;
}
return null;
}
Log.Error("Invalid Model Name Passed - Expected 'ProfileSetting'");
return null;
}
private bool CheckJsonProperty(JObject objectToCheck, string expectedJsonProperty)
{
if (objectToCheck[expectedJsonProperty] != null)
{
return true;
}
Log.Error("Invalid or Missing Model Property Name Passed - Expected '" + expectedJsonProperty + "'");
return false;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
If any one has any reading resources or examples that would help, it would be much appreciated.
Thanks,
VB.Net
This Example has been coded with Json.Net.
So I'm working with Vb.net but this should work in C# the same way.
I've been able to do it without an JsonConverter as follows:
Public Class TestController
Inherits ApiController
<HttpGet>
Public Function Index() As String
Dim o As New JObject
o.Add("Data", 10)
Dim j As New JObject
j.Add("Object", o)
Dim obj = j.ToObject(Of EmberDataObject(Of TestObject))()
Return "200 - OK"
End Function
End Class
Public Class EmberDataObject(Of T)
<JsonProperty("Object")>
Public Property DataObject As T
End Class
Public Class TestObject
Public Property Data As Integer
End Class
In the above example the JsonObject with this mark up
{
"Object": {
"Data": 10
}
}
can be transformed easily. You can then access the nested Type as obj.DataObject. Through the set JsonProperty Attribute you can omit the Object key word which at least in Vb is not a legal Property name.
C#
The C# translation would be like this:
public class EmberDataObject<T>
{
[JsonProperty("Object")
public T DataObject {get; set;}
}
public class TestData
{
public int Data {get; set;}
}
And then referencing this from your Controller as follows:
public class MyApiController : ApiController
{
public IActionResult Post(EmberDataObject<TestData> emberObject)
{
/// Inner Object Available as emberObject.Object
}
}

Custom Json Converter With Constructor Arguments

I am trying to create a custom Json converter that has no default constructor and instead takes a factory that is dependency injected by Autofac. When ever I hit the object that uses this converter I get an exception that there is no no-arg constructor to use for the deserialization.
I have an objects and primitives. One of the objects is an abstract base object that I have the converter on. Since this converter is abstract I want to dependency inject a factory into the converter's ReadJson method to make the choice as to what conversion to make.
Currently the code is something like the following:
using System;
using System.Collections.Generic;
using Autofac;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Newtonsoft = Newtonsoft.Json;
public class JsonModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<SubThingFactory>()
.As<IFactory>()
.SingleInstance();
builder.Register(c => this.CreateJsonSerializerSettings(c)).SingleInstance();
builder.RegisterType<CamelCasePropertyNamesContractResolver>()
.As<IContractResolver>()
.SingleInstance();
builder.RegisterType<IsoDateTimeConverter>()
.As<Newtonsoft.JsonConverter>()
.SingleInstance();
builder.RegisterType<SubThingConverter>()
.As<Newtonsoft.JsonConverter>()
.SingleInstance();
builder.Register(c => new StringEnumConverter
{
CamelCaseText = true
})
.As<Newtonsoft.JsonConverter>()
.SingleInstance();
}
private Newtonsoft.JsonSerializerSettings CreateJsonSerializerSettings(IComponentContext context)
{
var settings = new Newtonsoft.JsonSerializerSettings
{
DefaultValueHandling = Newtonsoft.DefaultValueHandling.Ignore,
NullValueHandling = Newtonsoft.NullValueHandling.Ignore,
DateTimeZoneHandling = Newtonsoft.DateTimeZoneHandling.Utc
};
settings.ContractResolver = context.Resolve<IContractResolver>();
foreach (var converter in context.Resolve<IEnumerable<Newtonsoft.JsonConverter>>())
{
settings.Converters.Add(converter);
}
return settings;
}
}
public class ThingBeingDeserialized
{
private string Name;
private SubThing subby;
}
[Newtonsoft.JsonConverterAttribute(typeof(SubThingConverter))]
public abstract class SubThing
{
public string Name { get; set; }
public virtual string GetName()
{
//Uses reflection to get the name from a custom attribute
return this.Name;
}
}
[CustomName("A")]
public class SubThingA : SubThing
{
public int Field1 { get; set; }
}
[CustomName("B")]
public class SubThingB : SubThing
{
public string Field2 { get; set; }
}
public class SubThingConverter : Newtonsoft.JsonConverter
{
//This is Autofac injected in
private readonly IFactory factory;
public SubThingConverter(IFactory factory)
{
this.factory = factory;
}
public override object ReadJson(Newtonsoft.JsonReader reader, Type objectType, object existingValue, Newtonsoft.JsonSerializer serializer)
{
if (reader.TokenType == Newtonsoft.JsonToken.Null)
{
return null;
}
var jsonObject = JObject.Load(reader);
var type = jsonObject["type"].ToString();
return this.factory.GetSubThing(type, jsonObject);
}
public override void WriteJson(Newtonsoft.JsonWriter writer, object value, Newtonsoft.JsonSerializer serializer)
{
var type = value.GetType();
var properties = type.GetProperties();
var jObject = new JObject
{
{ "type", type.Name }
};
foreach (var prop in properties)
{
if (prop.CanRead)
{
var propVal = prop.GetValue(value, null);
if (propVal != null)
{
jObject.Add(prop.Name, JToken.FromObject(propVal, serializer));
}
}
}
jObject.WriteTo(writer);
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SubThing);
}
}
public interface IFactory
{
SubThing GetSubThing(string type, JObject restOfObj);
}
public class SubThingFactory : IFactory
{
public SubThing GetSubThing(string type, JObject restOfObj)
{
switch (type)
{
case "A":
return new SubThingA
{
Field1 = (int)(restOfObj["Field1"])
};
case "B":
return new SubThingB
{
Field2 = (string)(restOfObj["Field2"])
};
}
return null;
}
}
public class CustomNameAttribute : Attribute
{
public CustomNameAttribute(string name)
{
this.Name = name;
}
public string Name { get; set; }
}
The way I am doing the Autofac injection for the JsonSerializerSettings is by registering the settings such that the settings.Converters will pick up the enumeration of all the JsonConverters that are registered with the Autofac container and the SubThingConverter is registered such that when it is resolved it will have the IFactory resolved for it and the JsonSerializer also comes from the autofac container with these settings.
Even when I skip the dependency injection and use a new JsonSerializer with the JsonSerializerSettings with the custom converter added as
settings.Converters.Add(new SubThingConverter(new SubThingFactory()))
I still get the complaint that the SubThingConverter does not have a no arg constructor.
It seems to me that overridding the settings to explicitly use this converter should be enough. I also tried adding in the object[] params in the JsonConverter attribute on the SubThing, I couldn't get it to work and it seems to need to be a compile time array, which doesn't work with the dependency injection I need to do. Any pointers would be greatly appreciated. Thank you!

Deserialise dynamic json types

I want to deserialize json which returns different data for different parameters.
Mostly I get:
{"posts": [{ "id" : 1, "name":"post1" },{ "id" : 1, "name":"post1" }]}
But sometimes the data returned is
{"posts": false}
I want to deserialize this as the following class
public class GetReaderResponse
{
public IEnumerable<ReaderPost> posts {get; set;}
}
public class ReaderPost
{
public int id {get; set;}
public string name{get; set;}
}
I am using C#,json.net but not able to do this correctly.
Newtonsoft.Json.JsonConvert.DeserializeObject<GetReaderResponse>(dataString);
You could build a custom converter, but an easy way to handle this would be to write an error handler that detects errors with the posts property:
var settings = new JsonSerializerSettings();
settings.Error += (sender, args) =>
{
if (string.Equals("posts", args.ErrorContext.Path, StringComparison.OrdinalIgnoreCase))
{
var currentObject = args.CurrentObject as GetReaderResponse;
currentObject.posts = Enumerable.Empty<ReaderPost>();
args.ErrorContext.Handled = true;
}
};
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
This sets posts to Enumerable.Empty<ReaderPost>. This is still a little unsatisfying because if any error occurs, the property will be set. You could build a full custom converter to do this as a more complete solution.
Here's a converter that will take care of this:
public class PostsConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JToken val = JValue.ReadFrom(reader);
object result = null;
if (val.Type == JTokenType.Array)
{
result = val.ToObject<IEnumerable<ReaderPost>>();
}
else if (val.Type == JTokenType.Boolean)
{
result = Enumerable.Empty<ReaderPost>();
}
return result;
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert (Type type)
{
return typeof(IEnumerable<ReaderPost>).IsAssignableFrom(type);
}
public override bool CanRead
{
get { return true; }
}
}
Usage:
var settings = new JsonSerializerSettings();
settings.Converters = new [] { new PostsConverter() };
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
Example: https://dotnetfiddle.net/i9CXwp
By using JSON.NETs built in LINQ to JSON, you can try someting like this:
JObject jObject = JObject.Parse(json);
GetReaderResponse response = new GetReaderResponse();
if (jObject["posts"] is JArray)
response = jObject.ToObject<GetReaderResponse>();
// Do something with the response object.
where json variable is the json string you need to deserialize.
try this:
public class GetReaderResponse
{
public bool posts { get; set; }
public ReaderPost[] post { get; set; }
}
After reading #Ilija's comment I think I might have found a answer. I did not want not use string literals so I modified my class GetReaderResponse to look like below:
public class GetReaderResponse
{
public dynamic posts {get; set;}
public IEnumerable<ReaderPost> Posts
{
get
{
if (posts is bool )
return new ReaderPost[0];
return posts.ToObject<IEnumerable<ReaderPost>>();
}
}
}
Does this sound fine or does it look messy?

WCF Data Services 5.0 Workaround for returning POCOs?

I'm pretty sure it hasn't, but apologies if this question has already been asked. And additional apologies if this is just flat out a dumb question but I feel like I'm either completely missing something or have the right idea and just need some backup for my own sanity.
I've been implementing WCF Data Services 5.0 in our application and am having no issues with read operations returning entity objects.
Unfortunately there is that nasty limitation when it comes to service operations that they can only return primitive types (See MSDN). It's very annoying given that it has no problems with the entity objects.
I know that one workaround is to create a "dummy" complex type since WCFDS will recognize that but I don't want to just throw random POCOs into my data model that aren't actually in the database.
So the solution that occurred to me was to create an extension method for my objects that can serialize them into JSON strings to be returned by the service. My question is; are there any compelling arguments why I shouldn't do this or can anyone suggest any better alternatives?
Edit: Additional information to clarify my current issues
I created a very simple example of what I'm doing that originally raised this question. My service class follows first:
[JsonpSupportBehavior]
public partial class SchedulingService : DataService<ChronosDataContext>, ISchedulingService
{
public static void InitializeService(DataServiceConfiguration config)
{
#if DEBUG
config.UseVerboseErrors = true;
#endif
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.SetServiceOperationAccessRule(
"TestService",
ServiceOperationRights.All);
}
[WebGet]
public SchedulingResult TestService(
string testParam1,
string testParam2)
{
// NOTE: I never use the params, they're just there for this example.
SchedulingResult result = SchedulingResult.Empty;
result.Status = OperationStatus.Success;
result.ResponseID = Guid.NewGuid();
result.AffectedIDs = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7 });
result.RecordsAffected = 10;
return result;
}
}
Attempting to access this service using my browser, I get the following request error:
The server encountered an error processing the request. The exception message is
'Unable to load metadata for return type
'Chronos.Services.SchedulingResult' of method
'Chronos.Services.SchedulingResult TestService(System.String, System.String)'.'.
See server logs for more details.
The exception stack trace is:
at System.Data.Services.Providers.BaseServiceProvider.AddServiceOperation(MethodInfo method, String protocolMethod)
at System.Data.Services.Providers.BaseServiceProvider.AddOperationsFromType(Type type)
at System.Data.Services.Providers.BaseServiceProvider.LoadMetadata()
at System.Data.Services.DataService`1.CreateMetadataAndQueryProviders(IDataServiceMetadataProvider& metadataProviderInstance, IDataServiceQueryProvider& queryProviderInstance, BaseServiceProvider& builtInProvider, Object& dataSourceInstance)
at System.Data.Services.DataService`1.CreateProvider()
at System.Data.Services.DataService`1.HandleRequest()
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
Below are the classes that make up the SchedulingResult that I'm trying to return:
public class SchedulingResult : ServiceInvocationResponse
{
public SchedulingResult()
: base()
{
this.Payload = new object[]
{
new List<int>(),
new List<int>()
};
}
public List<int> AffectedIDs
{
get { return (List<int>)Payload[0]; }
set { Payload[0] = value; }
}
public List<int> FailedIDs
{
get { return (List<int>)Payload[1]; }
set { Payload[1] = value; }
}
public static SchedulingResult Empty
{
get { return new SchedulingResult(); }
}
}
public class ServiceInvocationResponse : AbstractJsonObject<ServiceInvocationResponse>
{
public ServiceInvocationResponse()
{
this.Status = OperationStatus.Unknown;
this.Severity = ErrorSeverity.None;
}
public virtual int RecordsAffected { get; set; }
public virtual Exception ErrorObject { get; set; }
internal virtual object[] Payload { get; set; }
}
public abstract class AbstractJsonObject<TBaseType>
{
public virtual object Deserialize(string source)
{
return JsonConvert.DeserializeObject(source);
}
public virtual T Deserialize<T>(string source)
{
return JsonConvert.DeserializeObject<T>(source);
}
public string Serialize()
{
return JsonConvert.SerializeObject(
this, Formatting.Indented);
}
public override string ToString()
{
return this.Serialize();
}
public static TBaseType FromString(string json)
{
return JsonConvert.DeserializeObject<TBaseType>(json);
}
}
It is possible to return one or many primitive, complex, or entity types from a service operation.
A primitive type is what you'd expect: string, int, bool, etc.
A complex type is a class that doesn't have a unique key (a property named ID or the [DataServiceKey("<yourkeyhere>")] attribute)
An entity type is a class that does have a unique key
For instance:
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Scratch.Web
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ScratchService : DataService<ScratchContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
[WebGet]
public string GetPrimitive()
{
return "Success";
}
[WebGet]
public IQueryable<string> GetPrimitives()
{
return new[] { "Success", "Hello World" }.AsQueryable();
}
[WebGet]
public ComplexType GetComplexType()
{
return new ComplexType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<ComplexType> GetComplexTypes()
{
return new[] {
new ComplexType { Property1 = "Success", Property2 = "Hello World" },
new ComplexType { Property1 = "Success", Property2 = "Hello World" }
}.AsQueryable();
}
[WebGet]
public EntityType GetEntityType()
{
return new EntityType { Property1 = "Success", Property2 = "Hello World" };
}
[WebGet]
public IQueryable<EntityType> GetEntityTypes()
{
return new[] {
new EntityType { Property1 = "Success1", Property2 = "Hello World" },
new EntityType { Property1 = "Success2", Property2 = "Hello World" }
}.AsQueryable();
}
}
public class ScratchContext { }
public class ComplexType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
[DataServiceKey("Property1")]
public class EntityType
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
}
Perhaps you're running into some other problem?

JSON object setting to default /null value [duplicate]

I'm using Json.NET for a project I'm working on.
From an external API, I am receiving JSON with properties that are objects, but when they are empty 'false' is passed.
For example:
data: {
supplier: {
id: 15,
name: 'TheOne'
}
}
Could also be:
data: {
supplier: false
}
How should I define the supplier property so that the supplier will be deserialized to a Supplier object or null.
Right now I have:
public class Data {
[JsonProperty("supplier")]
public SupplierData Supplier { get; set; }
}
public class SupplierData {
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
But now when trying to deserialize when supplier has a value of 'false' it fails.
I would like the Supplier property to be null when the JSON value is 'false'.
I hope someone knows how to do this. Thanks.
This can be solved by making a custom JsonConverter for your SupplierData class. Here is what the converter might look like:
class SupplierDataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(SupplierData));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Object)
{
return token.ToObject<SupplierData>();
}
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the Supplier property in your Data class like this:
public class Data
{
[JsonProperty("supplier")]
[JsonConverter(typeof(SupplierDataConverter))]
public SupplierData Supplier { get; set; }
}
Below is a demonstration of the converter in action. Note that the demo assumes you have some kind of containing object for the data property, since the JSON in your question can't stand on its own. I defined a class called RootObject for this purpose:
public class RootObject
{
[JsonProperty("data")]
public Data Data { get; set; }
}
The actual demo code follows:
class Program
{
static void Main(string[] args)
{
string json = #"
{
""data"":
{
""supplier"":
{
""id"": 15,
""name"": ""TheOne""
}
}
}";
Console.WriteLine("--- first run ---");
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
DumpSupplier(obj.Data.Supplier);
json = #"
{
""data"":
{
""supplier"": false
}
}";
Console.WriteLine("--- second run ---");
obj = JsonConvert.DeserializeObject<RootObject>(json);
DumpSupplier(obj.Data.Supplier);
}
static void DumpSupplier(SupplierData supplier)
{
if (supplier != null)
{
Console.WriteLine("Id: " + supplier.Id);
Console.WriteLine("Name: " + supplier.Name);
}
else
{
Console.WriteLine("(null)");
}
Console.WriteLine();
}
}
And here is the output from the above:
--- first run ---
Id: 15
Name: TheOne
--- second run ---
(null)