Serializing ExpandoObject with ServiceStack.Text - c#

I am trying to serialize objects with the library ServiceStack.Text . This works
using System.Dynamic;
using ServiceStack.Text;
var x = new {Value= 10, Product = "Apples"};
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get, as I expect
{"Value":10,"Product":"Apples"}
However
dynamic x = new ExpandoObject();
x.Value = 100;
x.Product = "Apples";
Console.WriteLine(JsonSerializer.SerializeToString(x));
I get to my surprise
[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}]
Why! What's going on?
Secondly, how can I get what I want?

ExpandoObject implements IConnection<KeyValuePair> and IEnumerable<KeyValuePair>:
public sealed class ExpandoObject :
IDynamicMetaObjectProvider,
IDictionary<string, object>,
ICollection<KeyValuePair<string, object>>,
IEnumerable<KeyValuePair<string, object>>,
IEnumerable, INotifyPropertyChanged
My guess is that internally, the ServiceStack serializer is treating the ExpandoObject as an IEnumerable<KeyValuePair>, and so it serializes to a JSON array of key/value pairs.
This differs from your first (working) code snippet because .NET actually builds a real (anonymous) class for your data, basically it makes:
public class SomeNameTheCompilerMakesUp {
internal int Value { get; set; }
internal string Product { get; set; }
}
for you automatically, so when it is sent to the serializer, it is working with a real class with real properties, whereas the ExpandoObject is really backed by an object[] internally.
On a side-note, Microsoft's System.Web.Helpers.Json behaves the same way. This test passes:
[TestMethod]
public void ExpandoObjectSerializesToJsonArray()
{
dynamic anonType = new { Value = 10, Product = "Apples" };
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var anonResult = System.Web.Helpers.Json.Encode(anonType);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", anonResult);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
}
One final edit:
You can make this work the way you want by turning your ExpandoObject into a Dictionary<string, object>. The caveat to this code is that it duplicates the data into a dictionary, so you have 2 copies in memory (or slightly less than, since technically the strings might be interned).
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
// copy expando properties to dictionary
var dictionary = ((ExpandoObject)expando).ToDictionary(x => x.Key, x => x.Value);
var expandoResult = System.Web.Helpers.Json.Encode(expando);
var dictionaryResult = System.Web.Helpers.Json.Encode(dictionary);
Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Although, for anyone that comes across this later, and is actually using System.Web.Helpers.Json, the better thing to do is just wrap your ExpandoObject in a DynamicJsonObject like this:
[TestMethod]
public void TestMethod1()
{
dynamic expando = new ExpandoObject();
expando.Value = 10;
expando.Product = "Apples";
var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando));
Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
}
Ans once I worked through that, I found a similar question here: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

Related

Ensuring anonymous objects in C# all have certain common properties

