This project has moved and is read-only. For the latest updates, please go here.

lazy variable and Remote.Linq repository

Nov 28, 2015 at 1:59 AM
If I use WCF to send through and object which contains a lazy variable it works fine, but if I use the RemoteRepository with the WCF endpoint which returns the DynamicObject, it seems like it is not passing through.

I tried with an object like this:
public class MyClass
    {
        public string Name { get; set; }
        protected Lazy<int> HashCode;

        public MyClass()
        {
            ResetLazyHash();
        }

        protected void ResetLazyHash()
        {
            HashCode = new Lazy<int>(CalcHashCode);
        }

        private int CalcHashCode()
        {
            return Name.GetHashCode() * 31;
        }
    }
Feb 15, 2016 at 10:54 PM
Edited Feb 15, 2016 at 10:58 PM
There is an issue converting Lazy values into DynamicObjects and back using default DynamicObjectMapper.

You can overcome this limitation using a custom mapper as following:
public class CustomMapper : DynamicObjectMapper
{
    protected override DynamicObject MapToDynamicObjectGraph(object obj, Func<Type, bool> setTypeInformation)
    {
        if (!ReferenceEquals(null, obj))
        {
            var type = obj.GetType();
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>))
            {
                var value = type.GetProperty("Value").GetValue(obj);
                return MapToDynamicObjectGraph(value, setTypeInformation);
            }
        }

        return base.MapToDynamicObjectGraph(obj, setTypeInformation);
    }

    protected override object MapFromDynamicObjectGraph(object obj, Type targetType)
    {
        if (obj is DynamicObject && !ReferenceEquals(null, targetType) && targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Lazy<>))
        {
            var valueType = targetType.GetGenericArguments()[0];
            var value = ((DynamicObject)obj).Values.Single();
            var func = typeof(CustomMapper)
                .GetMethod("CreateFunc", BindingFlags.Static | BindingFlags.NonPublic)
                .MakeGenericMethod(valueType)
                .Invoke(null, new[] { value });
            return Activator.CreateInstance(targetType, func);
        }

        return base.MapFromDynamicObjectGraph(obj, targetType);
    }

    private static Func<T> CreateFunc<T>(T value)
    {
        return () => value;
    }
}
And then pass an instance of this mapper when executing the query expression on server side:
public IEnumerable<DynamicObject> ExecuteQuery(Expression queryExpression)
{
    return queryExpression.Execute(_queryableResourceProvider, mapper: new CustomMapper());
}
...and when creating the queryable in your RemoteRepository on client side:
public IQueryable<T> TQueryable 
{
    get
    {
        return RemoteQueryable.Create<T>(dataProvider, mapper: new CustomMapper()); 
    } 
}