Limiting extension method to target EF Entities only - c#

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

Related

C# recursively check all values not null

Without wanting to reinvent the wheel, is there a .NET NuGet library to perform checks on a object recursively for argument checking?
If not, how would I convert the code to check if a property is null, and if a type that can hold properties of its own, recursively check that type, and end up with a list of property names that are null.
public static class Assert
{
public static void AllPropertiesNotNull<T>(T obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
var emptyProperties = typeof(T)
.GetProperties()
.Select(prop => new { Prop = prop, Val = prop.GetValue(obj, null) })
.Where(val => IsEmpty((dynamic)val.Val))
.Select(val => val.Prop.Name)
.ToList();
if (emptyProperties.Count > 0)
throw new ArgumentNullException(emptyProperties.First());
}
private static bool IsEmpty(object o) { return o == null; }
}
Note: You should do null checking on constructor parameters or method parameters and throw exception when the parameter is unexpectedly null. It's better to follow the common best practices.
Anyway, here is an example showing how you can check all properties of an object recursively using an extension method and throw exception of finding null properties...
You can create an extension method ThrowOnNullProperty for object and use it like this:
something.ThrowOnNullProperty();
Here is an implementation of such extension method:
If the passed object is null, throw exception.
If the object is a primitive type or a string, continue.
If the object has been visited before, then continue, otherwise add it to list of visited objects.
Check first level properties of the object and if there are null properties, throw an exception containing name of the null properties.
If the first level properties are not null, the for each property value go to 1.
Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
public static class ObjectExtensions
{
public static void ThrowOnNullProperty(this object obj)
{
ThrowOnNullProperty(obj, new HashSet<object>());
}
private static void ThrowOnNullProperty(object obj, HashSet<object> visitedObjects)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
if (obj.GetType().IsPrimitive || obj.GetType() == typeof(string))
return;
if (visitedObjects.Contains(obj))
return;
visitedObjects.Add(obj);
var nullPropertyNames = obj.GetType().GetProperties()
.Where(p => p.GetValue(obj) == null)
.Select(p => p.Name);
if (nullPropertyNames.Any())
throw new ArgumentException(
$"Null properties: {string.Join(",", nullPropertyNames)}");
var notNullPropertyValues = obj.GetType().GetProperties()
.Select(p => p.GetValue(obj))
.Where(v => v != null);
foreach (var item in notNullPropertyValues)
ThrowOnNullProperty(item, visitedObjects);
}
}
To do so, write a method to check the properties of current object and call it recursively on the non-null properties. I went ahead and wrote some code, which includes looping over dictionaries and enumerables and checking them for nulls also, taking into account circular references as mentioned by #dcg.
static readonly HashSet<Type> excludedTypes = new HashSet<Type>{ typeof(string) };
public static List<string> AllPropertiesNotNull(IDictionary dictionary, string name, HashSet<object> alreadyChecked)
{
List<string> nullValues = new List<string>();
foreach(object key in dictionary.Keys)
{
object obj = dictionary[key];
if (!alreadyChecked.Contains(obj))
{
string elementName = $"{name}[\"{key}\"]";
nullValues.AddRange(AllPropertiesNotNull(obj, elementName, alreadyChecked));
}
}
return nullValues;
}
public static List<string> AllPropertiesNotNull(IEnumerable enumerable, string name, HashSet<object> alreadyChecked)
{
List<string> nullValues = new List<string>();
int i = 0;
foreach (object obj in enumerable)
{
if (!alreadyChecked.Contains(obj))
{
string elementName = $"{name}[{i}]";
nullValues.AddRange(AllPropertiesNotNull(obj, elementName, alreadyChecked));
}
i++;
}
return nullValues;
}
public static List<string> AllPropertiesNotNull(object obj, string name, HashSet<object> alreadyChecked, string baseName = "")
{
List<string> nullValues = new List<string>();
string basePropertyName;
if (string.IsNullOrEmpty(baseName))
{
basePropertyName = name;
}
else
{
basePropertyName = baseName + "." + name;
}
if (obj == null)
{
nullValues.Add(basePropertyName);
}
else if (!alreadyChecked.Contains(obj))
{
alreadyChecked.Add(obj);
if (!excludedTypes.Contains(obj.GetType()))
{
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
object value = property.GetValue(obj);
string propertyName = basePropertyName + "." + property.Name;
if (value == null)
{
nullValues.Add(propertyName);
}
else
{
if (typeof(IDictionary).IsAssignableFrom(property.PropertyType))
{
nullValues.AddRange(AllPropertiesNotNull((IDictionary)value, propertyName, alreadyChecked));
}
else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
nullValues.AddRange(AllPropertiesNotNull((IEnumerable)value, propertyName, alreadyChecked));
}
else
{
nullValues.AddRange(AllPropertiesNotNull(value, property.Name, alreadyChecked, basePropertyName));
}
}
}
}
}
return nullValues;
}
I wrote some classes to test with:
class A
{
public string s1 { set; get; }
public string s2 { set; get; }
public int i1 { set; get; }
public int? i2 { set; get; }
public B b1 { set; get; }
public B b2 { set; get; }
}
class B
{
public string s1 { set; get; }
public string s2 { set; get; }
public int i1 { set; get; }
public int? i2 { set; get; }
public A a1 { set; get; }
public Dictionary<int, string> d1 { set; get; }
public List<A> l1 { set; get; }
}
and tested it as follows:
A a = new A
{
s1 = "someText"
};
B b = new B
{
s1 = "someText",
a1 = a,
d1 = new Dictionary<int, string>
{
{ 1, "someText" },
{ 2, null }
},
l1 = new List<A>{ null, new A { s1 = "someText" } , a }
};
a.b1 = b;
Console.WriteLine(string.Join("\n", AllPropertiesNotNull(a, nameof(a), new HashSet<object>())));
Output:
a.s2
a.i2
a.b1.s2
a.b1.i2
a.b1.d1["2"]
a.b1.l1[0]
a.b1.l1[1].s2
a.b1.l1[1].i2
a.b1.l1[1].b1
a.b1.l1[1].b2
a.b2
Few points to take note of:
Only public properties are considered, use BindingFlags if you want to consider non-public ones.
Some types might need to be individually considered (e.g.: string) or maybe not (depending on your own case).
As mentioned before, the code loops on dictionaries and enumerables and checks every value for them too. You might or might not want that (depending on your own case).

