0

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.

Jashaszun
  • 9,207
  • 3
  • 29
  • 57
DDA
  • 991
  • 10
  • 28

1 Answers1

2

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.

esskar
  • 10,638
  • 3
  • 36
  • 57