Deserialize Dictionary<string, MyClass> from json, possible without Newtonsoft.Json? - c#

Help me to deserialize the Dictionary object.
By example I have my class
[Serializable]
public class MyClass
{
/// <summary>
/// some class variables
/// </summary>
public string variable_A;
public decimal variable_B;
/// <summary>
/// constructor for example
/// </summary>
public MyClass(string s, decimal d)
{
variable_A = s;
variable_B = d;
}
}
and I create Dictionary - with string as a key, and MyClass object as a value:
Dictionary<string, MyClass> myDictionary = new Dictionary<string, MyClass>
{
{ "key1", new MyClass("some string value", 5) },
{ "key2", new MyClass("some string value", 3) },
{ "key3", new MyClass("some string value", 10) }
};
Here I serialize this data to trasfer to other place:
string myObjectJson = new JavaScriptSerializer().Serialize(myDictionary);
Console.WriteLine(myObjectJson);
But how can I do reverse operation - to deserialize this data back to my Dictionary object?
I tried to use DeserializeObject like this:
JavaScriptSerializer js = new JavaScriptSerializer();
Dictionary<string, MyClass> dict = (Dictionary<string, Object>)js.DeserializeObject(myObjectJson);
//// Also tried this method, but it describes deserialize to Dictionary<string, string>, but I have my object in value, not string
//// http://stackoverflow.com/questions/4942624/how-to-convert-dictionarystring-object-to-dictionarystring-string-in-c-sha
//// p.s.: don't want to use third-party dll's, like Json.Net
//// http://stackoverflow.com/questions/19023696/deserialize-dictionarystring-t

You should use the generic overload:
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, MyClass>>(myObjectJson);
Also make sure that MyClass type has a default constructor.

Related

How to have a singleton class and use it through out the application c#

I have a class which deserializes a JSON file.
The JSON is styleconfig.json
{
"Style1": {
"Font": "Arial",
"width": "25px",
"className": "Grid-side"
} ,
"Style2": {
"Font": "Arial",
"width": "25px",
"className": "Grid-side"
}
}
I have a classA:
var jss = new JavaScriptSerializer();
string json = new StreamReader(context.Request.InputStream).ReadToEnd();
Dictionary<string, string> sData = jss.Deserialize<Dictionary<string, string>>(json);
So I need to call this classA every time in my application
For Example
There are two pages...Page1 and page2 both the style variables are there on json
so every time I need to call the classA to Deserialize
page1 call classA to Deserialize
page2 call classA to Deserialize
So this may affect the performance.End of the day the JSON file is the same for the whole application
So my requirement is to run classA only once when I login into the application and make the
Deserialized JSON object throughout the application.
I need some help with this
You could do this with a static class and use a Lazy<> to ensure it is loaded only once:
public static class A
{
private static Lazy<Dictionary<string, string>> _data = new Lazy<Dictionary<string, string>>(() => GetData());
public static Dictionary<string, string> Data => _data.Value;
private static Dictionary<string, string> GetData()
{
var jss = new JavaScriptSerializer();
string json = new StreamReader(context.Request.InputStream).ReadToEnd();
return jss.Deserialize<Dictionary<string, string>>(json);
}
}
You should use Lazy<T> for that. Here's an example:
static class ClassA
{
private static Lazy<Dictionary<string, string>> _json = new Lazy<Dictionary<string, string>>(ReadJson);
private static Dictionary<string, string> ReadJson()
{
var jss = new JavaScriptSerializer();
var json = new StreamReader(context.Request.InputStream).ReadToEnd();
return jss.Deserialize<Dictionary<string, string>>(json);
}
public Dictionary<string, string> Json => _json.Value;
}
Now the first time you read ClassA.Json the file will be parsed and read. The subsequent calls will just return the cached value.
If I have correctly understood your question, apart from a lazy field already explained in other comments, have you tried a simple property?
public class ClassA
{
//Just a singleton model
static ClassA _SingleInstance = null;
public static ClassA SingleInstance
{
get
{
if (_SingleInstance == null)
_SingleInstance = new ClassA();
return _SingleInstance;
}
}
Dictionary<string, string> _Data = null;
public Dictionary<string, string> Data
{
get
{
if (_Data == null)
LoadData();
return _Data;
}
}
private ClassA()
{
//your constructor
}
//As pointed out by torvin, to avoid multithread races, load must
//be synchronized
private void LoadData()
{
lock(LoadMutex)
{
if (_Data == null)
{
var jss = new JavaScriptSerializer();
string json = new StreamReader(context.Request.InputStream).ReadToEnd();
_Data = jss.Deserialize<Dictionary<string, string>>(json);
}
}
}
private static readonly object LoadMutex = new object();
}
and then from Page1 and Page2, you call it:
Dictionary<string, string> myConfigData = ClassA.SingleInstance.Data;

