Posted by: Pete Montgomery on: May 12, 2011
How to make several asynchronous requests in parallel to the same web service, when the number of such requests is dynamically determined.
Thanks to AsyncControllers, it’s quite easy to make several asynchronous requests in parallel to different web services, and have MVC gather the results.
A well-written example is on MSDN. Briefly, you save the result of each async call into the Parameters collection of the AsyncManager like so:
AsyncManager.Parameters["headlines"] = e.Value; ... AsyncManager.Parameters["scores"] = e.Value; ... AsyncManager.Parameters["forecast"] = e.Value;
Your Completed method will then bind to the parameters you have named:
public ActionResult IndexCompleted(
HeadlinesResult headlines,
ScoresResult scores,
ForecastResult forecast) { ... }
This is fine if you know how many requests you want to make. But what if you want to make several requests in parallel to the same web service (for example, with slightly different parameters) — but you don’t know in advance how many requests you will need to make?
For example, you might show the weather forecast for as many days into the future as the user requests, up to seven days, with each day requiring a separate request to the forecast service.
In this case you need a dynamically-sized collection of results of the same type, such as a list. Ideally, we want our Completed method to look something like this:
public ActionResult IndexCompleted(List results) { ... }
However, we don’t know on which threads, or even in what order, this collection will be added to when each of the web service calls complete independently.
The System.Collections.Concurrent namespace gives us a more suitable type to withstand the mutation this collection will have to put up with.
public class ForecastController : AsyncController
{
public void IndexAsync(ForecastInputModel input)
{
var results = new ConcurrentBag<ForecastResult>();
AsyncManager.Parameters["results"] = results;
foreach (var request in GetForecastRequests(input))
{
AsyncManager.OutstandingOperations.Increment();
var s = new WeatherService();
s.GetForecastCompleted += (sender, e) =>
{
results.Add(e.Value); // threadsafe
AsyncManager.OutstandingOperations.Decrement();
};
s.GetForecastAsync(request);
}
}
public ActionResult IndexCompleted(ConcurrentBag<ForecastResult> results)
{
...
}
}
Enjoy what you saw.
Posted by: Pete Montgomery on: February 10, 2011
I don’t use the famous Albahari PredicateBuilder because it doesn’t work so well with Entity Framework or the latest version of NHibernate.
This is because it relies on InvocationExpressions, which aren’t supported by many query translators, and the workaround requires an unnatural call to Tomas‘ AsExpandable method in all your queries.
A couple of years ago, Colin Meek on the EF team showed me how to compose predicates without using InvocationExpressions and since then I’ve used my own synthesized version of PredicateBuilder, with the same API as the awesome Albahari original.
var predicate = predicates.Aggregate(PredicateBuilder.Or);
If you need a PredicateBuilder that works as you’d expect with Entity Framework, NHibernate… as well as Linq to SQL, here it is. (It ought to work in Silverlight too. Let me know…!)
/// <summary>
/// Enables the efficient, dynamic composition of query predicates.
/// </summary>
public static class PredicateBuilder
{
/// <summary>
/// Creates a predicate that evaluates to true.
/// </summary>
public static Expression<Func<T, bool>> True<T>() { return param => true; }
/// <summary>
/// Creates a predicate that evaluates to false.
/// </summary>
public static Expression<Func<T, bool>> False<T>() { return param => false; }
/// <summary>
/// Creates a predicate expression from the specified lambda expression.
/// </summary>
public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
/// <summary>
/// Combines the first predicate with the second using the logical "and".
/// </summary>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
/// <summary>
/// Combines the first predicate with the second using the logical "or".
/// </summary>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
/// <summary>
/// Negates the predicate.
/// </summary>
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
{
var negated = Expression.Not(expression.Body);
return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
}
/// <summary>
/// Combines the first expression with the second using the specified merge function.
/// </summary>
static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// zip parameters (map from parameters of second to parameters of first)
var map = first.Parameters
.Select((f, i) => new { f, s = second.Parameters[i] })
.ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with the parameters in the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// create a merged lambda expression with parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
class ParameterRebinder : ExpressionVisitor
{
readonly Dictionary<ParameterExpression, ParameterExpression> map;
ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
}
Posted by: Pete Montgomery on: January 3, 2011
A commenter recently discovered that the technique I use to generate a cache key for any IQueryable was not working properly for one of his queries. The query contained a call to List.Contains, and the contents of the list was not getting put into the cache key.
The problem was that the query cache didn’t specifically know about local collection values.
Local collection values can be supplied as parameters to query operators such as Contains and Any, if the query provider supports them.
var ids = new List<int> { 1, 3, 5 };
var q = from c in db.Customers
where ids.Contains(c.CustomerId)
select c;
As far as FromCache was concerned, ids is just a constant expression, and treated it no differently to any other constant when evaluating its cache key.
Unfortunately, the ToString implementation of Lists (and of Arrays, and IEnumerables in general) is not suitable for use as a cache key, because it outputs the type name and not (for example) a representation of every element in the collection.
I couldn’t understand how I’d overlooked this. But then I remembered that Entity Framework v1, which was the main provider I was using at the time, didn’t support local collections either!
LINQ to SQL has always supported the Contains method, and Entity Framework now supports both Any and Contains overloads with local collections. So, I’ve updated the original source code and the blog post to support local collections.
This involves a pass over the expression tree to expand appropriate local collection values which might be used in methods like Any or Contains. Each method call in the expression tree is examined, and the argument to any parameters of type IEnumerable<> or List<> is wrapped in an object with an implementation of ToString which prints every element in the collection.
I’ve also extracted the method IQueryable.GetCacheKey and made it public, which could help emphasise that the meat of the idea is to automatically generate a cache key for a query (and that you can do whatever you like with it, such as make a FromCache extension method, or managing the cache manually).
If you’re using the FromCache extension method, please update use the latest version of the source code!
Posted by: Pete Montgomery on: December 8, 2010
The generic IEnumerable interface is the most important abstraction in the .NET framework after System.Object.
If you’re not 100% comfortable with IEnumerable and IEnumerable<T>, this introductory article might help!
An interface, in the general sense, is just the publicly exposed signature of a type, where ‘type’ means class or struct in C#.
We can describe an interface by writing out the full public signature of a type.
public class Customer
{
public int Age{ get; }
public void MakeHappy();
// … more methods and properties!
}
This is not valid C#, but all types have “an interface” in this basic sense. Right click on string in your code and click Go to definition to see what I mean.
Java and .NET also support a programming construct called an interface type, defined using the interface keyword. This is a formalization of the general OO concept of “interface”.
What? An interface type is really just an abstract class guaranteed to contain no implementation code.
Why? To allow a limited form of multiple inheritance.
When you “inherit” from an interface, you declare that you support the interface’s methods. This means your type can be used in situations that only require that it supports a given interface. I practice, this functionality is not directly related to the main job of the type. Interfaces give you a way of mixing and composing functionality into a type, allowing it to be used in more situations.
IComparable – an object that can be compared with other objects of the same type
IConvertible - an object that can be converted to different types
ISerializable - an object that can be serialized
IDisposable - an object that can deterministically clean up after itself
By convention, .NET interface type names are prefixed with I. Unfortunately this makes them less friendly and intuitive than normal classes. Just pretend the ‘I’ isn’t there when you read them, and keep in mind that interface types are simply a special kind of abstract class.
So, interface types can just be used in the same way as other types. In particular, you can declare variables and parameters of interface types.
bool IsABiggerThanB(IComparable a, IComparable b)
{
return a.CompareTo(b) > 0;
}
Here, parameters a and b can be of any type* that implements IComparable, which means they must define a CompareTo method.
[* Footnote. In this case, a and b have have to be the same type as each other, or a runtime exception will be thrown by CompareTo.]
The CompareTo method returns 1 if the object is bigger, 0 if the same, and -1 if smaller than the object passed to it. Many types in the .NET Framework support IComparable. For example, you can compare strings to sort them into alphabetical order.
Notice how inflexible this would be without interface types. We’d either have to
(1) inherit from some kind of “Comparable” class, using up our only base class, or
(2) support comparability in an ad-hoc, incompatible way for each type (making the polymorphic code above impossible).
Interface types support rich object oriented polymorphism without the burden of full-blown multiple inheritance.
Provides a way to traverse the elements of an aggregate object without exposing the underlying representation.
[GoF, 1995]
Aggregate object = a data structure; a collection, list or sequence of things of the same type.
Sure, often a list can be traversed with a basic for loop. For example, we can keep track of the current position in a list with a local integer variable and index into an array.
for (int i = 0; i < 10; i++)
{
object current = myCollection[i];
}
But this will only work if the collection is the kind of collection that can be indexed in to, such as a simple list or array. It doesn’t make any sense to “index” into a binary tree, for example; nor into many other data structures that we might want to traverse.
What about infinite lists? What if the size were unknown?
Depending on the kind of data structure, we’d probably need some kind private pointer inside the object to keep track of the current element, and some additional methods on the class itself. But you can see that this is not going to provide a solution to any of the above three requirements. This solution would allow one traversal at a time, and you would need to add additional methods to the class for each traversal algorithm you wanted to provide.
The Iterator pattern takes the responsibility for traversal out of the collection itself, and puts it into another object. This specialised object is responsible only for traversing the collection (in a particular way), and nothing else.
For example, an instance of this specialised object might contain a pointer to keep track of the current item, and some code implementing the particular traversal logic. The class will probably have intimate knowledge of the collection class that it supports traversal over, and might well be defined as a nested class.
The Iterator pattern is supported in the .NET framework v1 via two interface types in the System.Collections namespace.
IEnumerator – a specialised object responsible for doing the traversal
IEnumerable - a data structure that can be traversed
Microsoft uses ‘enumerate’ instead of ‘iterate’. So you can think instead of “the Enumerator pattern” if you like. Also note that this sense of ‘enumerate’ has nothing really to do with enumerated types (enums in C#).
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
}
This interface is the really the key to the pattern. It defines pretty much the simplest possible interface for traversing over a data structure. An enumerator object can tell you what the current item is, and you can tell it to move to the next item, and that’s it.(*) If MoveNext is false, we have run out of items. These two methods are just a slightly more verbose way of supporting the operation “Give me the next one“, which is the essence of the enumerator interface.
Notice the enumerator interface makes no assumptions at all about the structure, internal implementation or size of the data strucure that is being traversed. It’s perhaps the purest notion of a “sequence” you can think of.
(*) There are one or two other methods on the interface, but they’re not essential to understanding the pattern.
while (enumerator.MoveNext())
{
object current = enumerator.Current;
}
Note that Microsoft could have designed this type as an abstract class instead of an interface type.
Great – so now we can iterate over any kind of collection or sequence using this code, provided we have an enumerator for that kind of sequence.
If only we had a standardised way to get an enumerator!
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
This is the public face of the Iterator pattern in .NET. It simply provides a well-known way to get an instance of a default enumerator for a particular sequence or collection.
So, if I give you an object that is enumerable, you can call GetEnumerator to give you a nice enumerator object that you can use to do a standard traversal of the object’s items.
The IEnumerable interface is implemented by many different types, including all collection types, and even the String class.
string s = “abcdef”;
IEnumerator enumerator = s.GetEnumerator();
while (enumerator.MoveNext())
{
Console.Write( ((char) enumerator.Current) + “.” );
}
// output: “a.b.c.d.e.f.”
It turns out that this usage pattern (obtaining the default enumerator, then calling MoveNext on it in a loop) is so common it is formalised into a helpful language-level construct in C# and VB.
If you’ve ever wondered how the foreach keyword works, now you know. The following code is identical to the previous example.
string s = “abcdef”;
foreach (char c in s)
{
Console.Write(c + “.”);
}
The C# compiler simply expands this code to that in the previous example. The intermediate language produced is identical.(*)
(*) OK, it’s not, but assume it is. Check out the difference in Reflector.
The Iterator design pattern is deeply supported in the .NET framework class library and languages.
Generics in .NET 2.0 improved support for the pattern by adding strongly-typed versions of the interfaces, IEnumerator<T> and IEnumerable<T>. IEnumerable<T> in particular plays a key role in the language integrated query (LINQ) features and C# 3.0 in general. The C# 2.0 compiler was given the power to write its own iterator implementations via the yield keyword.
Posted by: Pete Montgomery on: September 20, 2010
The XML Document Transform language, or XDT, shipped with Visual Studio 2010. It’s an XML dialect designed to help you automatically transform your .NET config files appropriately for your various deployment environments.
Don’t worry, XDT is very simple and specifically designed for the task of transforming configuration files. For this scenario, it is much easier to use than a general-purpose transformation language like XSLT.
Application configuration files tend to be mostly identical across different deployment environments. Only small modifications, such as the value of your connection strings, the debug attribute, and so on, are required to create a production Web.config file out of a development Web.config file.
To show how simple it is, the basic semantics of the language can be expressed in a few lines of C#.
Let’s assume an existing Web.config file for our input document. We’ll also write a small XDT transform document which sets the ASP.NET debug attribute to false:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <system.web> <compilation debug="false" xdt:Transform="SetAttributes" /> </system.web> </configuration>
Notice it looks a bit like a small Web.config document. The input doc could be a big, complex Web.config file, but that doesn’t matter – the transform doc only needs to contain the differences.
The Transform attribute is defined within a distinguished XML namespace to ensure that it can’t clash with any existing attributes in the input doc. In this case, we’re using one of the most useful built-in transforms, SetAttributes, which modifies attribute values on the targeted element to those that are specified in the transform doc – in this case, setting debug to false. There are other useful transforms, such as Remove and Replace, which alter the targeted element in different ways.
A transform implicitly specifies the element(s) in the input document to act upon by virtue of the element that it belongs to: expressed in XPath, the above transform would target the
/configuration/system.web/compilation element(s).
Here is a simple implementation of XDT using C#:
public XDocument Transform(XDocument inputDoc, XDocument transformDoc)
{
var workingDoc = new XDocument(inputDoc);
// (1) pair each "Transform" element with the element(s)
// it targets in the working document
var xs = from e in transformDoc.Descendants()
from a in e.Attributes(Namespaces.Xdt + "Transform")
let xpath = GetElementXPath(e)
select new
{
TransformElement = e,
TargetElements = workingDoc.XPathSelectElements(xpath)
};
// (2) apply each transform to its target elements
foreach (var x in xs)
{
ApplyTransform(x.TransformElement, x.TargetElements);
}
return workingDoc;
}
This is a slight simplification, and of course doesn’t show you the implementation of the individual transforms or how to compute the XPath. You can find the full, reasonably complete implementation of XDT on Google Code.
The implicit XPath location of, for example, a /configuration/appSettings/add element would usually specify more than one element in most Web.config files. While this is valid, it’s not very useful. XDT provides a second attribute, Locator, which allows you to augment the implicit XPath expression with a predicate to filter the target element set:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add xdt:Locator="Condition(@key='key3')" />
</appSettings>
</configuration>
This would give us target XPath of /configuration/appSettings/add[@key='key3'], which is much more useful (although it doesn’t do anything, because we haven’t specified any transform!).
A convenience case of the Condition locator is to simply Match on the specified attribute, so to actually alter a particular app setting value, you would write:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <appSettings> <add key="key3" value="new value" xdt:Locator="Match(key)" xdt:Transform="SetAttributes" /> </appSettings> </configuration>
This specifies a SetAttributes transform with the same target XPath as the previous example.
I wanted to use XDT in production before Visual Studio 2010 was released. I also find that thinking about the implementation of something helps you understand its semantics. However, there are some other good reasons:
If you’re creating a serious build system, these restrictions would otherwise probably prevent you from using XDT for your transformations, which would be a shame.
It feels like a classic Microsoft situation – a well-engineered core technology, but restricted (understandably) for commercial / shipping reasons. If you do want to go ahead and use this alternative implementation, it’s very straightforward to create an MSBuild task to call XdtTransformer.Transform() in order to use XDT in your build system. If there’s enough demand, I could add one to the distribution on Google Code.
Posted by: Pete Montgomery on: April 1, 2009
A generic function to group a sequence into sequences of equal size.
var numbers = new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
var groups = numbers.GroupsOf(3);
Now groups is a sequence of sequences containing three items.
Perhaps you might use this in some tricky UI scenario or to gamble away your integers. You’ll need the IEnumerator.Next extension too.
Is this a special case of a more general function, I wonder?
/// <summary>
/// Groups a sequence into sequences of the specified size.
/// The final group may be shorter if there are leftover
/// elements.
/// </summary>
/// <param name="count">The size of the groups.</param>
public static IEnumerable<IEnumerable<T>> GroupsOf<T>(
this IEnumerable<T> source,
int count)
{
using (var it = source.GetEnumerator())
{
while (true)
{
var group = it.Next(count).ToList();
if (group.Any())
yield return group;
else
break;
}
}
}
Posted by: Pete Montgomery on: March 31, 2009
I still find it remarkable how syntax alone can alter the way I conceptualise a problem.
Here’s a useful helper for pulling the next n elements out of an enumerator. Think of it as a generalisation of MoveNext. I’ve found it handy for implementing certain IEnumerable extensions.
public static class EnumeratorExtensions
{
/// <summary>
/// Returns a specified number of contiguous elements
/// from the enumerator.
/// </summary>
public static IEnumerable<T> Next<T>(
this IEnumerator<T> source,
int count)
{
int counter = 0;
while (counter < count)
{
if (source.MoveNext())
yield return source.Current;
else
break;
counter++;
}
}
}
Posted by: Pete Montgomery on: March 30, 2009
One handy function in the F# Seq module is Seq.pairwise.
[ 1 ; 2 ; 3 ; 4 ; 5] |> Seq.pairwise
It produces a sequence of, well, pairs:
val it : seq<int * int> = seq [(1, 2); (2, 3); (3, 4); (4, 5)]
Its main use is comparing each value in a sequence with its successor. One example might be analysing a web server log for suspicious crawlers.
Obviously you’ll need your own Pair class, which I’ll leave to you, reader (at least until we get tuples in .NET 4). No argument checking, but otherwise I think complete. Enjoy!
public static class EnumerableExtensions
{
/// <summary>
/// Returns a sequence of each element in the input sequence and its
/// predecessor, with the exception of the first element which is only
/// returned as the predecessor of the second element.
/// </summary>
public static IEnumerable<Pair<T, T>> Pairwise<T>(
this IEnumerable<T> source)
{
T previous = default(T);
using (var it = source.GetEnumerator())
{
// skip the first element
if (it.MoveNext())
previous = it.Current;
while (it.MoveNext())
{
yield return new Pair<T, T>
{
First = previous,
Second = it.Current
};
previous = it.Current;
}
}
}
}
ts.Zip(us.Skip(1), (t, u) => new { t, u});
Posted by: Pete Montgomery on: January 27, 2009
In contrast with its more famous sibling System.StringBuilder, the System.UriBuilder class goes mostly unnoticed and unloved.
This is unfortunate, since although the URI is just a string, it’s restricted by detailed specification to a limited subset of all possible strings. This is why we have framework and library code to help us out. Think how many bugs and security errors have been caused by concatenating general-purpose strings!
The .NET UriBuilder class provides additional safety but inexplicably lacks support for one of the most common reasons for concatenating strings to form a URL – manipulating query strings.
In particular, you often find that you would like to set a query key/value pair on an existing URL. You want to add it if it doesn’t already exist (but change it if it does) and leave the rest of the URL intact.
A convenient API can be grafted with a couple of extension methods, GetQueryParams and SetQueryParam.
var uri = new UriBuilder("http://blah.com");
Assert.True( uri.GetQueryParams().Count() == 0 );
uri.SetQueryParam("sortBy", "price");
Assert.True( uri.GetQueryParams().Count() == 1 );
Assert.True( uri.Query.EndsWith("?sortBy=price") );
uri.SetQueryParam("page", "3");
Assert.True( uri.GetQueryParams().Count() == 2 );
Assert.True( uri.Query.Contains("page=3") );
uri.SetQueryParam("page", "4");
Assert.True( uri.GetQueryParams().Count() == 2 );
Assert.True( uri.Query.Contains("page=4") );
Here’s the full source.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Collections.Specialized;
// ...
public static class UriBuilderExtensions
{
/// <summary>
/// Sets the specified query parameter key-value pair of the URI.
/// If the key already exists, the value is overwritten.
/// </summary>
public static UriBuilder SetQueryParam(this UriBuilder uri, string key, string value)
{
var collection = uri.ParseQuery();
// add (or replace existing) key-value pair
collection.Set(key, value);
string query = collection
.AsKeyValuePairs()
.ToConcatenatedString(pair =>
pair.Key == null
? pair.Value
: pair.Key + "=" + pair.Value, "&");
uri.Query = query;
return uri;
}
/// <summary>
/// Gets the query string key-value pairs of the URI.
/// Note that the one of the keys may be null ("?123") and
/// that one of the keys may be an empty string ("?=123").
/// </summary>
public static IEnumerable<KeyValuePair<string, string>> GetQueryParams(
this UriBuilder uri)
{
return uri.ParseQuery().AsKeyValuePairs();
}
/// <summary>
/// Converts the legacy NameValueCollection into a strongly-typed KeyValuePair sequence.
/// </summary>
static IEnumerable<KeyValuePair<string, string>> AsKeyValuePairs(this NameValueCollection collection)
{
foreach (string key in collection.AllKeys)
{
yield return new KeyValuePair<string, string>(key, collection.Get(key));
}
}
/// <summary>
/// Parses the query string of the URI into a NameValueCollection.
/// </summary>
static NameValueCollection ParseQuery(this UriBuilder uri)
{
return HttpUtility.ParseQueryString(uri.Query);
}
}
The general-purpose folding function ToConcatenatedString is used in the implementation. Here it is:
public static class EnumerableExtensions
{
/// <summary>
/// Creates a string from the sequence by concatenating the result
/// of the specified string selector function for each element.
/// </summary>
public static string ToConcatenatedString<T>(this IEnumerable<T> source,
Func<T, string> stringSelector)
{
return source.ToConcatenatedString(stringSelector, String.Empty);
}
/// <summary>
/// Creates a string from the sequence by concatenating the result
/// of the specified string selector function for each element.
/// </summary>
///<param name="separator">The string which separates each concatenated item.</param>
public static string ToConcatenatedString<T>(this IEnumerable<T> source,
Func<T, string> stringSelector,
string separator)
{
var b = new StringBuilder();
bool needsSeparator = false; // don't use for first item
foreach (var item in source)
{
if (needsSeparator)
b.Append(separator);
b.Append(stringSelector(item));
needsSeparator = true;
}
return b.ToString();
}
}
Posted by: Pete Montgomery on: August 7, 2008
An essential feature of many applications is a caching architecture. What if your query layer could offer an easy way to optionally cache the result of any query issued against it? Ideally, this would
var q = from c in context.Customers
where c.City == "London"
select new { c.Name, c.Phone };
var result = q.Take(10).FromCache();
The FromCache extension method offers a nice way to opt in for local result caching on any LINQ query. Here’s the method signature:
/// <summary>
/// Returns the result of the query; if possible from the cache, otherwise
/// the query is materialized and the result cached before being returned.
/// </summary>
public static IEnumerable<T> FromCache<T>(this IQueryable<T> query) { ... }
Note that this works for any IQueryable<T>, and for any T (including anonymous types). The complete source is available at the bottom of the article. There’s an additional overload to allow more sophisticated caching policies to be specified, and of course you could easily add more.
The main challenge is to automatically generate a cache key which is sufficiently unique for the query, using only the query and no additional user-supplied information. Normally, cache key generation logic tends to permeate application code and really clutter it up. Handliy, LINQ queries are self-describing – what “identifies” a query is the expression it represents, and this is completely captured by the query’s expression tree.
Clearly it is possible to generate a textual representation of an expression tree – that’s almost exactly what they were designed for, and exactly how LINQ to SQL works. All we need to do is build a query evaluater which, instead of generating SQL, returns a suitable textual representation of the query.
Luckily the ToString method on the Expression class already does almost exactly this. Look what it produces for this simple predicate expression:
Expression<Func<Customer, bool>> predicate = c => c.Name.StartsWith("Smith");
Console.WriteLine(predicate.ToString());
"c => c.Name.StartsWith(\"Smith\")"
The information contained in the expression tree data structure allows the Expression.ToString implementation to produce a string representation which looks something like the query’s source code. This is a great candidate for our cache key!
A subtle problem is that the ToString output won’t be unique enough if the expression contains “local” nodes which haven’t been evaluated yet. In particular, the way the C# and VB compilers implement closures means that local variable values you might expect to be present in the query are actually on the other end of closure references.
string pattern = "Smith"; predicate = c => c.Name.StartsWith(pattern); Console.WriteLine(predicate.ToString());
"c => c.Name.StartsWith(value(App.Program+<>c__DisplayClass1).pattern)"
Unfortunately, exactly the same string representation would be also produced by a query for “Jones”. This is because the expression now contains a reference to an unevaluated member of a captured variable. This is what Matt Warren calls the closure mess.
Recall that LINQ queries are not evaluated until the last possible opportunity. If we were to build a query provider, we would need to evaluate all such unevaluated local expressions just before we generated our SQL (or whatever). If only we had a function like so:
predicate = Evaluator.PartialEval(predicate)
Such a sample implementation of partial query evaluation is provided by Microsoft in Creating an IQueryable LINQ Provider. Applying the PartialEval function to the expression walks the tree, evaluates locally-evaluable nodes and returns the simplified expression. This neatly gets us back to our original ToString expression representation.
"c => c.Name.StartsWith(\"Smith\")"
An additional complexity is this: For ConstantExpressions, the ToString implementation simply delegates to the underlying wrapped object. We therefore need to be careful about what we allow to be wrapped in a ConstantExpression during partial evaluation. For example, the string representation of a LINQ to SQL IQueryable object is some version of the SQL that it would like to generate. This may not be enough to ensure uniqueness. Therefore we need to supply a slightly more sophisticated rule to PartialEval which determines whether a given node in the query is locally evaluable in order to prevent raw queries being locally evaluated and wrapped in ConstantExpressions by the partial evaluator.
Local collection values can be supplied as parameters to query operators such as Contains and Any, if the query provider supports them.
LINQ to SQL and now Entity Framework v4 both support local collection values. However, local collections (such as lists or arrays) are just constant expressions in a query, so special support is needed to ensure that a suitable cache key is created representing each of their elements.
This is implemented by a pass over the expression tree to make appropriate local collection values expand themselves during ToString invocation. Each method call in the expression is examined, and the argument to any parameters of type IEnumerable<> or List<> is wrapped in an object with an implementation of ToString which prints every element in the collection.
A final problem is that the cache key string could get very big, especially for complicated queries. Unless your query results are really super-sensitive, it’s fine to use an MD5 fingerprint of the key instead. MD5 fingerprints are not guaranteed to be be unique, but it should be computationally infeasible to find two identical fingerprints.
While generating a cache key from the query expression in this manner is pretty elegant and very useful for LINQ-based applications and libraries, you should take care when using more than one query datasource of the same data type.
Constants in the query (including IQueryables) create the same key. Two different sources of type IQueryable<Customer> are not distinguished from each other – the same queries against them will generate identical cache keys. Usually this is what you want – for example, you want to be able to cache the results of a query regardless of which data context instance the query was issued against.
It (theoretically) may not be what you want in some scenarios. If in doubt, double-check that the cache key strings being generated don’t conflict.
ORMs generally have their own internal object manager. You will need to make sure that your query results from any such provider (LINQ to SQL, Entity Framework, etc.) are released from their object manager.
Remember that the normal consequences of caching still apply. Any object reference put into an application-wide cache will be kept alive indeterminately. Once you put something into cache it can (and probably will) be accessed from arbitrary threads. Cached objects should probably be treated as read-only data.
This example implementation of FromCache uses the System.Web.Caching.Cache class. It’s worth noting that this useful class isn’t really specific to ASP.NET, and can be used by any .NET application or library. You’ll just need a reference to the System.Web assembly. (Note that its use outside web applications is not officially supported by Microsoft.)
Alternatively, you could just as easily use this technique with another cache implementation.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Caching;
namespace Monty.Linq
{
/// <remarks>
/// Copyright (c) 2010 Pete Montgomery.
/// http://petemontgomery.wordpress.com
/// Licenced under GNU LGPL v3.
/// http://www.gnu.org/licenses/lgpl.html
/// </remarks>
public static class QueryResultCache
{
/// <summary>
/// Returns the result of the query; if possible from the cache, otherwise
/// the query is materialized and the result cached before being returned.
/// The cache entry has a one minute sliding expiration with normal priority.
/// </summary>
public static IEnumerable<T> FromCache<T>(this IQueryable<T> query)
{
return query.FromCache(CacheItemPriority.Normal, TimeSpan.FromMinutes(1));
}
/// <summary>
/// Returns the result of the query; if possible from the cache, otherwise
/// the query is materialized and the result cached before being returned.
/// </summary>
public static IEnumerable<T> FromCache<T>(this IQueryable<T> query,
CacheItemPriority priority,
TimeSpan slidingExpiration)
{
string key = query.GetCacheKey();
// try to get the query result from the cache
var result = HttpRuntime.Cache.Get(key) as List<T>;
if (result == null)
{
// todo: ... ensure that the query results do not
// hold on to resources for your particular data source
//
//////// for entity framework queries, set to NoTracking
//////var entityQuery = query as ObjectQuery<T>;
//////if (entityQuery != null)
//////{
////// entityQuery.MergeOption = MergeOption.NoTracking;
//////}
// materialize the query
result = query.ToList();
HttpRuntime.Cache.Insert(
key,
result,
null, // no cache dependency
Cache.NoAbsoluteExpiration,
slidingExpiration,
priority,
null); // no removal notification
}
return result;
}
/// <summary>
/// Gets a cache key for a query.
/// </summary>
public static string GetCacheKey(this IQueryable query)
{
var expression = query.Expression;
// locally evaluate as much of the query as possible
expression = Evaluator.PartialEval(expression, QueryResultCache.CanBeEvaluatedLocally);
// support local collections
expression = LocalCollectionExpander.Rewrite(expression);
// use the string representation of the expression for the cache key
string key = expression.ToString();
// the key is potentially very long, so use an md5 fingerprint
// (fine if the query result data isn't critically sensitive)
key = key.ToMd5Fingerprint();
return key;
}
static Func<Expression, bool> CanBeEvaluatedLocally
{
get
{
return expression =>
{
// don't evaluate parameters
if (expression.NodeType == ExpressionType.Parameter)
return false;
// can't evaluate queries
if (typeof(IQueryable).IsAssignableFrom(expression.Type))
return false;
return true;
};
}
}
}
/// <summary>
/// Enables the partial evaluation of queries.
/// </summary>
/// <remarks>
/// From http://msdn.microsoft.com/en-us/library/bb546158.aspx
/// Copyright notice http://msdn.microsoft.com/en-gb/cc300389.aspx#O
/// </remarks>
public static class Evaluator
{
/// <summary>
/// Performs evaluation & replacement of independent sub-trees
/// </summary>
/// <param name="expression">The root of the expression tree.</param>
/// <param name="fnCanBeEvaluated">A function that decides whether a given expression node can be part of the local function.</param>
/// <returns>A new tree with sub-trees evaluated and replaced.</returns>
public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
{
return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
}
/// <summary>
/// Performs evaluation & replacement of independent sub-trees
/// </summary>
/// <param name="expression">The root of the expression tree.</param>
/// <returns>A new tree with sub-trees evaluated and replaced.</returns>
public static Expression PartialEval(Expression expression)
{
return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
}
private static bool CanBeEvaluatedLocally(Expression expression)
{
return expression.NodeType != ExpressionType.Parameter;
}
/// <summary>
/// Evaluates & replaces sub-trees when first candidate is reached (top-down)
/// </summary>
class SubtreeEvaluator : ExpressionVisitor
{
HashSet<Expression> candidates;
internal SubtreeEvaluator(HashSet<Expression> candidates)
{
this.candidates = candidates;
}
internal Expression Eval(Expression exp)
{
return this.Visit(exp);
}
public override Expression Visit(Expression exp)
{
if (exp == null)
{
return null;
}
if (this.candidates.Contains(exp))
{
return this.Evaluate(exp);
}
return base.Visit(exp);
}
private Expression Evaluate(Expression e)
{
if (e.NodeType == ExpressionType.Constant)
{
return e;
}
LambdaExpression lambda = Expression.Lambda(e);
Delegate fn = lambda.Compile();
return Expression.Constant(fn.DynamicInvoke(null), e.Type);
}
}
/// <summary>
/// Performs bottom-up analysis to determine which nodes can possibly
/// be part of an evaluated sub-tree.
/// </summary>
class Nominator : ExpressionVisitor
{
Func<Expression, bool> fnCanBeEvaluated;
HashSet<Expression> candidates;
bool cannotBeEvaluated;
internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
{
this.fnCanBeEvaluated = fnCanBeEvaluated;
}
internal HashSet<Expression> Nominate(Expression expression)
{
this.candidates = new HashSet<Expression>();
this.Visit(expression);
return this.candidates;
}
public override Expression Visit(Expression expression)
{
if (expression != null)
{
bool saveCannotBeEvaluated = this.cannotBeEvaluated;
this.cannotBeEvaluated = false;
base.Visit(expression);
if (!this.cannotBeEvaluated)
{
if (this.fnCanBeEvaluated(expression))
{
this.candidates.Add(expression);
}
else
{
this.cannotBeEvaluated = true;
}
}
this.cannotBeEvaluated |= saveCannotBeEvaluated;
}
return expression;
}
}
}
/// <summary>
/// Enables cache key support for local collection values.
/// </summary>
public class LocalCollectionExpander : ExpressionVisitor
{
public static Expression Rewrite(Expression expression)
{
return new LocalCollectionExpander().Visit(expression);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
// pair the method's parameter types with its arguments
var map = node.Method.GetParameters()
.Zip(node.Arguments, (p, a) => new { Param = p.ParameterType, Arg = a })
.ToLinkedList();
// deal with instance methods
var instanceType = node.Object == null ? null : node.Object.Type;
map.AddFirst(new { Param = instanceType, Arg = node.Object });
// for any local collection parameters in the method, make a
// replacement argument which will print its elements
var replacements = (from x in map
where x.Param != null && x.Param.IsGenericType
let g = x.Param.GetGenericTypeDefinition()
where g == typeof(IEnumerable<>) || g == typeof(List<>)
where x.Arg.NodeType == ExpressionType.Constant
let elementType = x.Param.GetGenericArguments().Single()
let printer = MakePrinter((ConstantExpression) x.Arg, elementType)
select new { x.Arg, Replacement = printer }).ToList();
if (replacements.Any())
{
var args = map.Select(x => (from r in replacements
where r.Arg == x.Arg
select r.Replacement).SingleOrDefault() ?? x.Arg).ToList();
node = node.Update(args.First(), args.Skip(1));
}
return base.VisitMethodCall(node);
}
ConstantExpression MakePrinter(ConstantExpression enumerable, Type elementType)
{
var value = (IEnumerable) enumerable.Value;
var printerType = typeof(Printer<>).MakeGenericType(elementType);
var printer = Activator.CreateInstance(printerType, value);
return Expression.Constant(printer);
}
/// <summary>
/// Overrides ToString to print each element of a collection.
/// </summary>
/// <remarks>
/// Inherits List in order to support List.Contains instance method as well
/// as standard Enumerable.Contains/Any extension methods.
/// </remarks>
class Printer<T> : List<T>
{
public Printer(IEnumerable collection)
{
this.AddRange(collection.Cast<T>());
}
public override string ToString()
{
return "{" + this.ToConcatenatedString(t => t.ToString(), "|") + "}";
}
}
}
public static class Utility
{
/// <summary>
/// Creates an MD5 fingerprint of the string.
/// </summary>
public static string ToMd5Fingerprint(this string s)
{
var bytes = Encoding.Unicode.GetBytes(s.ToCharArray());
var hash = new MD5CryptoServiceProvider().ComputeHash(bytes);
// concat the hash bytes into one long string
return hash.Aggregate(new StringBuilder(32),
(sb, b) => sb.Append(b.ToString("X2")))
.ToString();
}
public static string ToConcatenatedString<T>(this IEnumerable<T> source, Func<T, string> selector, string separator)
{
var b = new StringBuilder();
bool needSeparator = false;
foreach (var item in source)
{
if (needSeparator)
b.Append(separator);
b.Append(selector(item));
needSeparator = true;
}
return b.ToString();
}
public static LinkedList<T> ToLinkedList<T>(this IEnumerable<T> source)
{
return new LinkedList<T>(source);
}
}
}
The source code now assumes .NET 4 and above. If you need to run on .NET 3.5, you can use the MSDN ExpressionVisitor and the framework methods below.
/// <summary>
/// These methods are built-in to .NET 4 and above.
/// </summary>
public static class Framework35Utility
{
public static IEnumerable<R> Zip<T, U, R>(
this IEnumerable<T> first,
IEnumerable<U> second,
Func<T, U, R> selector)
{
using (var e1 = first.GetEnumerator())
using (var e2 = second.GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext())
yield return selector(e1.Current, e2.Current);
}
}
public static MethodCallExpression Update(
this MethodCallExpression source,
Expression @object,
IEnumerable<Expression> arguments)
{
if (@object == source.Object && arguments.SequenceEqual(source.Arguments))
{
return source;
}
return Expression.Call(@object, source.Method, arguments);
}
}
Recent Comments