RSchmitt
RSchmitt

Reputation: 45

Classes to fit a JSON format — is this possible?

I've been trying create c# classes to map to a JSON format required by a service. But failing to find the right answer.

Here is the JSON:

{
  "request": {
    "path": "1",
    "coverages": {
      "path": "2",
      "broadcastCoverage": {
        "path": "3",
        "name": "First Coverage",
        "channel": "Channel 9",
        "callSign": "DSOTM"
      },
      "internetCoverage": {
        "path": "4",
        "name": "Second Coverage",
        "url": "www.stackoverflow.com"
      },
      "thirdCoverage": {
        "path": "5",
        "name": "Third Coverage",
        "differentProperty": "Units"
      }
    }
  }
}

If I put this into a JSON to C# converter I get the following:

public class BroadcastCoverage
{
    public string path { get; set; }
    public string name { get; set; }
    public string channel { get; set; }
    public string callSign { get; set; }
}

public class InternetCoverage
{
    public string path { get; set; }
    public string name { get; set; }
    public string url { get; set; }
}

public class ThirdCoverage
{
    public string path { get; set; }
    public string name { get; set; }
    public string differentProperty { get; set; }
}

public class Coverages
{
    public string path { get; set; }
    public BroadcastCoverage broadcastCoverage { get; set; }
    public InternetCoverage internetCoverage { get; set; }
    public ThirdCoverage thirdCoverage { get; set; }
}

public class Request
{
    public string path { get; set; }
    public Coverages coverages { get; set; }
}

public class RootObject
{
    public Request request { get; set; }
}

But I need different types of Coverages (Broadcast, Internet, others) to be variable so I tried taking those out of the Coverages class and added a property:

public Dictionary<string, CoverageBase> CoverageList { get; set; }

Which will allow me to choose which coverages to include, the problem then becomes the CoverageList property name is in the JSON when it is serialized. I essentially would like a key/value (string, CoverageBase) without the property name.

Is there a way to add key value pairs without having the property name in the JSON? I've seen examples where this is done at the root object level but I haven't been able to find any example where it nested within the JSON.

If this can't be done with a simple object model what would be a recommended method to get the JSON built?

UPDATE: I like the answer that utilizes JsonSubTypes as it doesn't require much code, however I can't use a 3rd party library outside of json.net. Is there a way to accomplish this using a JsonConverter?

Upvotes: 1

Views: 335

Answers (1)

ken lacoste
ken lacoste

Reputation: 894

I think its possible as checked here, however it seems your app needs to reconstruct the json in a format where it includes the C# typings. More documentation here.

EDIT: Thanks to dbc's reference I was able to dive in to the JsonSubtypes and its pretty easy to implement.

Here's my code base structure.

[JsonConverter(typeof(JsonSubtypes))]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(BroadcastCoverage), "channel")]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(InternetCoverage), "url")]
[JsonSubtypes.KnownSubTypeWithProperty(typeof(ThirdCoverage), "differentProperty")]
public class CoverageBase
{
    public string path { get; set; }
    public string name { get; set; }
}

public class BroadcastCoverage : CoverageBase
{
    public string channel { get; set; }
    public string callSign { get; set; }
}

public class InternetCoverage : CoverageBase
{
    public string url { get; set; }
}

public class ThirdCoverage : CoverageBase
{
    public string differentProperty { get; set; }
}

public class Request
{
    public string path { get; set; }
    public List<CoverageBase> coverages { get; set; }
}

However the Json you're receiving was not quite ideally structured, so I did some reformatting just to let it to be properly parsed.

string json = "{\"request\":{\"path\":\"1\",\"coverages\":{\"path\":\"2\",\"broadcastCoverage\":{\"path\":\"3\",\"name\":\"First Coverage\",\"channel\":\"Channel 9\",\"callSign\":\"DSOTM\"},\"internetCoverage\":{\"path\":\"4\",\"name\":\"Second Coverage\",\"url\":\"www.stackoverflow.com\"},\"thirdCoverage\":{\"path\":\"5\",\"name\":\"Third Coverage\",\"differentProperty\":\"Units\"}}}}";

var jsonReq = JObject.Parse(json);
var pathVal = jsonReq["request"]["path"].Value<string>();
var coverageObjects = jsonReq["request"]["coverages"].Value<JObject>();
var filteredObjects = coverageObjects.Children().Where(x => x.Value<JProperty>().Name.EndsWith("Coverage"));
var dictionary = filteredObjects.Select(x => new KeyValuePair<string, string>(x.Value<JProperty>().Name, x.Value<JProperty>().Value.ToString()));

// reformatted Json
var newJson = "{ \"path\":\"" + pathVal + "\", \"coverages\" : [" + String.Join(",", dictionary.Select(x => x.Value).ToList()) + "]}";
Request reqC = JsonConvert.DeserializeObject<Request>(newJson);

Result

Upvotes: 2

Related Questions