Idea: LINQ to SOAP to LINQ Again
Recently I have become a huge fan of LINQ, and have been doing a little work to extend LINQ which I hope to announce soon. It’s not the SQL server integration of LINQ to SQL that interests me, but the elegance of it: developers simply express a need for information, and the system can decide how best to fulfil it.
The Web Service Divide
One thing that I look forward to seeing is how LINQ will fit into typical multi-tier architectures:
In a scenario like the one above, we might use LINQ behind the Web Service to deal with our objects and databases. But can it be used from the Windows App? I’m not so sure. As you’re probably aware, the contracts exposed by web services are generally very “constrained”; for example:
Guid[] GetCustomerIDsInState(string state); BankAccount[] GetBankAccounts(Guid customerId);
Now, let’s say the Windows Application wanted to list all overdrawn bank accounts. On the server, the query could be expressed like this:
BankAccount[] overdrawnAccounts =
from account in AllBankAccounts
where account.Balance < 0
select account;
However, since they are using web services, they would be forced to write code that involves a number of service calls as well as client side processing:
foreach (Guid id in bankProxy.GetCustomersInState(”NSW”))
{
foreach (BankAccount account in
bankProxy.GetBankAccounts(customerId))
{
if (account.Balance < 0)
{
// Show the account
}
}
}
Or, alternatively:
BankAccount[] overdrawnAccounts =
from customerID in bankProxy.GetCustomerIDsInState(”NSW”)
from account in bankProxy.GetAccounts(customerID)
where account.Balance < 0
select account;
Which is still going to involve many service calls. So, for efficiency, we’d probably have to push that query logic down behind the web services:
Guid[] GetCustomerIDsInState(string state); BankAccount[] GetBankAccounts(Guid customerId); BankAccount[] GetOverdrawnAccountsInState(string state);
This begs the question: in a multi-tier architecture, can LINQ be used on the client side?
TFS versus CRM
Web Services (including WCF, and even REST services) are usually very constrained in their operations. While this gives extra control to the people defining the services, if the services provided aren’t very well-thought-out, it can leave the client performing some very inefficient actions. The Team Foundation Server services are a good example of this.
Most TFS information is available just from one service call, but if you wanted to, say, get a list of all running builds, in all build types, in all Team Projects, you’d be in for a very chatty experience.
Get list of team projects (service call, perhaps 10 results)
Get list of builds types (service call, perhaps 3 results per project)
Get build detail list (service call, perhaps 30 builds per build type)
if build.State == "Running"
display
Given that there is only likely to be, at most, a handful of builds running at once, we must ask why it takes so many web service calls to find them.
Microsoft CRM, on the other hand, provides a very different experience. CRM offers regular web service calls, but it also provides an ability to write very powerful queries, known as FetchXML. For example, you could make a web service call to CRM passing the following XML:
<fetch mapping='logical'>
<entity name='account'>
<attribute name="accountid" />
<filter type='and'>
<condition
attribute='createdon'
operator='on-or-before'
value='2007-10-17'
/>
</filter>
</entity>
</fetch>
This query would fetch the ID’s for any Accounts which were created on or before the 17th of October. Behind the web services, CRM transforms this into an SQL query and sends the results back as XML which you can then parse into objects. This is much more efficient, but as you can imagine, it would have taken a lot of work to implement. Although CRM’s FetchXML works over Web Services, it is very much a custom format.
(It strikes me that a LINQ to FetchXML adapter would be a fun project)
Web Service Queries
If we want to make efficient use of LINQ on all sides of the web service divide, it’s important to allow the client to write queries against the server, much like FetchXML allows us to do. But how can we do this in a way where we don’t have to come up with our own querying language?
I think the answer involves changing the way we think about web services.
The Team Foundation Server service layer says:
“Here is a list of operations you may perform.”
Whilst the CRM service layer says:
“Here is a list of abstract entities, and the operations that can be performed against them”
Note that this doesn’t make the web service layer any less of an “insulator” than in the first example. To illustrate, if you look at the CRM database schema, you’ll find that it looks quite different to the abstract “entities” that CRM exposes for querying. A translation layer sits in between to provide the abstraction necessary to protect the web service implementation from becoming coupled with the client.
Once our web services define entities and the operations that are valid upon them, it would be fairly easy to build a LINQ query provider to turn object queries into a SOAP web service call, and on the other end, to turn them back into object expressions which can then be executed on the server.
For example, the developer on the client side might write:
BankAccount[] overdrawnAccounts =
from account in bankProxy.Accounts
where account.Balance < 0
select account;
Which the LINQ query provider translates into:
<Query>
<MethodCallExpression Method="Select“>
<MethodCallExpression.Operators>
<ConstantExpression Name=”account” />
<MethodCallExpression Method=”Where“>
<MethodCallExpression.Operators>
<ConstantExpression Name=”account” />
<LambdaExpression>
<LambdaExpression.Operator>
<MemberExpression Name=”Balance” />
</LambdaExpression.Operator>
<LambdaExpression.Operand>
LessThan
</LambdaExpression.Operand>
<LambdaExpression.Value>
0
</LambdaExpression.Value>
</LambdaExpression>
</MethodCallExpression.Operators>
</MethodCallExpression>
</MethodCallExpression.Operators>
</MethodCallExpression>
</Query>
And on the web service side, the technology that provides the abstraction over turning objects to and from XML (ASP.NET or WCF) could turn the query back into an object expression to be executed.
(Of course, the serialized query would probably look quite different to the above - in fact, what I wrote above probably made no sense, but you get the idea)
Security
Executing arbitrary code from a client on the server would never be a smart thing to do, but that’s not quite what I’m proposing here.
In LINQ to SQL, for example, some expressions such as customerName.StartsWith("P"), can be translated into SQL (where CustomerName LIKE 'P%'), and the LINQ to SQL query provider is smart enough to figure this out. However, other expressions, such as File.Delete("blah.txt"), which could legally be placed within a call to a LINQ query, can’t be translated into SQL. LINQ to SQL executes as much of the query as it can on the SQL server, and is smart enough to recognize the things it can’t translate, and executes them using .NET code back on the client.
The same thing would happen with queryable web services. The WSDL provided by the web service would define entities and any operations that are valid to be executed on the server, and any part of the query that isn’t allowed to be called on the server could be executed on the client.
Summary
I am really just throwing this idea out there to see if there is interest. To summarise, what I’m proposing is:
- LINQ, and querying in general, should be usable from both the client side and the server side of a system
- We come up with a standard XML syntax around defining entities and expressing method calls upon them. Essentially, a serialized LINQ Expression Tree.
- We make use of LINQ query providers to convert to and from the XML transport mechanism.
The benefits:
- Implementing services is easier - we don’t have to imagine all the common operations that people might perform
- Consuming services is easier, and leads to a much less “chatty” use of the services
What do you think? If such a system were built into the .NET framework, do you think you would design your Web Service endpoints around it?
Technorati tags: linq, query provider, soap, wsdl, linq-to-soap-to-linq
Filed under: Web Services, WCF