convert IDictionary data into JSON string using NewtonJSON

how can I convert IDictionary data into JSON using NewtonJSON. My IDictionary data contains the following data:
type: 19
id : 4433
Now I want to convert it into
{
"type":"19",
"id": "4433"
}
How do I do this?
IDictionary<string, string> messageData = message.Data;
var json = JsonConvert.SerializeObject(messageData, new JsonSerializerSettings()
{
Formatting = Formatting.Indented
});
here is the update please see my screenshots
Json.NET (formely Newtonsoft.Json) already has the built in capability to convert dictionaries into Json objects:
// the dictionary may be anything IDictionary<string, whatever>, Json.NET will convert it anyway
IDictionary<string, string> dict = new Dictionary<string, string>()
{
{ "type", "19" },
{ "id" ,"4433"}
};
var json = JsonConvert.SerializeObject(dict, new JsonSerializerSettings()
{
Formatting = Formatting.Indented
});
Outputs:
{
"type": "19",
"id": "4433"
}
Demo: https://dotnetfiddle.net/a562kK
[Edit]
The type you are trying to serialize is not an IDictionary at all. You should try to convert it to a dictionary first.
Here an example (assuming message.Data implements at least IEnumerable):
var dict = new Dictionary<string, string>();
foreach(var item in message.Data)
{
// get Key and Value from item here
var kvp = item as KeyValuePair<string, string>; // this is just an example, I do not know what type your message.Data is returning
dict.Add(kvp.Key, kvp.Value);
}
// now you may serialize `dict`
var list = d.Select(x => new obj{ type = x.Key, id = x.Value});
var json = JsonConvert.SerializeObject(list);
Class:
public class obj
{
public string type { get; set; }
public string id { get; set;}
}

How to serialize anonymous object to JSON without including property name

I have the following code:
///<summary>
///In this case you can set any other valid attribute for the editable element.
///For example, if the element is edittype:'text', we can set size, maxlength,
///etc. attributes. Refer to the valid attributes for the element
///</summary>
public object OtherOptions { get; set; }
public override string ToString()
{
return this.ToJSON();
}
I need to get the anonymous object from the OtherOptions property and serialize each property of the anonymous object as it were from the main object.
E.g.:
OtherOptions = new { A = "1", B = "2" }
If I serialize it, it will be (or something like this):
OtherOptions: {
A: "1",
B: "2"
}
Is it possible to have A and B at the same level of OtherOptions without explicitly removing it.
Ok this is just ugly and I don't recommend doing it but it does what you want...
Essentially, it creates a Dictionary of just the properties you want and then serializes that dictionary.
static void Main(string[] args)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var obj = new {Prop1 = "val1", OtherOptions = new {A = "1", B = "2"}};
IDictionary<string, object> result = new Dictionary<string, object>();
foreach (var kv in GetProps(obj))
{
if (!kv.Key.Equals("OtherOptions"))
result.Add(kv);
}
foreach (var kv in GetProps(obj.OtherOptions))
{
result.Add(kv);
}
var serialized = serializer.Serialize(result);
}
static IEnumerable<KeyValuePair<string, object>> GetProps(object obj)
{
var props = TypeDescriptor.GetProperties(obj);
return
props.Cast<PropertyDescriptor>()
.Select(prop => new KeyValuePair<string, object>(prop.Name, prop.GetValue(obj)));
}
serialized becomes
{"Prop1":"val1","A":"1","B":"2"}
You could use an attribute on the field you want to ignore and then check for that attribute in the GetProps method and not return if exists.
Again, I do not recommend doing this.

