Donald N. Mafa
Donald N. Mafa

Reputation: 5283

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?

Upvotes: 1

Views: 463

Answers (2)

Robert Harvey
Robert Harvey

Reputation: 180908

For your particular scenario, it would be simpler (and probably more secure) to just pass the WHERE condition as a string and use dynamic linq on the server.

 using System.Linq.Dynamic;

 public virtual IEnumerable<Person> Get(string condition)
    {
        using (var ctx = MyContext())
        {
            return = ctx.DbContext.People.Where(condition).ToList();
        }
    }

More info here: Using the LINQ Dynamic Query Library

Upvotes: 3

Rabban
Rabban

Reputation: 2581

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>();

Upvotes: 4

Related Questions