Deserializing with Json.Net, deserialize a sub-object to a string / similar containing json?

I am trying to create a configuration file using Json that will contain the configuration for various types of objects.

Consider this file:

{ "cameras": [ { "type": "Some.Namespace.CameraClass", "assembly": "Some.Assembly", "configuration": { "ip": "127.0.0.1", "port": 8080 } } ] } 

At runtime, I will use the two properties “type” and “assembly” to create an object that supports a specific interface, and then I would like to load the configuration into this object.

However, at compile time, I do not know the type to which the "configuration" will be bound. I would like to save it as a json “property” and pass it to the camera object, and then let this object deserialize the json to the desired type.

As such, I would just like to “carry” the part of the configuration file containing the configuration for a specific type of camera with me in the object itself and let it deal with it, treating it as a black box while I carry it like that. The structure of this part should be preserved, since I would like to be fully faithful in creating configuration types for each camera implementation, even if necessary to add subobjects.

For this particular camera, I would configure the IP address and port, for some other camera I needed authorization data, and for some other camera it was completely different.

I would like the property containing this configuration to simply pass Json directly, still as a string.

Is it possible?

Here is a LINQPad example in which some bits are written:

 void Main() { const string configurationFile = @"[ { ""type"": ""UserQuery+Camera1"", ""configuration"": { ""id"": 10 } }, { ""type"": ""UserQuery+Camera2"", ""configuration"": { ""name"": ""The second camera"" } } ]"; var cameras = JsonConvert.DeserializeObject<Camera[]>(configurationFile); foreach (var camera in cameras) { var type = Type.GetType(camera.Type); var instance = Activator.CreateInstance(type, new object[0]) as ICamera; // instance.Configure(camera.Configuration); } } public class Camera { public string Type { get; set; } public JObject Configuration { get; set; } } public interface ICamera { void Configure(string json); } public class Camera1 : ICamera { private class Configuration { public int Id { get; set; } } public void Configure(string json) { JsonConvert.DeserializeObject<Configuration>(json).Dump(); } } public class Camera2 : ICamera { private class Configuration { public string Name { get; set; } } public void Configure(string json) { JsonConvert.DeserializeObject<Configuration>(json).Dump(); } } 

Two commented out bits, namely a property in the Camera class and a call to the Configure method, are what I would like to work with.

Is there something I can tag with this property, or is there any other type that I can select for this property that will do the job?

I know that I can make a dynamic property that a JObject will contain in it, but then each Configure method for each camera implementation must deal with a JObject , and not with a known non-dynamic type.

+6
source share
2 answers

It looks like if you are using a property of type JObject that parses but retains JSON:

 using System; using System.IO; using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class Foo { public string Name { get; set; } public int Age { get; set; } public JObject Configuration { get; set; } } public class Test { public static void Main() { var json = File.ReadAllText("test.json"); var foo = JsonConvert.DeserializeObject<Foo>(json); Console.WriteLine(foo.Configuration); } } 

Test.json:

 { "name": "Jon", "age": 10, "configuration": { "ip": "127.0.0.1", "port": 8080 } } 

Output:

 { "ip": "127.0.0.1", "port": 8080 } 

I suspect that you can deserialize directly from JObject , but you can always convert it back to string if you really want to.

+8
source

If the second level configuration is just a line:

 { "cameras": [ { "type": "Some.Namespace.CameraClass", "assembly": "Some.Assembly", "configuration": "{ \"ip\": \"127.0.0.1\", \"port\": 8080 }" } ] } 

This maps to the class:

 public class Camera { public string Type { get; set; } public string Assembly { get; set; } public string Configuration { get; set; } } 

Then you can perform second level deserialization, as already shown in your question.

0
source

Source: https://habr.com/ru/post/980893/


All Articles