I am working on a project which requires to work with dynamic objects with BreezeSharp. I am receiving the structure of my objects via a JSON file such as:
[{
name: 'Admin',
serviceAddress: 'http://abcd.com/breeze/admins',
dataProperties: {
Id: { type: breeze.DataType.Int32 },
Title: { nullable: true },
ContentTypeId: {},
Created: { type: breeze.DataType.DateTime },
Modified: { type: breeze.DataType.DateTime },
File: { complexType: 'Document:#File' },
},
{
name: 'Car',
serviceAddress: 'http://abcd.com/breeze/cars',
dataProperties: {
Id: { type: breeze.DataType.Int32 },
Model: { nullable: true },
Created: { type: breeze.DataType.DateTime },
Modified: { type: breeze.DataType.DateTime },
}]
and I want to auto generate objects which inherits from Breeze.Sharp.BaseEntity with the properties listed.
I will also have to create the breeze entity manager after the dynamic object has been created.
The reason why I need this is because I have a SharePoint app which uses BreezeJS. The entities are based of a JSON file over there.
So I want to create a Desktop app which would be using the same entities based of the JSON file. I am not sure it is possible to create dynamic objects which inherit the BaseEntity class.
yes, this is possible, but you need to put some work and code into it. Here is the idea (untested):
Create a class that inherits from BaseEntity
and implements IDynamicMetaObjectProvider.
Then you need to build functions that convert your function definitions to dynamic properties:
public class DynamicBreezeEntity : BaseEntity, IDynamicMetaObjectProvider
{
private readonly Dictionary<string, PropertyDefinition> _properties;
public DynamicBreezeEntity ()
{
_properties = new Dictionary<string, PropertyDefinition>();
}
public void DefineProperty(string name, Type type, bool isNullable = false)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
if (_properties.ContainsKey(name))
throw new ArgumentException("Property already defined.", "name");
if (type == null)
throw new ArgumentNullException("type");
if (isNullable && !type.IsValueType)
throw new ArgumentException("Only value types can be nullable.", "type");
if (isNullable)
{
type = Nullable.GetUnderlyingType(type);
if (type.IsValueType)
type = typeof(Nullable<>).MakeGenericType(type);
}
_properties.Add(name, new PropertyDefinition { Type = type });
}
public object GetValue(string name)
{
PropertyDefinition def;
if (_properties.TryGetValue(name, out def))
return def.Value;
throw new ArgumentException("Property not defined.", "name");
}
public void SetValue(string name, object value)
{
// more work todo here: handle value == null correctly
PropertyDefinition def;
if (_properties.TryGetValue(name, out def) && def.Type.IsAssignableFrom(value.GetType()))
def.Value = value;
throw new ArgumentException("Property not defined.", "name");
}
public IEnumerable<string> GetPropertyNames()
{
return _properties.Keys.ToList();
}
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
{
return new Proxy(this);
}
private class PropertyDefinition
{
public Type Type { get; set; }
public object Value { get; set; }
}
private class Proxy : DynamicMetaObject
{
public Proxy(DynamicBreezeEntity host, Expression expression)
: this(host, expression, BindingRestrictions.Empty) { }
public Proxy(DynamicBreezeEntity host, Expression expression, BindingRestrictions restrictions)
: base(expressiom restrictions, host) { }
private DynamicBreezeEntity Host
{
get { return (DynamicBreezeEntity)Value; }
}
private BindingRestrictions GetBindingRestrictions()
{
var restrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType);
return restrictions.Merge(BindingRestrictions.GetInstanceRestriction(this.Expression, this.Host));
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return this.Host.GetPropertyNames();
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var arguments = new Expression[] { Expression.Constant(binder.Name) };
var method = typeof(DynamicBreezeEntity).GetMethod("GetValue");
var callExpression = Expression.Convert(Expression.Call(Expression.Convert(this.Expressiom, this.LimitType), method, arguments), binder.ReturnType);
return new DynamicMetaObject(callExpression, GetBindingRestrictions());
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
var arguments = new Expression[] {
Expression.Constant(binder.Name),
Expression.Convert(value.Expression, typeof(object))
};
var method = typeof(DynamicBreezeEntity).GetMethod("SetValue");
return new DynamicMetaObject(
Expression.Call(Expression.Convert(this.Expression, this.LimitType), method, arguments),
this.GetBindingRestrictions()
);
}
}
}
I do not know Breeze, BaseEntity
may has abstract properties/methods that you need to implement. I did not focus on that.
You can use now as
var breeze = new DynamicBreezeEntity();
breeze.DefineProperty("Id", typeof(Int32));
dynamic dynBreeze = breeze;
dynBreeze.Id = "Foo";
Console.WriteLine("Id: {0}", dynBreeze.Id);
Code is probably not complete (have no VS access at the moment), but should point you in the right direction.