I agree that LINQ is of limited value against conventional web services, but in providing a query language like you describe.
I guess we would just have to be careful not to go down the “loosey goosey” antipattern path, where a method takes an XmlDocument and returns an XmlDocument, with no fixed contract.
Making the method return an array of the entity in question takes care of the return type … but how do we go about ensuring that the query passed to the web service conforms to the language we expect? XML schemata? Or maybe an class that represents expression-tree syntax similar to the way LINQ itself builds expression trees from lamda expressions.
Good to see you posting again, anyway, Paul. Look forward to hearing more of your thoughts on LINQ.
Matt
… and after posting a lengthy comment, I read a bit further and find that you are, in fact, proposing that we come up with a “serializable expression tree” class.
I like the idea a lot.
Hi Matt,
Yep. Although, it would be nice to go futher than serializing a LINQ expression tree, and to actually standardize “object queries” so they can be used and consumed from any language/platform. They could be bolted on top of standard Web Services - perhaps as a WS-* secificiation or just extensions to SOAP. Who knows, maybe SOAP/WSDL can already do this
I like the term “Loosey Goosey”
Paul
It’d still come down to expression trees in one form or another. If you had a bunch of classes representing expressions (unary and binary), and the operands of these expressions (constants and “variables” or “field references”) then it should be possible to convert a serialized class to any kind of query.
I could pass this into my web service:
new Field(”Balance”).IsLessThan(0)
So I end up with a ComparisonExpression object, whose left side is a FieldReference object, whose operator is “= x))
True
(I’ve hard-coded “y” to mean 5 and “x” to mean 3 in my “Reference” object.)
Damn - the angle brackets in my last comment corrupted it completely.
Drop me an email, Paul. I’d love to explore this some more.
Emailed
[…] LINQ to SOAP to LINQ Again […]
Hi Paul,
Me and a bunch of collegues just came up with the same idea. We would like to create a (ideally) platform-independent object-oriented way of quering - well, anything if possible.
We got some inspiration from Fowler’s Specificiation pattern, do you know this? It’s also more or less what you’re doing with validation in domain classes.
Maybe we could join some effort in an open source project?
Greetings,
André Boonzaaijer
Have you seen Astoria that Microsoft’s got under development, it uses URL’s to express a query for returning data over HTTP.
This example call made me think of LINQ and your post…
http://myserver/data.svc/Customers?$skip=30&$take=10
Cheers,
Graham
I’ve been desperate (yes, desperate) for this exact solution for several months now.
The problem right now is that all of the IQueryable extension methods take your Expressions and wrap them in a MethodCallExpression. No big deal right? System.Delegate and System.Reflection.MethodInfo are Serializable. In fact, this works great:
[Serializable]
class What
{
public string ItemID;
public int? Duration;
public DateTime ScheduleTime;
}
var items = new List
{
new What { ItemID = “1″, Duration=8, ScheduleTime=DateTime.Parse(”1/1/2001″) },
new What { ItemID = “2″, Duration=6, ScheduleTime=DateTime.Parse(”1/1/2005″) },
new What { ItemID = “3″, Duration=10, ScheduleTime=DateTime.Parse(”1/1/2005″) },
new What { ItemID = “4″, Duration=7, ScheduleTime=DateTime.Parse(”1/1/2005″) },
};
Func e = (What x) => x.Duration.GetValueOrDefault() > 7;
ConstantExpression ex = Expression.Constant(e);
var matches = items.Where(e);
var s = new NetDataContractSerializer();
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb))
{
s.WriteObject(writer, ex.Value);
}
using (var reader = XmlReader.Create(new StringReader(sb.ToString())))
{
e = Expression.Constant(s.ReadObject(reader)).Value as Func;
}
matches = items.Where(e);
But what happens when you try to send that delegate across the wire? The server doesn’t have a reference to the client assembly, and throws an exception.
This would work if you parsed the expression tree and resolved every variable to a constant, then sent it across the wire.
Hi Captain Ramen,
I think that’s exactly how it would have to work - the custom IQueryable would need to be smart enough to know what stuff it can execute on the server, and what stuff it can execute on the client.
For example, if the delegate used was declared in the generated proxy wrapper, then LINQ to SOAP could know to tell the server to execute it. Otherwise, it would need to execute it on the client - either before the query is executed (for parameters) or after (for things like “Where” clauses).
Paul
You’re eventually going to end up having to bug-fix your LINQ expression (or maybe the spec changed). Doing that on the server side is much easier to deploy
I’m absolutely loving this idea, having come from a java world where best practices for ORM are quite well bedded in I’m rather stumbling over LinQ to SQL and how to start using it.
Could someone point me in the direction of an end to end application that involves LINQ to SQL on the server hosting web service methods which allows a client to call. I’ve been creating experimental projects to try this out but I’m not clear on the true best practices in regards to context caching (or should it be a singleton), connection pooling and entity caching. I’m really unsure what the linq implementation already does and what I need to implement.
Sorry for the post here, it’s probably not the right place, but I do love what you propose as I think it would be a brilliant idea. The only thing that I’m weary of is how to make the calls strongly typed, maybe you could force this on the service calls with a method signature such as:
List GetCustomersByQuery ( QueryGraph qry ) ;
which would some how validate the query to ensure that you are selecting a customer object? Unsure, I’m still a pleb to LinQ, feel free to disregard my comments
-Brett
Okay, that was really nasty, anything in angle brackets got removed (replaced angles with squares).
List [Customer] GetCustomersByQuery [Customer] ( QueryGraph qry ) ;
-Brett
You guys might want to take a look at IdeaBlade’s DevForce EF (Entity Framework). Dip into their IdeaBlade.Linq.v4 assembly - they are serializing expression trees and sending them over the network to a WCF service, where they get deserialized, and processed through their abstraction / enhancements to the ADO.NET Entity Framework.
I have been told this works with WCF in all its glory - let’s hope that statement holds true - oh, and no, I don’t work for IdeaBlade, but with this technology coming out, I wish I did :-).
I am loving this idea too, and I could really use it in any number of situations. Have you ever made an attempt to implement this, and could you use any help?
Hi,
i’m in a need of exactly this kind of a solution,
is there any thing new that anyone can add to this thread?
Hi avi,
You could take a look at ADO.NET Data Services (project “Astoria”). I believe it attempts to cover similar scenarios.
Alternatively if you are comfortable learning RDF and some of the other semantic web standards then you could try LINQ to RDF. If you exposed your objects as RDF stores then you could query them remotely via LINQ.