How do I detect an ExpandoObject vs a Dynamic Object? - c#

How to I determine if a Type is an ExpandoObject vs a Dynamic object?
This is returning true for both:
public static bool IsDynamicObject(Type type)
{
return typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type);
}
Example Code for Dynamic Object:
public class Entity
{
public Guid Id { get; set; }
public String Name { get; set; }
}
Delta<Entity> x = new Delta<Entity>();
dynamic dynamicX = x;
dynamicX.Name = nameof(Entity);
dynamicX.Id = typeof(Entity).GUID;
Example Code for Expando Object:
dynamic childX = new ExpandoObject();
childX.A = 1;

The ExpandoObject can be casted to a dictionary to get the member names and values
public static bool IsExpandoObject(object objectValue)
{
if (objectValue == null)
return false;
if (IsDynamicObject(objectValue.GetType()))
{
IDictionary<string, object> expandoPropertyValues = objectValue as IDictionary<string, object>;
return expandoPropertyValues != null;
}
return false;
}
public static bool IsDynamicObject(Type type)
{
return typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type);
}

Related

Convert object by reflection

I want to convert an object A to object B. The classes A and B have the same properties, just the names are changed.
I use this method:
/// <summary>
internal static T objectMapper<T>(object objectSource, T objectTarget)
{
dynamic o = objectSource;
Type typeA = objectSource.GetType();
Type typeB = objectTarget.GetType();
IList<PropertyInfo> propsA = new List<PropertyInfo>(typeA.GetProperties());
IList<PropertyInfo> propsB = new List<PropertyInfo>(typeB.GetProperties());
dynamic s;
ArrayList listArray = new ArrayList();
foreach (var prop in propsA)
{
s = objectSource.GetType().GetProperty(prop.Name).GetValue(objectSource, null);
listArray.Add(s);
}
int i = 0;
foreach (var prop in propsB)
{
prop.SetValue(objectTarget, listArray[i], null);
i++;
}
return objectTarget;
}
How can I edit properties of objectB in the foreach loop? I want to use a generic method for different objects.
This solution provides both your reflection-way and an alternative way by defining and implementing a copy method CopyFrom. To reduce code you could make the interface a base-class so you don't need to implement CopyFrom in the sub-classes....
public interface MyInterface
{
int Prop1 { get; set; }
string Prop2 { get; set; }
void CopyFrom(MyInterface obj);
}
public class A: MyInterface
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public void CopyFrom(MyInterface obj)
{
this.Prop1 = obj.Prop1;
this.Prop2 = obj.Prop2;
}
}
public class B: MyInterface
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public void CopyFrom(MyInterface obj)
{
this.Prop1 = obj.Prop1;
this.Prop2 = obj.Prop2;
}
}
public static class CopyUtils
{
public static void Copy(MyInterface src, MyInterface dst)
{
var props = typeof(MyInterface).GetProperties();
foreach(var prop in props)
{
prop.SetValue(dst, prop.GetValue(src, null), null);
}
}
}
I feel there might be a deeper architecture issue here. I'm failing to imagine why would you want to "copy" the values of the properties from one object of a class to another of a different class with the same property names.
If you're trying to "shape" the object maybe just passing an interface will do the work
Anyhow, see if this helps:
public static class ObjectMorpher
{
public class InvalidMorphException : Exception
{
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoredOnMorphAttribute : Attribute
{
}
public static TargetType Morph<TargetType>(this object source, TargetType dest, Func<string, string> propertyMatcher = null, bool failOnNoMatch = false)
where TargetType : class
{
if (source == null || dest == null)
throw new ArgumentNullException();
foreach (var sourceProp in source.GetType().GetProperties().Where(x => x.GetCustomAttributes<IgnoredOnMorphAttribute>().Any() == false))
{
var destProp = typeof(TargetType).GetProperties().Where(x => x.Name == ((propertyMatcher == null) ? sourceProp.Name : propertyMatcher(sourceProp.Name))).FirstOrDefault();
//check property exists
if (destProp == null)
{
if (failOnNoMatch)
throw new InvalidMorphException();
else
continue;
}
//check value type is assignable
if (!destProp.GetType().IsAssignableFrom(sourceProp.GetType()))
{
if (failOnNoMatch)
throw new InvalidMorphException();
else
continue;
}
destProp.SetValue(dest, sourceProp.GetValue(source));
}
return dest;
}
}
Usage example:
var A = new ClassA();
var B = new ClassB();
B = A.Morph(B);
Optionally you can set a property match for the case when properties doesn't have the exact same name.
Also notice the use of the IgnoredOnMorph attribute to mark properties as not morph-able (like calculated properties)
You might find automapper of use here (see https://github.com/AutoMapper/AutoMapper/wiki/Getting-started).
You would need to create a line for each object mapping in a startup file to set it up but if the properties are the same this would be as simple as:
mapper.CreateMap<ClassA, ClassB>().ReverseMap();
And then a single line to resolve the mapping when needed
mapper.Map(objectOfClassA, new ClassB());

How do you convert any C# object to an ExpandoObject? [duplicate]

This question already has answers here:
Convert class to dynamic and add properties
(5 answers)
can one convert a dynamic object to an ExpandoObject (c#)
(2 answers)
How to extend an existing object in c# 4.0 using dynamics
(1 answer)
Closed 5 years ago.
I've read a lot about how ExpandoObject can be used to dynamically create objects from scratch by adding properties, but I haven't yet found how you do the same thing starting from a non-dynamic C# object that you already have.
For instance, I have this trivial class:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
I would like to convert this to ExpandoObject so that I can add or remove properties based on what it has already, rather than rebuilding the same thing from scratch. Is this possible?
Edit: the questions marked as duplicate are clearly NOT duplicates of this one.
It could be done like this:
var person = new Person { Id = 1, Name = "John Doe" };
var expando = new ExpandoObject();
var dictionary = (IDictionary<string, object>)expando;
foreach (var property in person.GetType().GetProperties())
dictionary.Add(property.Name, property.GetValue(person));
You cannot "convert" a Person class into an expando object. However, you could create a wrapper DynamicObject that contains a Person and forwards all of the fields.
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Reflection;
namespace SandboxConsole
{
public class ExpandoWrapper : DynamicObject
{
private readonly object _item;
private readonly Dictionary<string, PropertyInfo> _lookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCulture);
private readonly Dictionary<string, PropertyInfo> _ignoreCaseLookup = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, Box> _lookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCulture);
private readonly Dictionary<string, Box> _ignoreCaseLookupExtra = new Dictionary<string, Box>(StringComparer.InvariantCultureIgnoreCase);
private class Box
{
public Box(object item)
{
Item = item;
}
public object Item { get; }
}
public ExpandoWrapper(object item)
{
_item = item;
var itemType = item.GetType();
foreach (var propertyInfo in itemType.GetProperties())
{
_lookup.Add(propertyInfo.Name, propertyInfo);
_ignoreCaseLookup.Add(propertyInfo.Name, propertyInfo);
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
result = lookup.GetValue(_item);
return true;
}
Box box;
if (binder.IgnoreCase)
{
_ignoreCaseLookupExtra.TryGetValue(binder.Name, out box);
}
else
{
_lookupExtra.TryGetValue(binder.Name, out box);
}
if (box != null)
{
result = box.Item;
return true;
}
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
PropertyInfo lookup;
if (binder.IgnoreCase)
{
_ignoreCaseLookup.TryGetValue(binder.Name, out lookup);
}
else
{
_lookup.TryGetValue(binder.Name, out lookup);
}
if (lookup != null)
{
lookup.SetValue(_item, value);
return true;
}
var box = new Box(value);
_ignoreCaseLookupExtra[binder.Name] = box;
_lookupExtra[binder.Name] = box;
return true;
}
}
}
Example usage:
using System;
namespace SandboxConsole
{
class Program
{
static void Main(string[] args)
{
var person = new Person() {Id = 1};
dynamic wrapper = new ExpandoWrapper(person);
wrapper.Id = 2;
wrapper.NewField = "Foo";
Console.WriteLine(wrapper.Id);
Console.WriteLine(person.Id);
Console.WriteLine(wrapper.NewField);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Telephone { get; set; }
}
}

Custom deserialize from json object string

I'm trying to deserialize this JSON into an object but I can't reach the solution.
Json format:
{"option1":
{"field1":"true","field2":"false"},
"option2":
{"field1":"true","field2":"false"}}
I Have the following object:
[Serializable]
public class genericFieldOptions
{
public string option { get; set; }
public string field { get; set; }
public bool value{ get; set; }
}
And then the "deserializer":
public class genericFieldsConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(genericFieldOptions) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
List<genericFieldOptions> p = new List<genericFieldOptions>();
foreach (var entry in dictionary.Keys)
{
try
{
Dictionary<string, Boolean> test = (Dictionary<string, Boolean>)dictionary[entry];//error
p.Add(new genericFieldOptions { key = entry, field1=test["field1"],field2=test["field2"] });
}
catch { }
}
return p;
}
The call:
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new genericFieldsConverter() });
var example= serializer.Deserialize<List<genericFieldOptions>>(json);
How can I access the IDictionary<string, object> as Dictionary<string, Dictionary<string,boolean>> ? Or is it just impossible?
What am I doing wrong? Is there another easy way to do this?
The easy way is to correctly make objects that represent the serialized values. So for:
{"option1":
{"field1":"true","field2":"false"},
"option2":
{"field1":"true","field2":"false"}}
I would make:
public class Options
{
public Option Option1 { get; set; }
public Option Option2 { get; set; }
}
public class Option
{
public bool Field1 { get; set; }
public bool Field2 { get; set; }
}
For beginners, one of the easier ways is to use http://json2csharp.com/.
As mentioned, you can use Json.NET. If you don't want to create classes to deserialise to, you can use dictionaries as you have tried, or you could use a dynamic.
const string json = "{\"option1\":{\"field1\":true,\"field2\":false}," +
"\"option2\":{\"field1\":true,\"field2\":false}}";
var result1 = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, bool>>>(json);
Console.WriteLine(result1["option2"]["field1"]);
dynamic result2 = JsonConvert.DeserializeObject(json);
Console.WriteLine(result2.option2.field1);
Given that you have chosen to use javascriptserializer, firstly you need to do your conversion at the level of the List<genericFieldOptions> not the genericFieldOptions, because the serializer cannot convert a JSON object to a List<T> automatically.
Secondly, rather than casting the nested dictionaries to Dictionary<string, Boolean>, you need to cast to IDictionary<string, object> and then deserialize each value to a bool using JavaScriptSerializer.ConvertToType<bool>. Thus:
public class genericFieldsListConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(List<genericFieldOptions>) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var query = from entry in dictionary
let subDictionary = entry.Value.AsJsonObject()
where subDictionary != null
from subEntry in subDictionary
select new genericFieldOptions { option = entry.Key, field = subEntry.Key, value = serializer.ConvertToType<bool>(subEntry.Value) };
return query.ToList();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var list = (IList<genericFieldOptions>)obj;
if (list == null)
return null;
return list
.GroupBy(o => o.option)
.ToDictionary(g => g.Key, g => (object)g.ToDictionary(o => o.field, o => serializer.Serialize(o.value)));
}
}
public static class JavaScriptSerializerObjectExtensions
{
public static bool IsJsonObject(this object obj)
{
return obj is IDictionary<string, object>;
}
public static IDictionary<string, object> AsJsonObject(this object obj)
{
return obj as IDictionary<string, object>;
}
}

