Is there a way to automatically initialize null child objects when serializing? - c#

I'm using json.net to serialize my responses to the client
I'm building a controller action (in mvc) that produce a json string from types of objects
so it looks something like this:
string json = JsonConvert.SerializeObject(Activator.CreateInstance(type));
my problem is that when an object has an object inside of it (complex type), the activator assign null to it and then, the Json serializer doesn't serialize it at all
for example
if my object class looks like this:
public class Phone
{
public string Name {get; set;}
public Model Model {get; set;}
}
public class Model
{
public string Name {get; set;}
public string IMEI {get; set;}
}
the json string will be:
{"Name":null, "Model":null}
so is there a way to make be:
{"Name":null, "Model":{"Name":null, "IMEI":null}}
thank you all for your answers

OK
it took me some time to write this answer (stack overflow restriction) but i've found a great way to do it with reflection and recurssion I've created this method:
public void CreateFullInstance(object obj)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach(var property in properties)
{
Type propertyType = property.PropertyType;
if(!propertyType.IsPrimitive &&
propertyType.GetConstructor(Type.EmptyTypes) != null)
{
var val = Activator.CreateInstance(propertyType);
property.SetValue(obj,val);
CreateFullInstance(val);
}
}
}
when I call it, I just pass my initial:
var phone = Activator.CreateInstance(propertyType);
CreateFullInstance(phone);
var json = JsonConvert.SerializeObject(phone);
the downside for this method is that objects with no empty constructor will be ignored. I think I can fix that but then again as I said, these are POCO models so they all have empty constructors

You need to initialize Model in the constructor of Phone object.
public class Phone
{
public Phone()
{
Model = new Model();
}
public string Name {get; set;}
public Model Model {get; set;}
}
public class Model
{
public string Name {get; set;}
public string IMEI {get; set;}
}
You can also use the Activator.CreateInstance overload by which you can pass values as parameters to the constructor of a type.

Using Activator you are creating the object of main class that's why after serializing json string contain entries for properties of the class...{"Name":null, "Model":null}
Now if you want property names of Model class properties as well in the json string, then odo something because of which your inner class get initialized...
We can achieve it in two ways
1)In constructor of Phone class initialize Model class follows.
public class Phone
{
public Phone()
{
Model = new Model();
}
public string Name {get; set;}
public Model Model {get; set;}
}
2)
MyClassObject obj = (MyClassObject)Activator.CreateInstance(type);
obj.Model=new Model();
hope it helped

Related

How can I capture included property names in a JSON web api request with asp.net core?

I am building an asp.net core web api and I need to keep track of properties that were actually included in a JSON body, since .NET doesnt have the concept of undefined as in javascript, just null.
I created an interface which all of my models implement which is just a string array called IncludedProperties:
string[] IncludedProperties {get; set;}
I might have models which have more of these models nested inside. Any time I am deserializing one of these models, I want it to populate this list of IncludedProperties.
For example, in my controller:
public async Task<ActionResult> PatchModel([FromRoute]Guid id, [FromBody] RootModel model) { ... }
And classes are is defined as:
public class RootModel : IIncludedProperties
{
public string Name { get; set;}
public string Description {get; set;}
public NestedModel SubEntity { get; set;}
public string[] IncludedProperties {get; set;}
}
public class NestedModel : IIncludedProperties
{
public string Name {get; set;}
public decimal Value {get; set;}
public string[] IncludedProperties {get; set;}
}
If the JSON body is as follows:
{
"Name": "New Entity 01",
"SubEntity": {
"Name": "Child Entity 01",
"Value": 0.5
}
}
The included properties for the root would be [ "Name", "SubEntity"] and the included properties for the nested model would be [ "Name", "Value" ].
I am going through the documentation from Microsoft on custom converters for JSON, but it seems I will need to rewrite the entire json converter just to add in a bit of extra functionality. Is there any way I could "plug in" to the existing converter, just to capture the included property names?
This can be solved with reflection and recursion. If you don't mind adding one more line inside each controller, you can call this function after model binding:
void PopulateIncludedProperties(IIncludedProperties obj)
{
var properties = obj.GetType().GetProperties().ToList();
obj.IncludedProperties = properties
.Where(p => p.Name != "IncludedProperties" && p.GetValue(obj) != null)
.Select(p => p.Name).ToArray();
foreach (var prop in properties)
{
var value = prop.GetValue(obj);
if (value is IIncludedProperties includedPropValue)
{
PopulateIncludedProperties(includedPropValue);
}
}
}
Please customize yourself if you want to populate IncludedProperties of an IEnumerable<IIncludedProperties>

I need to deserialize JSON string

string json = #" {""data"":[{""Name"":""Yaj"",""Number"":""null"",""Name"":""null"",""PhotoUrl"":""http://worldforme.com/rfr/fr"",""date"":""1994-06-14 00:00:00.000"",""ID"":""178"",""ssid"":""1"",""InOut"":""Incoming"",""Intime"":""null"",""OutTime"":""null"",""Por"":""null""}]}";
var dt = JsonConvert.DeserializeObject<mainlist>(json);
But dt returns null !
Please help
Your mainlist class needs to be structured to fit the key values of the json string.
Here's an example:
public class mainlist
{
public string Name {get; set;}
public int Number {get; set;}
[JsonProperty("PhotoUrl")] //Notice how this is different from the property name?
//This is because the property needs to fit exactly with the json string.
public string PhotoURL {get; set;}
//...
}
And if you still can't get it, well then there's something wrong with your json string.