I have a problem regarding anonymous objects in C#. The situation is as follows:
I have a C# web app which does NOT use the traditional ASP.NET Razor engine, but instead uses the RazorEngine open source project (https://github.com/Antaris/RazorEngine). I'm not sure if this is relevant, but it could be.
I'm passing a model object to each page I'm displaying. Each model object is different, there are many pages and therefore many different model objects, but I would rather not have to declare separate classes for each model, which is why I've been using anonymous classes:
// In method which displays page A:
var model = new {
Lang = _lang,
PropX = "foo",
PropY = "bar"
};
RazorEngine.Run("templateA", model);
// In a different method which displays page B:
var model = new {
Lang = _lang,
PropZ = "smu"
};
RazorEngine.Run("templateB", model);
You may notice that botn (and in fact, all) those models have a common property (the "Lang" property), a few common properties actually (Lang is the only one displayed in the example above to simplify matters).
My main problem is that I'm trying to ensure that those properties are added to all the models in a way which guarantees that they are included to all pages, and if I later decide to add a new common property, then I can do that in a single place.
One way would of course be to drop the anonymous classes, and use typed classes which all inherit from a single base class, which would declare the common properties. But this would be a lot of boilerplate code, and if there is another solution then I would prefer that.
Another solution would be to either declare the common properties in a sub-property of the model object, or declare the individual page properties in a sub object:
// Either like this:
var model = new {
Common = GetCommonModelProperties(),
PropX = "foo",
PropY = "bar"
};
public object GetCommonModelProperties()
{
return new {
Lang = _lang
};
}
// etc.
// or like this:
var pageModel = new {
PropX = "foo",
PropY = "bar
};
var model = CreateModel(pageModel);
RazorEngine.Run("templateA", model);
// where CreateModel could be implemented like this:
public object CreateModel(object pageModel)
{
return new
{
Lang = _lang,
// etc., whatever common properties there exist
Data = pageModel
};
}
The problem with this approach is that I would have to modify all my templates, either all instances where those pages refer to the common property (I would have to rename all Model.Lang instances to Model.Common.Lang), or to the individual page data (modify Model.AnyProperty to Model.Data.AnyProperty). Of course there is a great risk of errors when such a rewrite takes place.
So: is there a way to create an anonymous object, where a number of its properties are always the same, but the rest can be specified dynamically?
I've tried to create two separate objects, and then combine them into one, using code from this question: Merging anonymous types
var commonModel = new {
Lang = _lang
};
var pageModel = new {
PropX = "foo",
PropY = "bar"
};
var model = Merge(commonModel, pageModel);
and yes, this works. Until I have to use the Lang object, which is of a class type (which I have full control over), and this class overloads operator[]. If I use this workaround, the overload stops working, and I get the error:
Cannot apply indexing with [] to an expression of type 'object'
N.b. the indexing works perfectly fine if I just include the Lang property in a regular anonymous object.
I've also tried to create a separate base class for all the models, declare all the common properties in that class, but also derive it from System.Dynamic.DynamicObject, and override the TryGetMember method which would dynamically look up the page properties from a dictionary (which would work, since those properties are usually simple objects, i.e. they don't override the indexing operator, so I can add those properties dynamically at runtime:
var pageModel = new {
PropX = "foo",
PropY = "bar"
};
var model = CreateMainModel(pageModel);
public object CreateMainModel(object pageModel)
{
var mainModel = new BaseModel()
mainModel.Lang = _lang;
foreach (System.Reflection.PropertyInfo fi in pageModel.GetType().GetProperties())
{
mainModel.PageProperties[fi.Name] = fi.GetValue(pageModel, null);
}
return mainModel;
}
class BaseModel : DynamicObject
{
public LanguageMap Lang { get; set; }
public Dictionary<string, object> PageProperties { get; set; }
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (PageProperties.ContainsKey(binder.Name))
{
result = PageProperties[binder.Name];
return true;
}
return false;
}
}
The problem with this is that properties declared inside a class which derives from DynamicObject will NOT be visible inside the page templates, it seems that only properties returned from TryGetMember are. And if I make the members visible the explicity checking for their names inside TryGetMember, then the indexing stops working just like in the case above.
Now if this was C++, I could create a preprocessor macro:
#define COMMON_MODEL_PROPERTIES \
Lang = _lang
More = _otherProperty
// Where models are declared:
var model = new
{
COMMON_MODEL_PROPERTIES,
PropX = "foo",
PropY = "bar"
}
but this isn't C++... It's C#.
Any ideas?
Ok, so as per my initial comment... just wow. I would highly recommend that you bite the bullet and refactor to use static typing. To anyone else reading this, please do not do this.
However if you really really really really really really really really want to achieve this with minimal changes, I think this will work for you.
Add an extension method to your codebase:
internal static class DynamicCommonPropertyExtensions
{
public static object AddCommonProperties(this object obj)
{
dynamic expando = new ExpandoObject();
foreach (var prop in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (expando is IDictionary<string, object?> dict)
{
dict[prop.Name] = prop.GetValue(obj, null);
}
}
//Add common properties here
expando.CommonProp1 = "CommonPropValue1";
expando.CommonProp2 = "CommonPropValue2";
return expando;
}
}
This can then be used as follows (with your example)
var model = new
{
Lang = _lang,
PropX = "foo",
PropY = "bar"
};
var addedCommonProperties = model.AddCommonProperties();
RazorEngine.Run("templateA", addedCommonProperties);
Or even "better" without using another variable
var model = new
{
Lang = "Test",
PropX = "foo",
PropY = "bar"
}.AddCommonProperties();
RazorEngine.Run("templateA", model);
If you need to access the properties before passing through you can declare it as dynamic
dynamic model = new
{
Lang = "Test",
PropX = "foo",
PropY = "bar"
}.AddCommonProperties();
var a = model.CommonProp1;
I now feel really dirty having written this