.NET - Omit Fields from JSON Web Service Call

I'm working on a .NET application for my company to interact with the Nutshell CRM. They have documentation provided for their JSON API here. I'm slowly building out all the classes in my application, but I've run into the issue of only needing to update one field on a call, but having the application include every field that I have on that class.
So for a condensed example of the editLead method, where I'm only modifying the customFields:
Nutshell documentation states that all fields are optional. My classes are set up as the following, where my custom fields in Nutshell are Division, Product, Country:
public class editLead
{
public Customfields customFields { get; set; }
}
public class Customfields
{
public string Division { get; set; }
public string Product { get; set; }
public string Country { get; set; }
}
EDIT (adding more code):
[DataContract(Name = "params")]
public class EditLeadParams
{
public string leadId { get; set; }
public editLead lead { get; set; }
public string rev { get; set; }
}
I'm using RestSharp to make the following call:
var editleadclient = new RestClient();
Method editleadMethod = new Method();
editleadMethod = Method.POST;
var editleadrequest = new RestRequest(editleadMethod);
editleadrequest.RequestFormat = DataFormat.Json;
editleadclient.BaseUrl = new Uri(apiuri);
editleadrequest.Credentials = new NetworkCredential(login, apikey);
leadJSON.EditLeadParams lead1 = new leadJSON.EditLeadParams()
{
leadId = foundlead[0],
lead = new leadJSON.editLead()
{
customFields = new leadJSON.Customfields()
{
Division = "AMERICAS",
}
},
rev = foundlead[1],
};
leadJSON.EditLeadRequest editreq = new leadJSON.EditLeadRequest()
{
#params = lead1,
method = "editLead",
};
editleadrequest.AddBody(editreq);
IRestResponse editResponse = editleadclient.Execute(editleadrequest);
If I only want to update the Division, it will use the following JSON {"customFields":{"Division":"AMERICAS","Product":null,"Country":null}}, and overwrite the Product and Country fields and make them blank. However, if I comment out the Product and Country, in the Customfields definition, it will update the Division and leave the Product and Country alone.
Is there another way to define these classes so that I can have it all defined, but only update what needs to be?
Declaration:
//JsonSerializer.cs
public static class JsonSerializer
{
public static string Serialize(object target, bool ignoreNulls = true)
{
var javaScriptSerializer = new JavaScriptSerializer();
if (ignoreNulls)
{
javaScriptSerializer.RegisterConverters(new[]
{
new NullExclusionConverter(target)
});
}
return javaScriptSerializer.Serialize(target);
}
}
//NullExclusionConverter.cs
public class NullExclusionConverter : JavaScriptConverter
{
private readonly Type _type;
public NullExclusionConverter(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this._type = target.GetType();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { this._type };
}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
if (obj == null)
{
return result;
}
var properties = obj.GetType().GetProperties();
foreach (var propertyInfo in properties)
{
//Use propertyInfo.Name to exclude a specific property name
if (propertyInfo.GetValue(obj, null) == null)
{
continue;
}
result.Add(propertyInfo.Name, propertyInfo.GetValue(obj, null));
}
return result;
}
}
Usage:
string jsonString = JsonSerializer.Serialize(objectToSerialize);
Add a reference to System.Web.Extensions
I am leaving my initial answer because it does return only non-null properties as a Json string. However here is your answer when using RestSharp.
On your request add:
editleadrequest.JsonSerializer.Options = new SerializerOptions()
{
SkipNullProperties = true
};