Remove an element from JsonResult in C#

I've a JsonResult object to return from a MVC method, but I need to remove one element from it before send it.
UPDATE:
I'm trying to do it without mapping it because the object is huge and very complex.
How can I achieve this?
For eg.:
public class MyClass {
public string PropertyToExpose {get; set;}
public string PropertyToNOTExpose {get; set;}
public string Otherthings {get; set;}
}
and
JsonResult result = new JsonResult();
result = Json(myObject, JsonRequestBehavior.AllowGet);
and then REMOVE PropertyToNOTExpose from the result.
UPDATE from real code:
public JsonResult GetTransaction(string id)
{
//FILL UP transaction Object
JsonResult resultado = new JsonResult();
if (CONDITION USER HAS NOT ROLE) {
var jObject = JObject.FromObject(transaction);
jObject.Remove("ValidatorTransactionId");
jObject.Remove("Validator");
jObject.Remove("WebSvcMethod");
resultado = Json(jObject, JsonRequestBehavior.AllowGet);
} else {
//etc.
}
return resultado;
}
You can create a new object, excluding the properties you don't want sent in the result...
var anonymousObj = new {
myObject.PropertyToExpose,
myObject.Otherthings
};
JsonResult result = Json(anonymousObj, JsonRequestBehavior.AllowGet);
Another options could be to convert the object to a Newtonsoft.Json.Linq.JObject and remove the property using JObject.Remove Method (String)
var jObject = JObject.FromObject(myObject);
jObject.Remove("PropertyToNOTExpose");
var json = jObject.ToString(); // Returns the indented JSON for this token.
var result = Content(json,"application/json");
You could try using the [ScriptIgnore] attribute on your property. This will cause the JavaScriptSerializer to ignore it. However, this means that it will be ignored on deserialization as well. I'm not sure whether that is an issue for your situation or not.
public class myClass
{
public string PropertyToExpose {get; set;}
[ScriptIgnore]
public string PropertyToNOTExpose {get; set;}
public string Otherthings {get; set;}
}

Mapping object with properties names and values

I have class
public class Foo
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
I want to convert the object to a generic object
{
"properties": {
"id" : "1234",
"name": "John Doe",
"email" : "john.doe#mail.com"
}
}
I want to convert the class instance to the structure where the properties would be dynamic depending on the class. Is this possible with Automapper?
Seems you want to serialize/deserialize to/from JSON. In this case you can reference to Newtonsoft.Json and use the JsonConvert.SerializeObject/JsonConvert.DeserializeObject generic method which does not depend on any specific class:
Deserializing (From String to Class Instance):
var foo = JsonConvert.DeserializeObject<Foo>(jsonString);
Serializing (From Class Instance to String):
var stringValue = JsonConvert.SerializeObject(foo)
One More Point (Mapping)
Also you may want to decorate your class with some attributes to specify the mapping:
[DataContract]
public class Foo
{
[DataMember(Name = "id")]
public string Id {get;set;}
[DataMember(Name = "name")]
public string Name {get;set;}
[DataMember(Name = "email")]
public string Email {get;set;}
}
Partially AutoMapper cannot map to dictionary or ExpandoObject, so no.
The following solution was posted before I was aware that by mapping to an ExpandoObject Automapper will simply leave you with an empty object.
The simplest solution would be this I think (assuming you want an ExpandoObject as a result):
public ExpandoObject Map<TInput>(TInput inputObject)
{
dynamic result = new ExpandoObject();
result.properties = Mapper.DynamicMap<TInput, ExpandoObject>(inputObject);
return (ExpandoObject)result;
}
As far as I know you can't delegate all members as child properties to another field using automapper, but it's simple to do this yourself. AutoMapper is completely useless here.
edit: seems that automapper struggles with ExpandoObject... Actually it seems like AutoMapper cannot do this at all, so you're left with reflection.
You would then write a reflection object that can create or populate a dictionary with the objects properties.

Order of properties get messed up when serialized by JSON.NET

In my POCO objects, I often inherit from other POCO objects. When I serialize a POCO object using JSON.NET, the order of properties gets all messed up.
Say, I have a Person class that looks like this:
public class Person
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
Then I have an Employee class that inherits from Person class:
public class Employee : Person
{
public int DepartmentId {get; set;}
public string Title {get; set;}
}
When I serialize the Employee class, my JSON object looks like this:
{
"departmentId": 123,
"title": "Manager",
"id": 1234567,
"firstName": "John",
"lastName": "Smith"
}
Two questions:
Does the order of my JSON object properties matter?
Even if the order of properties doesn't matter, how can I get the properties to be in correct order i.e. I'd like to see the Person class properties first, then the Employee class properties.
Thank you for your help.
1.) No, order doesn't matter.
2.) You can use the [JsonProperty(Order=x)] attribute to control the order:
public class Employee : Person
{
[JsonProperty(Order = 1)]
public int DepartmentId { get; set; }
[JsonProperty(Order = 1)]
public string Title { get; set; }
}
From a quick test, order defaults to 0, is sorted from low to high, and properties with the same value of Order are sorted in an arbitrary order.
Actually, since my Object was already a JObject, I Had to use the following solution:
public class SortedJObject : JObject
{
public SortedJObject(JObject other)
{
var pairs = new List<KeyValuePair<string, JToken>>();
foreach (var pair in other)
{
pairs.Add(pair);
}
pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value);
}
}
and then use it like this:
string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject));

Categories

Resources