class for this JSON - c#

I am hitting an API that returns some JSON as follows:
{"stats":{"X":{"Name":"X","Found":"Yes"}},"response":"OK","runtimeMs":798}
I would like to generate C# classes for it and I used json2sharp, it generated classes such as root object which i modified as follows:
public class RootObject
{
public Stats stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
public class Stats
{
public string name { get; set; }
}
public class Variant
{
public string name { get; set; }
public string Found { get; set; }
}
The issue i am facing is that in the class Stats I have used name since the json will reply with any name such as X or Y or Z.
I am able to deserialise the JSON into the root object but cannot get any data into the stats class.
JsonConvert.DeserializeObject<RootObject>(response.Content);
Any ideas why i might be doing incorrectly?

Your problem is similar to this How can I parse a JSON string that would cause illegal C# identifiers?
So, your model should be
public class Variant
{
public string Name { get; set; }
public string Found { get; set; }
}
public class RootObject
{
public Dictionary<string, Variant> stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
EDIT
#evanmcdonnal if use a dictionary as shown in the EZI's answer or an object with fields named X, Y, and Z you have to perform nullity or keyexists checks all over the place in order to safely use the object.
I don't think this simple linq is hard to write
rootObj.stats.Values.Where(....);
or
rootObj.stats.Keys.Select(....);

That is happening because json.NET is looking for a property name in your class which matches the field name in the json. Since name does not resemble anything in the json it finds nothing.
There are a couple of options for how to work around this. You can use an annotation to say what the json field you want to put there is, or you can change the name of the property. However, from you post it sounds like you're saying there could be an object called X or an object called Y in the json, neither of those options will make that deserialize correctly in all cases. I'll edit with some ideas for how you may want to handle that.
Based on OP's comment, here's what you're looking for;
public class RootObject
{
public Stats stats { get; set; }
public string response { get; set; }
public int runtimeMs { get; set; }
}
public class Stats
{
public Varient X { get; set; }
public Varient Y { get; set; }
public Varient Z { get; set; }
}
public class Variant
{
public string name { get; set; }
public string Found { get; set; }
}
In other places in your code you just have to have two code paths or do a conversion to avoid doing nullity checks everywhere.
if (myInstance.X != null)
// it was X that was in the json
else if (myInstace.Y != null)
// it was Y
else
// not sure what happened, perhaps neither X nor Y were present.
Now the other option is to make this just an intermediary then you define another type that just has one property named name and you give it a constructor that takes a RootObject and assigns whichever value isn't null to it's name property or whatever you want to call it. I would probably do something like this myself because if use a dictionary as shown in the EZI's answer or an object with fields named X, Y, and Z you have to perform nullity or keyexists checks all over the place in order to safely use the object.

Related

Send a limited/reduced class to frontend

What I want
I want to send a limited/reduced class/object to frontend (as JSON). I use .NET Core 5.
What I have
I have a model class like this:
namespace Tasks.Models
{
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
+++ many more properties
}
}
Now depending on the which controller that calls this model I want to have different "kind" of models. So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
I tried setting up a method that "initialized the fields I wanted, but that also returned all properties
public static Responses FileResponse()
{
var response = new Responses()
{
Id = new Guid(),
Name = "",
Type = "File",
};
return response;
}
Now, when I call the Resources class or this method I get all properties, and returning it to the view presents all properties, but mostly as null, because I only set the three fields in the method.
What is the recommended way of solving this?
If you want to remove the field if it's null instead of showing in json with null value.
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Url { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
}
PS: Fiddle https://dotnetfiddle.net/hiMAci
It is just limiting the Resource class I am not able to do
Yep, side effect of C# being strongly typed, with object X definitely having properties Y and Z. You need differently shaped objects - either full on classes or records - that name the reduced set of properties because the serializer is going to look a tthe object and ser every property it can find.
You could make a new class for every variation - quick and easy with records, and easy to pass around inside your C#:
public record FileThing(string Id, string Type, string Name);
//make a new one and return it
new FileThing(someResources.Id, someResources.Type, someResources.Name);
Or can consider using an anonymous type if you're literally looking to put a few properties into some json, down a socket to a consuming front end (I can't quite decide what you mean by "view" - it doesn't seem to be an MVC View) that only cares about a few props out of many
So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
public ActionResult SomeControllerMethod(){
if(isFile)
return Ok(new { someResources.Id, someResources.Type, someResources.Name });
else if(isUrl)
return Ok(new { someResources.Id, someResources.Url, someResources.Name });
}
Anonymous types are a bit harder to work with because the compiler writes the class for you, so it's tricky to do things like declare return types from methods if the method is returning an AT.. But if you're using it as some fill-in all within one method, such as a "make this and serialize it", they work well..
I think your approach is not the right one here. I tend to follow more general OO guidelines in this situation (note, some consider these a bit dated, and other solutions exist. But they are still commonly used)
You write against an interface. So let's see what you want... A guid, type and name. All other deatils aren't important.
public interface IResourceDetails
{
public Guid Id { get; }
public string Name { get; }
public string Type { get; }
}
And you can have multiple of these interfaces.
You could then implement the interfaces per type. But I would probably combine them in a base class
public abstract class ResourceBase : IResourceDetails
{
public Guid Id { get; } = new ();
public string Name { get; init; }
public string Type { get; }
public ResourceBase(string type)
{
Type = type;
}
}
Each resource type would have it's own implementation
public class FileResource : ResourceBase
{
public FileResource() : base("File") { }
// File-specific properties.
public string Description { get; init; }
public DateTime? Createdon { get; init; }
}
The response method then could be made generic and look like this
public static IActionResult Response(IResourceDetails resource)
{
return Ok(new
{
resource.Id,
resource.Name,
resource.Type,
});
}

Creating class members during run time - C#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!
You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

Umbraco - Map strong-typed object to IPublishedContent

I'm 'conjoining' Umbraco with another web application and using Elasticsearch to store data from both applications in one index. So far, I've been only searching through Umbraco content, getting its ID and then using UmbracoHelper to retrieve the proper IPublishedContent item, which then I mapped to a strong-typed object [Class1], which inherits from PublishedContentModel abstract class, using Ditto.
Currently in the Umbraco application, the Class1 object is being serialized with JSON.Net and output and I can't change the structure of it. With addition of the items coming from another, non-Umbraco application I wanted to completely omit the step of retrieving the content from Umbraco and instead hold all of the relevant data directly in the index. That way I could just create strong typed objects based on the content of the index. However, after remapping the item to it's DTO [Class1DTO], I found myself unable to map those onto the Class1.
Obviously, I cannot use Ditto anymore, as it only works when mapping from IPublishedContent and it's derivatives. I was thinking about using AutoMapper, but the problem is, I cannot instantiate my Class1, without passing IPublishedContent object (because of the need to implement the PublishedContentModel constructor).
I know I could duplicate all of my strong-typed objects without the PublishedContentModel inheritance, but it feels really wrong doing that. Is there a way to somehow fake the IPublishedContent object, so that I could use AutoMapper? Or is there any other way of achieving the same output?
Example classes below:
[JsonObject(MemberSerialization.OptIn)]
public class Class1 : PublishedContentModel
{
public Class1(IPublishedContent content)
: base(content)
{
}
[JsonProperty]
public string type { get; set; }
[JsonProperty]
public override int Id { get { return base.Id; } }
[JsonProperty]
public override string SomeData { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class Class1DTO
{
[JsonProperty]
public string type { get; set; }
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string SomeData { get; set; }
[JsonProperty]
public SomeFilter FilterForSearch { get; set; }
}
Couldn't you create your own version of the PublishedContentModel that doesn't have a reliance on IPublishedContent? Something like this:
public abstract class Base
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Path { get; set; }
public IList<Int32> PathIds
{
get
{
return !String.IsNullOrEmpty(Path) ? Path.Split(',').Select(x => Convert.ToInt32(x)).ToList() : null;
}
}
public Int32 ParentId
{
get
{
if (PathIds.HasItemsAndNotNull() && PathIds.Count >= 2)
return PathIds[PathIds.Count - 2];
return -1;
}
}
public Int32 Level { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public String WriterName { get; set; }
public String DocumentTypeAlias { get; set; }
}
Unless you have a need of very specific fields that are on PublishedContentModel.

Map JSON object to c# class property

I'm getting a bunch of JSON data back from a 3rd party API like this:
returnValue = data["value"].ToObject<List<T>>();
All but one of the fields are just basic name:value pairs like this:
"Name":"Value"
I map the values I need to a class like this:
public sealed class Project
{
public string Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public DateTime ProjectDateLocal { get; set; }
public string ParentFolderName { get; set; }
public string ParentFolderId { get; set; }
//causing trouble
public Int32 ProjectTypeId { get; set; }
public string PlayerUrl
{
get
{
return "http://em.edu.edu/prj/Play/" + this.Id;
}
}
}
However, one name:value pair is complicated like this:
"CustomFieldValues":[
{
"FieldName":"ProjectTypeId","FieldDefinitionId":"37a2ffeb3bd441f6a60158458910a04d40","DataType":"Integer","Value":"100105"
}
]
I only need the FieldName(ProjectTypeId) and Value, is there a way to get just that have the class recognize that and set it in my ProjectTypeId property?
Thanks!
As #viggity stated, you can use Newtonsoft for your problem and the solution provided is good. The only thing you have to do is provide a good string json to the Deserializer.
If you want a simpler solution why don't you use data["value"].ToObject<List<Project>>() ?
Note: Assigning attributes like [JsonProperty("FieldNameFromJson")] is ussefull for mappings.
See this post for more info about how you can do this.
Use Json.net to deserialize JsonConvert.Deserialize<Project>(jsonStringContent)
Json.net will go multi levels, just add a new class and have your Project have that property.
public class CustomFieldValue
{
public string FieldName {get;set;}
public string Value {get; set;}
}
and add a list of them to your Project.
public sealed class Project
{
public string Id { get; set; }
...
public List<CustomFieldValue> CustomFieldValues { get; set; }
}
Json.net won't have any problem with it. If you don't add FieldDefinitionId, etc then Json.net will just ignore it.
http://www.newtonsoft.com/json

more json c# issues

This is a continuation of a previous question of mine. The solution worked for what I was trying to do at the time but broke a whole lot of my code. I know it was bad practice not to make sure beforehand but yeah... you live and learn.
Anyhoo, here's the Q: an easy way to serialise c# objects
What I want to know is: is there any way to get the NewtonSoft Library to handle this stuff? If yes, how? If no, suggestions?
What i'm doing is chatting to a RoR3 app using json, now I cant deserialise the response. here's a little code:
The response i'm getting from RoR looks like:
[{"directory":{"created_at":"2011-07-20T22:29:38Z","drive_info":1,"id":15,"name":"New Drive","parent":0,"size":0,"updated_at":"2011-07-20T22:29:39Z","user":1}}]
I'm trying to deserialise it into a list of Directory objects using:
public static CompositeCollection deserialise<T>(string json)
{
CompositeCollection result = new CompositeCollection();
JArray arr = JArray.Parse(json);
foreach (JObject obj in arr)
{
result.Add(JsonConvert.DeserializeObject<T>(obj.First.First.ToString()));
}
return result;
}
and the relevant part of the directory class looks like:
// [Serializable]
// [DataContract]
public class Directory
{
// [DataMember]
public int id { get; set; }
// [DataMember]
public string name { get; set; }
// [DataMember]
public int parent { get; set; }
// [DataMember]
public int drive_info { get; set; }
// [DataMember]
public int size { get; set; }
// [DataMember]
public int user { get; set; }
// [DataMember]
public string state
{
get
{
/* if (parent == 0)
return _state.identify();
Directory parental;
return parental.state;*/
if (parental != null)
return parental.state;
return _state.identify();
}
set
{
_state = StateFactory.getState(value);
}
}
//[JsonIgnore]
blah...
I can deserialise most of the time by uncommenting [Serializable] (sometimes i get the following error: Object of type 'System.Int32' cannot be converted to type 'OffloadUI.Directory'. still investigating), and I can serialise by uncomenting [DataContract] and all instances of [DataMember]. What i need is something that will work in both directions.
Thanks to Zootius I found a useful guide. Here's what i did, works like a bought one:
[JsonObject(MemberSerialization.OptIn)]
public class Directory
{
[JsonProperty]
public int id { get; set; }
[JsonProperty]
public string name { get; set; }
[JsonProperty]
public int parent { get; set; }

Categories