C# Nested Reflection SetValue with IDictionary - c#

How do you set a value of a nested object? Here are my classes:
public class MyPage<MyData> {
public MyData Content {get;set;}
}
public class MyData {
public IDictionary<string, string> Text { get;set; }
}
I have an expression represented as a string as follows
var expressionString = "Content[\"Main\"]";
The value to set
var value = "hello world!";
The object to set
var page = new MyPage<MyData>();
Please note that Content is null and Text is null. I would like to create the while setting Text["Main"] = "hello world!";
Thanks.

Your code can work, you have to initialize everything to get it to work. To use those classes you need to do the following:
MyPage<MyData> myPage = new MyPage<MyData>();
myPage.Content = new MyData();
myPage.Content.Text = new Dictionary<string, string>();
myPage.Content.Text["foo"] = "bar";
myPage.Content.Text["fizz"] = "buzz";
foreach (var item in myPage.Content.Text)
{
Console.WriteLine(item.Key + item.Value);
}
What you probably want to do is change your classes to do the following. This way all of your objects are already initialized when you create your MyPage class. Also I don't see a need for adding to MyPage since you are limiting it to anyway.
public class MyPage
{
public MyPage()
{
Content = new MyData();
}
public MyData Content { get; set; }
}
public class MyData
{
public MyData()
{
Text = new Dictionary<string, string>();
}
public IDictionary<string, string> Text { get; private set; }
}

Related

C#: Create dynamic JSON string based on properties in a class with Newtonsoft.Json package?

I have this class for building strings:
public class WebSocketMessageBuilder
{
private readonly string _eventName;
private readonly Dictionary<string, string> _eventData;
public WebSocketMessageBuilder(string eventName)
{
_eventName = eventName;
}
public void AddData(string key, string value) => _eventData[key] = value;
public string ToJson()
{
return #"";
}
}
I would like to produce JSON strings like:
{
"event_name": "testing1",
"event_data": {
"key1": "value1",
"key2": "value2"
}
}
This string could be created like:
var wsMessage = new WebSocketMessageBuilder("testing1");
wsMessage.AddData("key1", "value2");
wsMessage.AddData("key1", "value2");
Console.WriteLine(wsMessage.ToJson());
How would I finish off the ToJson method? The documentation showed me some cool stuff, but nothing that helped me do this?
I have tried this, but it seems to just give me my class name back?
return new JObject {["event_name"] = _eventName, ["event_data"] = JsonConvert.SerializeObject(_eventData)}.ToString();
You can use the following way to serialize the object,
using Newtonsoft.Json; // This goes with the other using statements on top.
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
this is the reference to the object itself. Formatting.Indented will produce the serialized version with the proper indentation.
To make it work with the private properties, use the attribute [JsonProperty] above the private properties. See documentation here
Excerpt:
By default a type's properties are serialized in opt-out mode. What that means is that all public fields and properties with getters are automatically serialized to JSON, and fields and properties that shouldn't be serialized are opted-out by placing JsonIgnoreAttribute on them. To serialize private members, the JsonPropertyAttribute can be placed on private fields and properties
public class test
{
[JsonProperty]
private string prop1 { get; set; }
[JsonProperty("property_name")]
private string prop2 { get; set; }
}
Note:
When I ran your code, it produced errors with the dictionary because it was not initizlied, in your constructor, you should add the initialization as well,
public WebSocketMessageBuilder(string eventName)
{
_eventName = eventName;
_eventData = new Dictionary<string, string>(); // this will help with NRE errors.
}
//using System.Text.Json;
public string ToJson()
{
return JsonSerializer.Serialize(this);
}
---- Update : ----
With the following code, I am getting exactly what you expect.
Note that Fields are converted to properties with the private set (this is important) and dictionary added to the Constructor.
public class WebSocketMessageBuilder
{
public string event_name { get; private set; }
public Dictionary<string, string> event_data { get; private set; }
public WebSocketMessageBuilder(string eventName, Dictionary<string, string> eventData)
{
event_name = eventName;
event_data = eventData;
}
public string ToJson()
{
return JsonSerializer.Serialize(this);
}
}
How to Call it?! :
var eventData = new Dictionary<string, string>();
eventData.Add("key1", "value1");
eventData.Add("key2", "value2");
var wsMessage = new WebSocketMessageBuilder("testing1", eventData);
var jsonResult = wsMessage.ToJson();
Result I am getting
{"event_name":"testing1","event_data":{"key1":"value1","key2":"value2"}}

how can I parse object into a class like json deserialize?

I want to make a own parser that can parse object values into the <T> Type that contains class with propertys.
the class ASObject is just a Dictionary<string, object>
public class Example {
public string User { get; set; }
public int Id { get; set; }
}
public static class ServiceResultParser<T>
{
public static T Parse(ASObject AS)
{
foreach(var l in AS.Values)
{
}
}
}
Usage:
var Result = ServiceResultParser.Parse<Example>(theobject);
string User = Result.User;
that is only a test class that I called Example
in json we can use JsonConvert.DeserializeObject<T>(value)
and no I dont want parse json.
how can I now parse the value into the Example class?
regarding.
You could check wheter T has a property with a name that matches the Dictionary's key:
public static class ServiceResultParser<T> where T : new()
{
public static T Parse(ASObject AS)
{
var temp = GetObject();
foreach(var l in AS)
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name == l.Key) property.SetValue(temp, l.Value);
}
}
return temp;
}
protected T GetObject()
{
return new T();
}
}
You should also check if the properties type match, etc...

Dynamic property name for serialization [duplicate]

