Serialize instance of a class deriving from DynamicObject class - c#

I have a class that derives from DynamicObject class. On calling JsonConvert.SertializeObject, none of the dynamic properties are serialized.
Class is defined as,
public class Component : DynamicObject
{
// The inner dictionary.
public Dictionary<string, object> dictionary
= new Dictionary<string, object>();
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember (
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember (
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
then i do this,
dynamic component = new Component();
component.test = "123";
JsonConvert.SerializeObject(component);

You need to override DynamicObject.GetDynamicMemberNames:
public override IEnumerable<string> GetDynamicMemberNames()
{
return dictionary.Keys;
}

Related

How to get a value of the property from the class inside of another class using reflection

I'm trying to come up with a solution to a serialization problem in my code which I described here:
After using XmlSerializer on the class, it loses some of the properties when returned back to the caller
So, I was thinking about creating another class that would extend MerchantWSBO with a properties in the subject and assign the value of the property I'm looking for from a MerchantWSVO class.
So, here is a new class definition:
public class MerchantTest: MerchantWSBO
{
private MerchantWSVO overviewField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true)]
public new MerchantWSVO overview
{
get
{
return this.overviewField;
}
set
{
this.overviewField = value;
}
}
public class MerchantWSVO
{
private System.Nullable<bool> discoverRetainedField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true)]
public System.Nullable<bool> discoverRetained
{
get
{
return this.discoverRetainedField;
}
set
{
this.discoverRetainedField = value;
}
}
}
}
Here is a part of existing classes(Those classes are coming as WebReferences from a 3rd party)
I have a class MerchantWSBO that has a property overviewField of a type MerchantWSVO:
public class MerchantWSBO
{
private MerchantWSVO overviewField;
public MerchantWSVO overview
{
get{return this.overviewField;}
set{this.overvieField = value;}
}
}
And I have a class describing the property of type MerchantWSVO:
public class MerchantWSVO
{
private System.Nullable<bool> discoverRetainedField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public System.Nullable<bool> discoverRetained
{
get {return this.discoverRetainedField;}
set {this.discoverRetainedField = value;}
}
}
In the following method I'm trying to get the value of the property I need and set it to a new class's property to see if the class won't loose any properties after the serialization.
This method receives an object as a parameter. This parameter can be of a type MerchantWSBO or another type:
private string ClassToXML(Object classObject)
{
MerchantWSVO test = new MerchantWSVO();
MerchantTest mt = new MerchantTest();
//here I'm trying to get the property's value
if(classObject is MerchantWSBO)
{
mt.overview.discoverRetained = //how to do it?
}
var myString = new System.IO.StringWriter();
var serializer1 = new XmlSerializer(test.GetType());
serializer1.Serialize(myString, test);
var serializer = new XmlSerializer(classObject.GetType());
serializer.Serialize(myString, classObject);
return myString.ToString();
}
What I'm looking for is I need to get a value of discoverRetained property from MerchantWSVO class from inside of above method either through a reflection or a different way.
I have another method where I assign values to MerchantWSBO and MerchantWSVO properties and all the properties have values before the serialization.
But after the serialization, the strung myString doesn't have all the properties defined as System.Nullable<bool>
What am I missing here

There is any way to create a class with the same behavior as dynamic or ExpandoObject?