How do I detect an ExpandoObject vs a Dynamic Object?

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);
}

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());

Converting Flat file to List which is a property of another class

public class DummyResponse
{
public int UpdatedRecords { get; set; }
public string Id { get; set; }
public bool Isvalid { get; set; }
}
public class Request
{
public List<DummyResponse> Changes { get; set; }
public string ReuestedBy { get; set; }
public Request()
{
Changes = new List<DummyResponse>();
}
}
I have a flat file which contains tab separated data for Dummy Response.
I want this to be serialized to Request object.
The implementation needs should be generic as in I only need user to pass T (Request) in this case and identify the correct sub type to be filled from flat file.
I have below Code to convert it into Object. How ever its only working for properties having string type.
interface ICollectionBuilder
{
object Build(IList dictionaries);
}
internal class CollectionBuilder<T> : ICollectionBuilder where T : new()
{
public object Build(IList dictionaries)
{
var dictConverter = new DictionaryConerter<T>();
return dictionaries
.OfType<IDictionary<string, object>>()
.Select(dict => dictConverter.ConvertTyped(dict))
.ToList();
}
}
interface IDictionaryConverter
{
object Convert(IDictionary<string, object> dict);
}
internal class DictionaryConerter<T> : IDictionaryConverter where T : new()
{
public object Convert(IDictionary<string, object> dict)
{
return ConvertTyped(dict);
}
public T ConvertTyped(IDictionary<string, object> dict)
{
T t = new T();
var properties = t.GetType().GetProperties();
foreach (KeyValuePair<string, object> curr in dict)
{
if (String.IsNullOrEmpty(curr.Key)) continue;
if (curr.Value == null) continue;
Type valType = null;
Type newType = null;
PropertyInfo currProperty = null;
foreach (PropertyInfo p in properties)
{
if (String.IsNullOrEmpty(p.Name)) continue;
if (String.Compare(p.Name.ToLower(), curr.Key.ToLower()) == 0)
{
valType = t.GetType().GetProperty(p.Name).PropertyType;
newType = Nullable.GetUnderlyingType(valType) ?? valType;
currProperty = p;
break;
}
}
object newVal = curr.Value;
var curDict = curr.Value as IDictionary<string, object>;
var curList = curr.Value as IList;
if (curDict != null && newType.GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((IDictionaryConverter)Activator.CreateInstance(typeof(DictionaryConerter<>).MakeGenericType(newType))).Convert(curDict);
}
else if (
curList != null &&
curList.OfType<IDictionary<string, object>>().Any() &&
newType.IsGenericType &&
newType.GetGenericTypeDefinition() == typeof(List<>) &&
newType.GetGenericArguments()[0].GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((ICollectionBuilder)Activator.CreateInstance(typeof(CollectionBuilder<>).MakeGenericType(newType.GetGenericArguments()[0]))).Build(curList);
}
t.GetType().GetProperty(currProperty.Name).SetValue(t, newVal);
}
return t;
}
}
Example usage:
void Main ()
{
var dict = new Dictionary<string,object>();
dict.Add("ReuestedBy",abc);
var innerDict = new Dictionary<string,object>();
var list = new LIst<Dictionary<string,object>>();
innerDict.Add("UpdatedRecords","45");
innerDict.Add("Id","1");
innerDict.Add("IsValid","False");
dict.Add("Changes",list )
}
The problem here is it not working for any other type other than string.
I fixed it using below code while setting value
propertyVal = Convert.ChangeType(propertyVal, targetType);
propertyInfo.SetValue(inputObject, propertyVal, null);

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>;
}
}

Categories

Resources