This question already has answers here:
Serialize/Deserialize dynamic property name using JSON.NET
(4 answers)
Closed 2 years ago.
I need to have a dynamic property-name for the serialization.
public class Home
{
public virtual int Id { get; set; } // value: 2
public virtual string propertyName { get; set; } // value: administration
public virtual string Text { get; set; } // value: text1
}
should serialize to:
{
"Id": 2,
"administration": "text1"
}
Is there any way to serialize that? Which is the best way to deserialize it?
According to this post on how to Dynamically rename or ignore properties without changing the serialized class by Rico Suter, you can add a class which extends DefaultContractResolver named PropertyRenameAndIgnoreSerializerContractResolver.
So the model would look like:
public class Home
{
[JsonProperty("firstName")]
public int Id { get; set; } // value: 2
//public Dictionary<string,string> dictionary { get; set; }
[JsonProperty("propertyName")]
public string propertyName { get; set; } // value: administration
[JsonIgnore]
public string Text { get; set; } // value: text1
}
And serialization would look like this:
var home = new Home();
home.Id = 2;
home.propertyName = "text1";
var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolver.RenameProperty(typeof(Home), "propertyName", "administration");
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;
var json = JsonConvert.SerializeObject(home, serializerSettings);
Which give the desire output.
Add this class PropertyRenameAndIgnoreSerializerContractResolver.cs:
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
private readonly Dictionary<Type, HashSet<string>> _ignores;
private readonly Dictionary<Type, Dictionary<string, string>> _renames;
public PropertyRenameAndIgnoreSerializerContractResolver()
{
_ignores = new Dictionary<Type, HashSet<string>>();
_renames = new Dictionary<Type, Dictionary<string, string>>();
}
public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
{
if (!_ignores.ContainsKey(type))
_ignores[type] = new HashSet<string>();
foreach (var prop in jsonPropertyNames)
_ignores[type].Add(prop);
}
public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
{
if (!_renames.ContainsKey(type))
_renames[type] = new Dictionary<string, string>();
_renames[type][propertyName] = newJsonPropertyName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (IsIgnored(property.DeclaringType, property.PropertyName))
property.ShouldSerialize = i => false;
if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
property.PropertyName = newJsonPropertyName;
return property;
}
private bool IsIgnored(Type type, string jsonPropertyName)
{
if (!_ignores.ContainsKey(type))
return false;
return _ignores[type].Contains(jsonPropertyName);
}
private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
{
Dictionary<string, string> renames;
if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
{
newJsonPropertyName = null;
return false;
}
return true;
}
}
Add a ToJObject method that returns a JObject.
public JObject ToJObject()
{
JObject jObject = new JObject()
{
{ "Id", Id },
{ propertyName, Text }
}
return jObject;
}
Then for Deserializing i would probably create a factory method something like this:
public static Home CreateFromJObject(JObject obj)
{
Home h = new Home();
foreach (var a in obj)
{
if (a.Key == "ID")
{
h.Id = a.Value.Value<int>();
}
else
{
h.propertyName = a.Key;
h.Text = a.Value.Value<string>();
}
}
return h;
}
Ofcause if you have multiple other values in there i would either change it to a switch or make sure that only the needed JObject is passed in there.

C# Dictionary with list as base

I'm trying to create a custom dictionary that uses a List as a base (will be used in XML deserialization). I can't figure out how to create it as the key can't be put on string it seems.
The dictionary would have the key property of the TestObject as the Key and as Value it would have the TestObject itself.
public class TestObject
{
public string Key { get; set; }
public string Property1 { get; set; }
public int Property2 { get; set; }
}
public class CustomDictionary<string, TestObject> : List<TestObject>
{
}
public class Methods
{
public void TestMethod(List<TestObject> list)
{
var testObject = new TestObject()
{
Key = "TEST",
Property1 = "ABC",
Property2 = 123,
};
CustomDictionary<string, TestObject> dictionary = new CustomDictionary<string, TestObject>(list);
var test;
dictionary.TryGetValue(testObject.Key, out test);
}
}
Given your last comment, what you want to do is something like this:
public class Methods
{
public void TestMethod(List<TestObject> list)
{
Dictionary<string, TestObject> data = list.ToDictionary(x => x.Key);
}
}
This uses LINQ's ToDictionary method, although a simple foreach loop would suffice.

Inheritance from Jobject Newtonsoft

Inheritance from Jobject(Newtonsoft) the existents properties from class not serialized.
Why were the Id and Name properties not serialized?
public class Test : JObject
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test["new_pro"] = 123456;
test.Id = 1;
test.Name = "Dog";
var r = Newtonsoft.Json.JsonConvert.SerializeObject(test);
// Result = { "new_pro":123456}
}
}
Any idea?
Whatever is the reason you want to do that - the reason is simple: JObject implements IDictionary and this case is treated in a special way by Json.NET. If your class implements IDictionary - Json.NET will not look at properties of your class but instead will look for keys and values in the dictionary. So to fix your case you can do this:
public class Test : JObject
{
public int Id
{
get { return (int) this["id"]; }
set { this["id"] = value; }
}
public string Name
{
get { return (string) this["name"]; }
set { this["name"] = value; }
}
}
If you just want to have both dynamic and static properties on your object - there is no need to inherit from JObject. Instead, use JsonExtensionData attribute:
public class Test {
public int Id { get; set; }
public string Name { get; set; }
[JsonExtensionData]
public Dictionary<string, JToken> AdditionalProperties { get; set; } = new Dictionary<string, JToken>();
}
var test = new Test();
test.AdditionalProperties["new_pro"] = 123456;
test.Id = 1;
test.Name = "Dog";
var r = Newtonsoft.Json.JsonConvert.SerializeObject(test);

Categories