Could JsonDocument be used as ContractResolver?

I have a question regarding the newly released .NET Core 3.0 and its new System.Text.Json, I would like to ask if the new JsonDocument could be used similarly to ContractResolver class in Newtonsoft JSON.NET.
What I need is quite straightforward, assume one class with two properties
public string Name {get; set;}
public string Street {get; set;}
and I need to deserialize two different JSONs into this class.
JSON 1:
{"person_A":{"full-name":"Micheal","address-street":"1st avenue","address-city":"New York"},
"person_B":{"full-name":"John","address-street":"Green street","address-city":"London"}}
JSON 2:
{"man_A":{"fullname":"Bush","street":"1st avenue","city":"Washington","state":"US"},
"woman_B":{"fullname":"McCarter","street":"Green street","city":"London","state":"GB"}}
I need to deserialize property full-name, fullname as Name and address-street,street as Street. The other JSON fields are not needed.
To deserialize multiple JSON with different property names I am using a ContractResolver in JSON.NET, which works quite well.
The reason why I am looking into the JsonDocument is that I am deserializing just few JSON properties and with current approach I have to cache entire JSON. If I uderstood correctly, the JsonDocument should allow me to access just the properties I need.
Thanks!
EDIT
To clarify a bit what I am trying to ask here - the idea is to get info about the Json object but not to load it entirely since it is not needed, that's why I would like to use the new JsonDocument, select just the things that I need and load those. Since the Json property names are different than my class properties and I have multiple Json trying to deserialize into the same class, I need something like IContractResolver to match the class properties with the names in Json.
I was able to make something like this working, but I admit it is not very pretty.
private readonly Dictionary propertyMappings = new Dictionary();
private void AddMap<U>(Expression<Func<Instrument,U>> expression, string jsonPropertyName)
{
var memberExpression = (MemberExpression)expression.Body;
propertyMappings.Add(memberExpression.Member.Name, jsonPropertyName);
}
public override async Task<List<Person>> GetPeopleAsync(HttpRequestMessage request)
{
AddMap(x => x.Name, "full-name");
AddMap(x => x.Street, "address-street");
var result = new List<Person>();
var response = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var stream = await response.Content.ReadAsStreamAsync();
var document = await JsonDocument.ParseAsync(stream);
document.RootElement.GetProperty("people").EnumerateObject()
.ToList()
.ForEach(x =>
{
var person= new Person();
foreach (var p in propertyMappings)
{
x.Value.TryGetProperty(p.Value, out var prop);
var v = person.GetType().GetProperty(p.Key);
v.SetValue(person,Convert.ChangeType(prop.ToString(),v.PropertyType));
}
result.Add(person);
});
return result;
}</code>

How to deserialize generic dictionary with object value in protobuf-net using a proxy/shim property?

I've tried using the solutions in this post. Both the property and the surrogate didn't work. The cause would most likely be that protobuf-net doesn't work on dictionary directly but serializes the types a dictionary contains (and a surrogate on object is impossible).
My test code
class Program
{
static void Main(string[] args)
{
var library = new Library();
library.Keeper.Add("Harry Potter", "blablabla text... text...");
library.Keeper.Add("Other book", "Awesome story.");
// Write and read to test serializing.
Library deserialize;
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, library);
ms.Flush();
ms.Position = 0;
deserialize = Serializer.Deserialize<Library>(ms);
}
Console.WriteLine(deserialize.Keeper.Count);
}
}
Library class
[ProtoContract]
public class Library
{
public Dictionary<string, object> Keeper { get; set; }
[ProtoMember(1)]
public Dictionary<string, string> KeeperSer
{
get
{
var res = new Dictionary<string, string>();
foreach (var pair in Keeper)
{
res.Add(pair.Key, TypeDescriptor.GetConverter(pair.Value.GetType()).ConvertToInvariantString(pair.Value));
}
return res;
}
set
{
var set = new Dictionary<string, object>();
foreach (var pair in value)
{
set.Add(pair.Key, pair.Value);
}
Keeper = set;
}
}
public Library()
{
Keeper = new Dictionary<string, object>();
}
}
I've also tried adding [ProtoIgnore] to the Keeper property. Adding a breakpoint at the setter of either KeeperSer or Keeper never triggers when running the project. The getters do work and the data is being written by protobuf-net to the MemoryStream. The length also varies when adding new items to the Library.
The reason for the Dictionary<string, object> is that I'm using TypeDescriptor.GetConverter(Type) in another project. And I want to dynamically convert types to my required type.
What am I missing to make the setter of the proxy/shim property KeeperSer working?
Through testing it seems that any IEnumerable<object> compatible type just won't work in any way with Protobuf-net because it doesn't know how to handle it at all. The setter of those types never get called even though no error is thrown. Besides that, using a generic surrogate to 'cheat' the implicit operator gives a recursive loop inside Protobuf-net.
For now, I think I need to go with just storing a textual representation of the object data (Dictionary<string,string>) and never use Dictionary<string,object> in conjunction with the Protobuf-net serializer.

