16

My current project is using the IDesign architecture, so all of my layers are services. I wanted to have my Read method in the CRUD of my resource access layer take a predicate in the form of a lambda expression as well as a list of related objects to pull. This way the resource access layer will be very generic.

[OperationContract]
Result<MyObject> ReadObjects(Func<MyObject, bool> predicate, string[] includes);

Now I have come to discover something that should have been obvious, and that is that I cannot serialize lambda expressions. I looked into parsing a string into a lambda expression, but that is a no go as well.

Is there any method that I can use to pass a lambda expression to a service? Is there a better way to do what I am trying to do?

Alec
  • 1,646
  • 3
  • 19
  • 35
  • 15
    Do you really want your web service to accept executable code, in any form, shape, or color? I would consider the security aspects of this approach. – Lasse V. Karlsen Jun 22 '11 at 16:44
  • 2
    At best you could probably get it to accept a serialized version of an Expression, but not a lambda, lambda is a method pointer, an expression is a representation of something that can be compiled, analyzed, etc. But again, I would consider the security aspects here. In my opinion, this is right up there with passing SQL as part of the query string to a web application. – Lasse V. Karlsen Jun 22 '11 at 16:48
  • This service will not be exposed, it is used in a higher layer of the architecture. And I believe I read that Expressions cannot be serialized either, at least not without significant difficulty. – Alec Jun 22 '11 at 16:48
  • There isn't anything inherently wrong with this imo as long as you're aware of the risks and they are permissible in your deployment situation. If your service is for internal use only or something I don't see it being a problem. Necessarily. – Joshua Evensen Jun 22 '11 at 16:50
  • 2
    Lambdas cannot be serialized, they are already compiled as executable code, ie. they're a method pointer to executable code. An expression, at least you have a fighting chance with that but it isn't easy with that either. Possible, not easy. With a lambda, you would have to decompile the code, and pass the IL to the server, and that wouldn't necessarily work in that context. – Lasse V. Karlsen Jun 22 '11 at 16:51
  • Yeah I know I can't serialize lamdas, and the only thing I have found remotely close to serializing Expressions is this: http://archive.msdn.microsoft.com/exprserialization. Also, am I correct in thinking that since this service is not exposed this is not a security issue? – Alec Jun 22 '11 at 16:54
  • 1
    @OpticalDelusion: The key question is "not exposed to who?" What you need to do to answer the question of security is to build a *threat model*. That is, diagram all the different components in your system and then determine what the "trust boundaries" are between those components. Then ask yourself "what resources are being protected by each component?" and "how can an attacker compromise a protected resource at every boundary?" If there is no way for a dangerous system to be lured into attacking a resource by an attacker outside of the boundary, then you're good. – Eric Lippert Jun 22 '11 at 17:12
  • *My current project is using the IDesign architecture, so all of my layers are services.* Services should be used when they are needed and they should encapsulate some logic so be aware to not over architecture your application. Any remote call is damn expensive. – Ladislav Mrnka Jun 22 '11 at 19:55
  • Juval has done benchmark testing which has shown that the IDesign architecture still results in performance that is more than acceptable for the average business application. Also, this project is also a learning experience so while it is not needed, it is good to try at a lower level before I actually do need it. Further, the services do encapsulate logic. The services have a lot more to them but I try to generalize my question in order to get a more useful answer in terms of concept and also an answer that can potentially be used by someone else who later sees it. – Alec Jun 22 '11 at 20:19

6 Answers6

25

We have to solve this problem in LINQ-to-Just-About-Everything. For example, when doing LINQ-to-SQL:

var results = from c in customers where c.City == "London" select c.Name;

somehow the content of the lambdas c=>c.City == "London" and c=>c.Name need to end up on the SQL server in a form the server understands. Clearly we cannot persist the lambdas to the server.

Instead what we do is turn the lambdas into Expression Trees, analyze the expression trees at runtime, build an actual string of SQL out of it, and send that string to the server for processing.

You can do the same thing. Create a query language for your server. On the client side, turn the lambdas into expression trees. Analyze them at runtime, turn the result into a string in your query language, and then send the query to the service.

If you're interested in how this works in LINQ, the LINQ-to-SQL architect Matt Warren has written a long series of blog articles on how to do it yourself:

http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
6

Perhaps a dynamic query would work in your situation?

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

You would pass a where clause string to the service which would validate and convert it to an expression

Jason Miesionczek
  • 14,268
  • 17
  • 76
  • 108
4

WCF doesn't offer this out of the box. You would essentially have to write a custom serializer that took lambda expressions and turned the expression tree into a serializable piece of data.

This is how WCF DataServices works. You use lambdas in your client code, it decomposes those lambda expressions into strings which it passes on the querystring to the data service which then turns the string back into a lambda which it applies to a IQueryable on the server side.

Doable, but you will have to to write a lot of custom serialization code for this. Also, let's be clear, these would be lamdba expressions, not full lambda methods containing random code that could ever be executed on the server side.

Drew Marsh
  • 33,111
  • 3
  • 82
  • 100
0

I found a project open source in codeplex is solution of this problem as subject

Expression Tree Serializer

Project Description a .NET 4.0 and Silverlight 4 class library that serializes and deserializes Expression instances. Also: a WCF IQueryable LINQ Provider and Web Http (REST) client for Silverlight that provides a simplified REST client API (i.e. WCF's WebChannelFactory) that's easier to use than WebClient.

on this link

http://expressiontree.codeplex.com/

Hicham
  • 129
  • 2
  • 12
0

I use this library on CodePlex to serialize/deserialize Expression trees (but its previous version), and it does the work.

There are also some other similar questions here like this one: Serializing and Deserializing Expression Trees in C#

Community
  • 1
  • 1
Kamarey
  • 10,832
  • 7
  • 57
  • 70
0

Create a Query Object and pass it to your services.

See if this helps:

http://ruijarimba.wordpress.com/2011/05/09/entity-framework-and-t4-generate-query-objects-on-the-fly-part-1/

An example:

var search = new AlbumSearch();
search.PriceFrom = 5;
search.PriceTo = 10;
search.Artist = new ArtistSearch(){ Name = "Metallica" };
search.Genre = new GenreSearch(){ NameContains = "Metal" };

var albuns = from x in repository.All<Album>(search.GetExpression())
                  select x;
Rui Jarimba
  • 11,166
  • 11
  • 56
  • 86