Search code examples
c#wcfserializationexpressionfunc

How to work with Expression Trees not working using WCF since they are not serializable?


I have a 4 layered architecture project, i.e. UserInterface, BusinessLogic, Service (WCF) and DataAccess (EF6) layers. I have exposed methods on my service that accept an expression which I can pass to my data access layer to be evaluated using EF. However, this does not work because the Expression<Func> is not serializable.

On my client end I want to be able to build queryable expressions to send to the server side and return the correct projection.

Server Side:

public virtual IEnumerable<Person> Get(Expression<Func<Person, bool>> expression)
{
            using (var ctx = MyContext())
            {
                IQueryable<PersonDto> col = ctx.DbContext.People.Where(expression);
                //
                return col.ToList();
            }
}

Client side:

public IEnumerable<PersonDto> GetFromService(Expression<Func<PersonDto, bool>> expression)
{
    using (MyService client = new MyService())
    {
        return client.Get(expression);
    }
}

Is there an alternative to the way I'm doing this? And is there a reason why expressions and funcs are not serializable?


Solution

  • You can use Remote.Linq for this. The Project is currently hosted on GitHub, but it seems that there is no documentation. But you can use the old one from CodePlex.

    The easiest way to achieve this (Code copied from the old documentation)

    // create linq expression
    System.Linq.Expressions.Expression<Func<Order, bool>> linqExpression =
        order => order.Items.Where(i => i.ProductId == prodId).Sum(i => i.Quantity) > 1;
    
    // transform linq expression into serializable expression tree
    Remote.Linq.Expressions.LambdaExpression serializableExpression =
        linqExpression.ToRemoteLinqExpression();
    
    // transform serializable expression tree back into linq expression
    System.Linq.Expressions.Expression<Func<Order, bool>> recreatedLinqExpression =
        serializableExpression.ToLinqExpression<Order, bool>();