More safe way to do dynamic list? (dynamic type .NET 4.0)

I was trying to make a List with different types of objects (or another enumerable / indexed type). I didn't use to create own enumerator on classes, so I was googling more and more.
Now I am here with (probably) one of the worst idea
public List<dynamic> IndexedProperties
{
get
{
// some code
// returned list (I wrote only types)
return new List<dynamic> { String, String, String, DateTime, DateTime, String };
}
}
So I could use it like that:
foreach (var prop in data.IndexedProperties)
Console.WriteLine(prop);
So, to precise the question - is this a good way to do that? (I think that using dynamic is not good at all, only in critical situation)
Can I do it more safe?
If all you're doing with the members of the list is showing a string then you can use:
public List<object> IndexedProperties = new List<object>();
...
foreach(var prop in data.IndexedProperties)
Console.WriteLine(prop.ToString());
Alternatively, you could replace the dynamic type with an interface or abstract class that is augmented with a property that aggregates the object:
public class DynamicContainer
{
public dynamic ValueMember{ get; set; }
public item(dynamic valueMember)
{
this.ValueMember = valueMember;
}
}
Then in your list constructor would go something like:
public List<DynamicContainer> IndexedProperties
{
get
{
return new List<DynamicContainer>
{
new DynamicContainer(stringObject1),
new DynamicContainer(stringObject2),
new DynamicContainer(stringObject3),
new DynamicContainer(dateTimeObject1),
new DynamicContainer(dateTimeObject2),
new DynamicContainer(stringObject4)
};
}
}
...
foreach(var prop in data.IndexedProperties)
Console.WriteLine(prop.ValueMember.ToString());

automapper map dynamic object

I am working with Automapper and need to achieve the following mapping but not sure how it can be done.
I want to map a Dictionary object to a dynamic object, so that the key is the property on the object and the value of the dictionary is the value of property in dynamic object.
Can this be achieve with automapper and if so, how?
You can simply get Dictionary from ExpandoObject and fill it with original dictionary values
void Main()
{
AutoMapper.Mapper.CreateMap<Dictionary<string, object>, dynamic>()
.ConstructUsing(CreateDynamicFromDictionary);
var dictionary = new Dictionary<string, object>();
dictionary.Add("Name", "Ilya");
dynamic dyn = Mapper.Map<dynamic>(dictionary);
Console.WriteLine (dyn.Name);//prints Ilya
}
public dynamic CreateDynamicFromDictionary(IDictionary<string, object> dictionary)
{
dynamic dyn = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)dyn;
dictionary.ToList()
.ForEach(keyValue => expandoDic.Add(keyValue.Key, keyValue.Value));
return dyn;
}
Here's en example, but if you drop a comment or elaborate your post it could be more descriptive. Given this class:
class Foo
{
public Foo(int bar, string baz)
{
Bar = bar;
Baz = baz;
}
public int Bar { get; set; }
public string Baz { get; set; }
}
You can create a dictionary of its public instance properties and values this way:
var valuesByProperty = foo.GetType().
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));
If you want to include more or different results, specify different BindingFlags in the GetProperties method. If this doesn't answer your question, please leave a comment.
Alternatively, assuming you're working with a dynamic object and anonymous types, the approach is similar. The following example, clearly, doesn't require the class Foo.
dynamic foo = new {Bar = 42, Baz = "baz"};
Type fooType = foo.GetType();
var valuesByProperty = fooType.
GetProperties(BindingFlags.Public | BindingFlags.Instance).
ToDictionary(p => p, p => p.GetValue(foo));

Categories