I want to create a class with fixed properties and the capability to extend them as dynamic or ExpandoObject can.
e.g:
public class DynamicInstance : DynamicObject
{
public string FixedTestProperty { get; set; }
}
Usage:
DynamicInstance myCustomObj = new DynamicInstance();
myCustomObj.FixedTestProperty = "FixedTestValue";
myCustomObj.DynamicCreatedTestProperty = "Custom dynamic property value";
Finally if I serialize that class with json.net or something else output something like that:
{
FixedTestProperty: 'FixedTestValue',
DynamicCreatedTestProperty: 'Custom dynamic property value'
}
You need to inherit DynamicObject and override the TryGetMember and TrySetMember methods. Here is a class which has one property named One. However, you can add more to it dynamically.
public class ExpandOrNot : DynamicObject
{
public string One { get; set; }
// The inner dictionary.
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
Usage
dynamic exp = new ExpandOrNot { One = "1" };
exp.Two = "2";
More info here.
<== Fiddle Me ==>
This is possible using TrySetMember on DynamicObject.
The example at the bottom of this shows how to do it: https://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.trysetmember(v=vs.110).aspx

Which is better Params or List

My current code is following, it is a WCF service method exposed as a proxy to the client:
public UnifiedDTO GetAllCardTitle(string trainSymbolOrCarLocation,
DateTime startDate,
DateTime endDate,
string procedureName = CardTitle.procedureNameTrainRuns)
This method takes a procedure name (as the last parameter) and rest of the parameters are the binding the input parameters, however the issue is that we do not have the flexibility in the case of parameters numbers and types changing. The project is in its initial stage, so changes will surely be made.
The options that I have is convert the method as follows:
public UnifiedDTO GetAllCardTitle(params object [] parameters)
Where we have the freedom to pass the parameters and procedure details and can accordingly bind. However, there might be a performance issue due to boxing and unboxing. It would require client application to pass the parameters with correct order and value to bind as it would be expected by underlying layers
public UnifiedDTO GetAllCardTitle(List<Filter> parameter, string procedureName)
Where Parameter class would be defined as:
public class Filter
{
public string name { set; get; }
public string value { set; get; }
public string dataTypeID { set; get; }
public Filter(string _name, string _value, string _dataTypeID)
{
name = _name;
value = _value;
dataTypeID = _dataTypeID;
}
}
In this method for a given procedure, we bind each parameter with its name value and DataType, and it would need value to typecasted to the correct data type, it has more flexibility then last method and can be passed in any order, as binding is by name. However, it would need much more due diligence from the application.
Is there still a better way to take care of this situation using something new introduced in C#.Net?
None. Use Dynamic object instead
To create a C# class that works with the DLR, the easiest thing to do is derive from DynamicObject. One limitation arises when trying to use a dynamic type in a WCF service. Trying to use a DynamicObject-derived type will result in a runtime exception when trying to serialize with WCF’s DataContractSerializer.
[DataContract]
public class SerializableDynamicObject : IDynamicMetaObjectProvider
{
[DataMember]
private IDictionary<string,object> dynamicProperties = new Dictionary<string,object>();
#region IDynamicMetaObjectProvider implementation
public DynamicMetaObject GetMetaObject (Expression expression)
{
return new SerializableDynamicMetaObject(expression,
BindingRestrictions.GetInstanceRestriction(expression, this), this);
}
#endregion
#region Helper methods for dynamic meta object support
internal object setValue(string name, object value)
{
dynamicProperties.Add(name, value);
return value;
}
internal object getValue(string name)
{
object value;
if(!dynamicProperties.TryGetValue(name, out value)) {
value = null;
}
return value;
}
internal IEnumerable<string> getDynamicMemberNames()
{
return dynamicProperties.Keys;
}
#endregion
}
public class SerializableDynamicMetaObject : DynamicMetaObject
{
Type objType;
public SerializableDynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: base(expression, restrictions, value)
{
objType = value.GetType();
}
public override DynamicMetaObject BindGetMember (GetMemberBinder binder)
{
var self = this.Expression;
var dynObj = (SerializableDynamicObject)this.Value;
var keyExpr = Expression.Constant(binder.Name);
var getMethod = objType.GetMethod("getValue", BindingFlags.NonPublic | BindingFlags.Instance);
var target = Expression.Call(Expression.Convert(self, objType),
getMethod,
keyExpr);
return new DynamicMetaObject(target,
BindingRestrictions.GetTypeRestriction(self, objType));
}
public override DynamicMetaObject BindSetMember (SetMemberBinder binder, DynamicMetaObject value)
{
var self = this.Expression;
var keyExpr = Expression.Constant(binder.Name);
var valueExpr = Expression.Convert(value.Expression, typeof(object));
var setMethod = objType.GetMethod("setValue", BindingFlags.NonPublic | BindingFlags.Instance);
var target = Expression.Call(Expression.Convert(self, objType),
setMethod,
keyExpr,
valueExpr);
return new DynamicMetaObject(target,
BindingRestrictions.GetTypeRestriction(self, objType));
}
public override IEnumerable<string> GetDynamicMemberNames ()
{
var dynObj = (SerializableDynamicObject)this.Value;
return dynObj.getDynamicMemberNames();
}
}
One warning, dynamic members can be anything, meaning at runtime someone could assign a method to one of these fields. If this is possible in your application, you’ll need to ensure any methods assigned to the dynamic type are not serialized. I’m leaving this as an exercise for the reader.
Taken from Here
Is it possible to allow an "Interfaced" parameter. From that, you could handle multiple things based on the interfaced value setting. Just shooting out a simple sample.
public enum eWhatAmI
{
ListedObjects,
StringArrays,
Other
}
public interface IWhatParmType
{
eWhatAmI whatAmI { get; set; }
}
public class MyListVersion : IWhatParmType
{
public eWhatAmI whatAmI { get; set; }
public List<string> whatever { get; set; }
public MyListVersion()
{
whatAmI = eWhatAmI.ListedObjects;
whatever = new List<string>();
... build out list of strings
}
}
public class MyArrayVersion : IWhatParmType
{
public eWhatAmI whatAmI { get; set; }
public string[] whatever { get; set; }
public MyArrayVersion()
{
whatAmI = eWhatAmI.StringArrays;
... build out array of strings
}
}
etc...
Then in your process for handling whatever the incoming parameter is, you can handle either way.
public UnifiedDTO GetAllCardTitle(IWhatParmType parameter, string procedureName)
{
switch( parameter )
{
case (eWhatAmI.ListedObjects):
// Just for grins, test to make sure object really IS expected list version object
if( parameter is MyListVersion)
DoViaList( (MyListVersion)parameter );
break;
case (eWhatAmI.StringArrays ):
if( parameter is MyArrayVersion )
DoViaArray( (MyArrayVersion)parameter );
break;
}
}
private void DoViaList( MyListVersion parm1 )
{
.. do whatever based on the "List<string>" property
}
private void DoViaArray( MyArrayVersion parm1 )
{
.. do whatever based on the "string []" property
}
Then, if you ever needed to expand a setting per a particular object instance, you could and handle within the specific sub-handler method for populating or forcing whatever defaults to be implied.

Why when return interface in a web api method, I get the values of inherited class with interface values?

I have a class that inherited from an Interface , And I am returning interface from my web api get methed , The problem is I am getting values of the inherited class as json string.
This is the interface
public interface IFoo
{
string A { get ;set ; }
string B { get ; set ; }
}
Inherited Class
public class Child : iFoo
{
string A { get ; set ; }
string B { get ; set ; }
string C { get ; set ; }
string D { get ; set ; }
}
Then I return IFoo from my controller's GetMethod
public IFoo GetIFoo()
{
return ChildInstance ;
}
current result give me all the values of inherited class , and interface both but I want only values that are implemented in interface in json result.
By the time it hits the Json serializer, it doesn't care what the return type of the method was. All it knows is "I have this object, let's see what I can do with it".
If you want the serializer to only contain the properties that your interface has, you better give it an object that only has the properties that your interface has. You might consider using e.g. Automapper to copy values across from ChildInstance to this new object.
The alternative is more complex - implementing your own serializer so that the Json serializer doesn't get a chance to get involved.
Your method is contracted to return an object that implements IFoo. It can return any object that implements IFoo, but cannot return an Ifoo itself as you cannot have an instance of an interface. So it returns an instance of Child.
The JSON serializer is then given this instance of Child and uses reflection to work out it's properties. It finds A - D and so serializes them.
If you only want A - B serialised, then you'll have to return an instance of a class that only implements A - B.
Having said all that, if you are using ASP MVC, then check out http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx. By changing your class definition to
public class Child : iFoo
{
string A { get ; set ; }
string B { get ; set ; }
[ScriptIgnore]
string C { get ; set ; }
[ScriptIgnore]
string D { get ; set ; }
}
Then you have instructed the JSON serializer to only serialise A - B.
If you don't mind returning dynamic, you do something like this:
The flip side is that this only works out of the box if you use the json serializer, so you have to specify "accept: application/json" for it to work.
public class Person
{
public string Name { get; set; }
}
public class User : Person
{
public string Title { get; set; }
public string Email { get; set; }
}
public dynamic Get()
{
var user = new User { Title = "Developer", Email = "foo#bar.baz", Name = "MyName" };
return new { user.Name, user.Email };
}
You can also apply action filters to serialize only the interface properties if the return type of the controller method is an interface. This way you always stay in sync with your interface definition without having to change any attributes on the class implementing the interface.
For this you'd first have to create a custom InterfaceContractResolver contract resolver as explained here:
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _interfaceType;
public InterfaceContractResolver(Type interfaceType)
{
_interfaceType = interfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(_interfaceType, memberSerialization);
return properties;
}
}
Then add an action filter (either as an attribute as explained here or globally if you want this as a default behavior) that looks at the return type of the controller method and if it's an interface uses the contract resolver defined above:
public class InterfaceFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
if (content != null)
{
Type returnType = actionExecutedContext.ActionContext.ActionDescriptor.ReturnType;
if (returnType.IsInterface && content.Formatter is JsonMediaTypeFormatter)
{
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings =
{
ContractResolver = new InterfaceContractResolver(returnType)
}
};
actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, formatter);
}
}
}
}