Limiting extension method to target EF Entities only

I've made an extension method which I use to make serializable dictionaries from EF Entities:
public static class Extensions
{
public static IDictionary<string, object> ToSerializable(this object obj)
{
var result = new Dictionary<string, object>();
foreach (var property in obj.GetType().GetProperties().ToList())
{
var value = property.GetValue(obj, null);
if (value != null && (value.GetType().IsPrimitive
|| value is decimal || value is string || value is DateTime
|| value is List<object>))
{
result.Add(property.Name, value);
}
}
return result;
}
}
I'm using it like this:
using(MyDbContext context = new MyDbContext())
{
var someEntity = context.SomeEntity.FirstOrDefault();
var serializableEntity = someEntity.ToSerializable();
}
I would like to know if there is any way to constrain it to be usable on my entities only, instead of all object:s.
Code for Patryk's answer:
public interface ISerializableEntity { };
public class CustomerEntity : ISerializableEntity
{
....
}
public static class Extensions
{
public static IDictionary<string, object> ToSerializable(
this ISerializableEntity obj)
{
var result = new Dictionary<string, object>();
foreach (var property in obj.GetType().GetProperties().ToList())
{
var value = property.GetValue(obj, null);
if (value != null && (value.GetType().IsPrimitive
|| value is decimal || value is string || value is DateTime
|| value is List<object>))
{
result.Add(property.Name, value);
}
}
return result;
}
}
Seeing how this code works with the marker interface, you may choose to put the serialization method in the interface to avoid the reflection and to have finer control on what gets serialized and how it might be encoded or encrypted:
public interface ISerializableEntity
{
Dictionary<string, object> ToDictionary();
};
public class CustomerEntity : ISerializableEntity
{
public string CustomerName { get; set; }
public string CustomerPrivateData { get; set; }
public object DoNotSerializeCustomerData { get; set; }
Dictionary<string, object> ISerializableEntity.ToDictionary()
{
var result = new Dictionary<string, object>();
result.Add("CustomerName", CustomerName);
var encryptedPrivateData = // Encrypt the string data here
result.Add("EncryptedCustomerPrivateData", encryptedPrivateData);
}
return result;
}
public static IDictionary<string, T> ToSerializable(this T obj) where T:Class
Will narrow it down a bit. If you need more than that you will need to assign a marker interface to all entities and use:
public static IDictionary<string, T> ToSerializable(this T obj) where T:IEntity

Categories

Resources