Serializing a class containing a Dictionary of Dictionay

I have defined a class which contains only one member of type dictionary of dictionary. I want to serialize it to JSON format and hence using JavaScriptSerializer.
[Serializable]
class X
{
private readonly Dictionary<string, Dictionary<string, string>> dic;
public X()
{
dic = new Dictionary<string, Dictionary<string, string>>();
}
public void Add()
{
this.dic.Add("x", new Dictionary<string, string>() { { "a", "b" } });
}
}
class Program
{
static void Main(string[] args)
{
var x = new X();
x.Add();
string msg = new JavaScriptSerializer(new SimpleTypeResolver()).Serialize(x);
var y = new JavaScriptSerializer(new SimpleTypeResolver()).Deserialize<X>(msg);
}
}
Now, the above code run successful without any error/exception but the results are not as excepted. The serialized string of class X in the above code is
{"__type":"Testing.X, Testing, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}
Can anybody tell me whats the problem in the above code and what I'm missing? Also, if in the above class, I change the inner dictionary type to Dictionary<string, IEntity> then what all I have to do to serialize it.
JavaScriptSerializer is designed to only pull public properties by default. Once you expose the field through a getter or setter you should be able to serialize this data.
[Serializable]
class X
{
private readonly Dictionary<string, Dictionary<string, string>> dic;
public X()
{
dic = new Dictionary<string, Dictionary<string, string>>();
}
public void Add()
{
this.dic.Add("x", new Dictionary<string, string>() { { "a", "b" } });
}
//Property exposing private field 'dic'.
public Dictionary<string, Dictionary<string, string>> Dictionary
{
get
{
return dic;
}
}
}
class Program
{
static void Main(string[] args)
{
var x = new X();
x.Add();
string msg = new JavaScriptSerializer(new SimpleTypeResolver()).Serialize(x);
var y = new JavaScriptSerializer(new SimpleTypeResolver()).Deserialize<X>(msg);
}
}
In this case, the string contains the following output (look to the very end):
{"__type":"ConsoleApplication1.X, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Dictionary":{"x":{"a":"b"}}}

How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

I really like the ExpandoObject while compiling a server-side dynamic object at runtime, but I am having trouble flattening this thing out during JSON serialization. First, I instantiate the object:
dynamic expando = new ExpandoObject();
var d = expando as IDictionary<string, object>;
expando.Add("SomeProp", SomeValueOrClass);
So far so good. In my MVC controller, I want to then send this down as a JsonResult, so I do this:
return new JsonResult(expando);
This serializes the JSON into the below, to be consumed by the browser:
[{"Key":"SomeProp", "Value": SomeValueOrClass}]
BUT, what I'd really like is to see this:
{SomeProp: SomeValueOrClass}
I know I can achieve this if I use dynamic instead of ExpandoObject -- JsonResult is able to serialize the dynamic properties and values into a single object (with no Key or Value business), but the reason I need to use ExpandoObject is because I don't know all of the properties I want on the object until runtime, and as far as I know, I cannot dynamically add a property to a dynamic without using an ExpandoObject.
I may have to sift through the "Key", "Value" business in my javascript, but I was hoping to figure this out prior to sending it to the client. Thanks for your help!
Using JSON.NET you can call SerializeObject to "flatten" the expando object:
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
Will output:
{"name":"John Smith","age":30}
In the context of an ASP.NET MVC Controller, the result can be returned using the Content-method:
public class JsonController : Controller
{
public ActionResult Data()
{
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
return Content(json, "application/json");
}
}
You could also, make a special JSONConverter that works only for ExpandoObject and then register it in an instance of JavaScriptSerializer. This way you could serialize arrays of expando,combinations of expando objects and ... until you find another kind of object that is not getting serialized correctly("the way u want"), then you make another Converter, or add another type to this one. Hope this helps.
using System.Web.Script.Serialization;
public class ExpandoJSONConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
var dictionary = obj as IDictionary<string, object>;
foreach (var item in dictionary)
result.Add(item.Key, item.Value);
return result;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) });
}
}
}
Using converter
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJSONConverter()});
var json = serializer.Serialize(obj);
Here's what I did to achieve the behavior you're describing:
dynamic expando = new ExpandoObject();
expando.Blah = 42;
expando.Foo = "test";
...
var d = expando as IDictionary<string, object>;
d.Add("SomeProp", SomeValueOrClass);
// After you've added the properties you would like.
d = d.ToDictionary(x => x.Key, x => x.Value);
return new JsonResult(d);
The cost is that you're making a copy of the data before serializing it.
I solved this by writing an extension method that converts the ExpandoObject into a JSON string:
public static string Flatten(this ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{");
foreach (KeyValuePair<string, object> kvp in d) {
contents.Add(String.Format("{0}: {1}", kvp.Key,
JsonConvert.SerializeObject(kvp.Value)));
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
This uses the excellent Newtonsoft library.
JsonResult then looks like this:
return JsonResult(expando.Flatten());
And this is returned to the browser:
"{SomeProp: SomeValueOrClass}"
And I can use it in javascript by doing this (referenced here):
var obj = JSON.parse(myJsonString);
I hope this helps!
I was able to solve this same problem using JsonFx.
dynamic person = new System.Dynamic.ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";
person.Address = "1234 Home St";
person.City = "Home Town";
person.State = "CA";
person.Zip = "12345";
var writer = new JsonFx.Json.JsonWriter();
return writer.Write(person);
output:
{ "FirstName": "John", "LastName": "Doe", "Address": "1234 Home St",
"City": "Home Town", "State": "CA", "Zip": "12345" }
I took the flattening process one step further and checked for list objects, which removes the key value nonsense. :)
public string Flatten(ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{ ");
foreach (KeyValuePair<string, object> kvp in d)
{
if (kvp.Value is ExpandoObject)
{
ExpandoObject expandoValue = (ExpandoObject)kvp.Value;
StringBuilder expandoBuilder = new StringBuilder();
expandoBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
String flat = Flatten(expandoValue);
expandoBuilder.Append(flat);
string expandoResult = expandoBuilder.ToString();
// expandoResult = expandoResult.Remove(expandoResult.Length - 1);
expandoResult += "]";
contents.Add(expandoResult);
}
else if (kvp.Value is List<Object>)
{
List<Object> valueList = (List<Object>)kvp.Value;
StringBuilder listBuilder = new StringBuilder();
listBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
foreach (Object item in valueList)
{
if (item is ExpandoObject)
{
String flat = Flatten(item as ExpandoObject);
listBuilder.Append(flat + ",");
}
}
string listResult = listBuilder.ToString();
listResult = listResult.Remove(listResult.Length - 1);
listResult += "]";
contents.Add(listResult);
}
else
{
contents.Add(String.Format("\"{0}\": {1}", kvp.Key,
JsonSerializer.Serialize(kvp.Value)));
}
//contents.Add("type: " + valueType);
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
JsonResult uses JavaScriptSerializer which actually deserializes (the concrete) Dictionary<string, object> as you want.
There's an overload of the Dictionary<string, object> constructor which takes IDictionary<string, object>.
ExpandoObject implements IDictionary<string, object> (I think you can see where I am going here...)
Single level ExpandoObject
dynamic expando = new ExpandoObject();
expando.hello = "hi";
expando.goodbye = "cya";
var dictionary = new Dictionary<string, object>(expando);
return this.Json(dictionary); // or new JsonResult { Data = dictionary };
One line of code, using all built-in types :)
Nested ExpandoObjects
Of course if you are nesting ExpandoObjects then you will need to recursively convert them all into Dictionary<string, object>s:
public static Dictionary<string, object> RecursivelyDictionary(
IDictionary<string, object> dictionary)
{
var concrete = new Dictionary<string, object>();
foreach (var element in dictionary)
{
var cast = element.Value as IDictionary<string, object>;
var value = cast == null ? element.Value : RecursivelyDictionary(cast);
concrete.Add(element.Key, value);
}
return concrete;
}
your final code becoming
dynamic expando = new ExpandoObject();
expando.hello = "hi";
expando.goodbye = "cya";
expando.world = new ExpandoObject();
expando.world.hello = "hello world";
var dictionary = RecursivelyDictionary(expando);
return this.Json(dictionary);
This may not be useful to you, but I had a similar requirement, but used a SerializableDynamicObject
I changed the name of the dictionary to "Fields" and then this serializes with Json.Net to produce json which looks like:
{"Fields":{"Property1":"Value1", "Property2":"Value2" etc.
where Property1 and Property2 are Dynamically added properties - i.e. Dictionary Keys
It would be perfect if I could get rid of the extra "Fields" property which encapsulates the rest, but I've worked around that limitation.
Answer moved from this question on request
This is a late answer, but I had the same problem, and this question helped me solve them.
As a summary, I thought I should post my results, in hopes that it speeds up the implementation for others.
First the ExpandoJsonResult, which you can return an instance of in your action. Or you can override the Json method in your controller and return it there.
public class ExpandoJsonResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
response.ContentEncoding = ContentEncoding ?? response.ContentEncoding;
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoConverter() });
response.Write(serializer.Serialize(Data));
}
}
}
Then the converter (which supports both serialization and de-serialization. See below for an example of how to de-serialize).
public class ExpandoConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{ return DictionaryToExpando(dictionary); }
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{ return ((ExpandoObject)obj).ToDictionary(x => x.Key, x => x.Value); }
public override IEnumerable<Type> SupportedTypes
{ get { return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) }); } }
private ExpandoObject DictionaryToExpando(IDictionary<string, object> source)
{
var expandoObject = new ExpandoObject();
var expandoDictionary = (IDictionary<string, object>)expandoObject;
foreach (var kvp in source)
{
if (kvp.Value is IDictionary<string, object>) expandoDictionary.Add(kvp.Key, DictionaryToExpando((IDictionary<string, object>)kvp.Value));
else if (kvp.Value is ICollection)
{
var valueList = new List<object>();
foreach (var value in (ICollection)kvp.Value)
{
if (value is IDictionary<string, object>) valueList.Add(DictionaryToExpando((IDictionary<string, object>)value));
else valueList.Add(value);
}
expandoDictionary.Add(kvp.Key, valueList);
}
else expandoDictionary.Add(kvp.Key, kvp.Value);
}
return expandoObject;
}
}
You can see in the ExpandoJsonResult class how to use it for serialization. To de-serialize, create the serializer and register the converter in the same way, but use
dynamic _data = serializer.Deserialize<ExpandoObject>("Your JSON string");
A big thank you, to all participants here that helped me.
Using returning dynamic ExpandoObject from WebApi in ASP.Net 4, the default JSON formatter seems to flatten ExpandoObjects into simple JSON object.
It seems like the serializer is casting the Expando to a Dictionary and then serializing it (thus the Key/Value business). Have you tried Deserializing as a Dictionary and then casting that back to an Expando?
I just had the same problem and figured out something pretty weird.
If I do:
dynamic x = new ExpandoObject();
x.Prop1 = "xxx";
x.Prop2 = "yyy";
return Json
(
new
{
x.Prop1,
x.Prop2
}
);
It works, but only if my method use HttpPost attribute. If I use HttpGet i get error.
So my answer works only on HttpPost. In my case it was an Ajax Call so i could change HttpGet by HttpPost.

Categories

Resources