Get value of field by string

I want to get the value of a field of an object by using a string as variable name.
I tried to do this with reflection:
myobject.GetType().GetProperty("Propertyname").GetValue(myobject, null);
This works perfectly but now I want to get the value of "sub-properties":
public class TestClass1
{
public string Name { get; set; }
public TestClass2 SubProperty = new TestClass2();
}
public class TestClass2
{
public string Address { get; set; }
}
Here I want to get the value Address from a object of TestClass1.
You already did everything you need to do, you just have to do it twice:
TestClass1 myobject = ...;
// get SubProperty from TestClass1
TestClass2 subproperty = (TestClass2) myobject.GetType()
.GetProperty("SubProperty")
.GetValue(myobject, null);
// get Address from TestClass2
string address = (string) subproperty.GetType()
.GetProperty("Address")
.GetValue(subproperty, null);
Your SubProperty member is actually a Field and not a Property, that is why you can not access it by using the GetProperty(string) method. In your current scenario, you should use the following class to first get the SubProperty field, and then the Address property.
This class will allow you to specify the return type of your property by closing the type T with the appropriate type. Then you will simply need to add to the first parameter the object whose members you are extracting. The second parameter is the name of the field you are extracting while the third parameter is the name of the property whose value you are trying to get.
class SubMember<T>
{
public T Value { get; set; }
public SubMember(object source, string field, string property)
{
var fieldValue = source.GetType()
.GetField(field)
.GetValue(source);
Value = (T)fieldValue.GetType()
.GetProperty(property)
.GetValue(fieldValue, null);
}
}
In order to get the desired value in your context, simply execute the following lines of code.
class Program
{
static void Main()
{
var t1 = new TestClass1();
Console.WriteLine(new SubMember<string>(t1, "SubProperty", "Address").Value);
}
}
This will give you the value contained in the Address property. Just make sure you first add a value to the said property.
But should you actually want to change the field of your class into a property, then you should make the following change to the original SubMember class.
class SubMemberModified<T>
{
public T Value { get; set; }
public SubMemberModified(object source, string property1, string property2)
{
var propertyValue = source.GetType()
.GetProperty(property1)
.GetValue(source, null);
Value = (T)propertyValue.GetType()
.GetProperty(property2)
.GetValue(propertyValue, null);
}
}
This class will now allow you to extract the property from your initial class, and get the value from the second property, which is extracted from the first property.
try
myobject.GetType().GetProperty("SubProperty").GetValue(myobject, null)
.GetType().GetProperty("Address")
.GetValue(myobject.GetType().GetProperty("SubProperty").GetValue(myobject, null), null);

Categories