OutputCacheProvider for Redis

Following this series of posts about caching and OutputCache in particular, I will now show you how to use Redis to store the output cache items in your ASP.NET MVC application. You can use the same concepts to store in any other data store, such as AppFabric, MongoDb, File System, etc.

First, we will need a Redis client. In this implementation i’m using StackExchange.Redis, so you will need to run this in the package manager console (or via nuget package manager UI):

Install-Package StackExchange.Redis

Next, let’s implement the provider. The first thing you should do is to create a class that inherits from System.Web.Caching.OutputCacheProvider, and then provide implementations for Add, Set, Get and Remove methods. The stubs look like this:

public class RedisOutputCacheProvider : OutputCacheProvider
{
    public override object Add(string key, object entry, DateTime utcExpiry)
    {
        throw new NotImplementedException();
    }

    public override object Get(string key)
    {
        throw new NotImplementedException();
    }

    public override void Remove(string key)
    {
        throw new NotImplementedException();
    }

    public override void Set(string key, object entry, DateTime utcExpiry)
    {
        throw new NotImplementedException();
    }
}

Next, we will connect to the Redis cluster. Since i’m only using my local development machine for testing, i’ll create a ConnectionMultiplexer like so:

private static ConnectionMultiplexer Redis = ConnectionMultiplexer.Connect("localhost:6379");

Also, since this Redis client needs to receive a byte[] when storing the entries, we will need to handle the serialization as well. I created an abstraction for this, also because I wanted to test with different serializers:

public interface IItemSerializer
{
    byte[] Serialize(object item);
    object Deserialize(byte[] itemBytes);
}

Now, for the provider implementation:

public class RedisOutputCacheProvider : OutputCacheProvider
{
    private static ConnectionMultiplexer Redis = ConnectionMultiplexer.Connect("localhost:6379");
    private static IItemSerializer Serializer = new BinaryFormatterItemSerializer();

    public override object Add(string key, object entry, DateTime utcExpiry)
    {
        // return the existing value if any
        var existingValue = Get(key);
        if (existingValue != null)
        {
            return existingValue;
        }

        var expiration = utcExpiry - DateTime.UtcNow;
        var entryBytes = Serializer.Serialize(entry);

        var db = Redis.GetDatabase();

        // set the cache item with the defined expiration, only if an item does not exist
        db.StringSet(key, entryBytes, expiration, When.NotExists);

        return entry;
    }

    public override void Set(string key, object entry, DateTime utcExpiry)
    {
        var expiration = utcExpiry - DateTime.UtcNow;
        var entryBytes = Serializer.Serialize(entry);

        var db = Redis.GetDatabase();

        // set the cache item with the defined expiration, overriding existing items
        db.StringSet(key, entryBytes, expiration, When.Always);
    }

    public override object Get(string key)
    {
        var db = Redis.GetDatabase();

        var valueBytes = db.StringGet(key);

        if (!valueBytes.HasValue)
        {
            return null;
        }

        var value = Serializer.Deserialize(valueBytes);

        return value;
    }

    public override void Remove(string key)
    {
        var db = Redis.GetDatabase();

        // signal key removal but don't wait for the result
        db.KeyDelete(key);
    }
}

The provider implementation must follow the documentation guidelines in the MSDN page.

In particular, these are the main design rules for the Add method:

  • If there is already a value in the cache for the specified key, the provider must return that value.
  • The Add method stores the data if it is not already in the cache.
  • If the data is in the cache, the Add method returns it.

In the example above, i’m using a implementation of the IItemSerializer interface that uses the BinaryFormatter for the serialization:

public class BinaryFormatterItemSerializer : IItemSerializer
{
    public byte[] Serialize(object item)
    {
        var formatter = new BinaryFormatter();

        byte[] itemBytes;

        using (var ms = new MemoryStream())
        {
            formatter.Serialize(ms, item);
            itemBytes = ms.ToArray();
        }

        return itemBytes;
    }

    public object Deserialize(byte[] bytes)
    {
        var formatter = new BinaryFormatter();

        object item;
        using (var ms = new MemoryStream(bytes))
        {
            item = formatter.Deserialize(ms);
        }

        return item;
    }
}

Unit testing

I wrote some unit tests so that we can check that everything is working correctly before using it in our application. The first test checks all the basic functionality, and the second one checks the ability of the cache provider to remove expired items:

[TestClass]
public class RedisOutputCacheProviderTests
{
    [TestMethod]
    public void CanAddAndGetAndSetAndRemoveItem()
    {
        var key = "mykey" + Guid.NewGuid();
        var provider = new RedisOutputCacheProvider();

        // test add and get

        provider.Add(key, "myvalue", DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)));

        var value = (string)provider.Get(key);

        Assert.AreEqual("myvalue", value);

        // test set and get

        provider.Set(key, "anothervalue", DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)));

        var valueAfterSet = (string)provider.Get(key);

        Assert.AreEqual("anothervalue", valueAfterSet);

        // test remove and get

        provider.Remove(key);

        var valueAfterRemove = (string)provider.Get(key);
        Assert.Is Null(valueAfterRemove);
    }

    [TestMethod]
    public async Task EntryExpiresAfterAbsoluteTime()
    {
        var key = "mykey" + Guid.NewGuid();
        var provider = new RedisOutputCacheProvider();

        // add the value and check that it is in cache

        provider.Add(key, "myvalue", DateTime.UtcNow.Add(TimeSpan.FromSeconds(3)));
        var value = (string)provider.Get(key);
        Assert.AreEqual("myvalue", value);

        await Task.Delay(3000);

        var valueAfterExpiration = (string)provider.Get(key);
        Assert.Is Null(valueAfterExpiration);
    }
}

Configure your web application

After checking that the basic behavior is fine, we can integrate the provider into our web application. Assuming that you are already using the OutputCacheAttribute, you can do this by adding the following xml to your web.config:

<system.web>
  (...)
  <caching>
    <outputCache defaultProvider="RedisOutputCache">
      <providers>
        <add name="RedisOutputCache" type="YourNamespace.RedisOutputCacheProvider, YourAssemblyName" />
      </providers>
    </outputCache>
  </caching>
  (...)
</system.web>

Then, if you go back to your web application, your OutputCache attributes should all be using this new provider!

Further work

I was also experimenting with a faster binary serializer, protobuf-net. It works for unit tests, but since the type that the OutputCache is trying to store is internal, we cannot use this implementation at the moment. I will try to figure out a way to use protobuf-net for this, and if you have any suggestions please drop a comment below:

    ...
    using ProtoBuf;
    ...
    public class ProtoBufItemSerializer : IItemSerializer
    {
        public byte[] Serialize(object entry)
        {
            var item = new CacheItem { Value = entry };

            byte[] itemBytes;

            using (var ms = new MemoryStream())
            {
                Serializer.Serialize<CacheItem>(ms, item);
                itemBytes = ms.ToArray();
            }

            return itemBytes;
        }

        public object Deserialize(byte[] bytes)
        {
            CacheItem item;
            using (var ms = new MemoryStream(bytes))
            {
                item = Serializer.Deserialize<CacheItem>(ms);
            }

            return item.Value;
        }

        [ProtoContract]
        public class CacheItem
        {
            [ProtoMember(1, DynamicType = true)]
            public object Value { get; set; }
        }
    }

Finally, since I didn’t want my web application to fail when temporary connection issues to the Redis cluster arise, I wrapped all the implementations in a try-catch, so that if the cache fails, MVC will ignore the cache and execute the action.

Example for the Get method:

public override object Get(string key)
{
    try
    {
        // implementation goes here
    }
    catch (RedisConnectionException e)
    {
        Trace.TraceError(e.ToString());
        return null;
    }
}

You can test this by loading up your web application, making a request to a OutputCached action, and then shutting down redis and reloading the page. The page should still show up, but the content is being regenerated in every request.

Invalidating cache when data changes

You can invalidate a cache item over the response context. As an example, I created one more action in my controller to invalidate the Index item cache:

public string InvalidateCache()
{
    Response.RemoveOutputCacheItem(Url.Action("Index", "Home"));
    return "Done";
}

Code on GitHub

I created a repository on github to host these and other OutputCache-related extensions. You can find the full code at https://github.com/danielbcorreia/OutputCacheExtensions.

If you have any comments or suggestions about this article, go ahead and write in the comments.

 

ASP.NET MVC OutputCache Vary by Current User

Caching user-specific data is a common requirement in web applications. Most times the first thing that you do when you sign in a user in your website is redirect them to a dashboard that is unique for that user. When the user spends a lot of time on his dashboard, you need to make sure that you can improve his experience without compromising your ability to fetch all the relevant data from all the different parts of your system.

In ASP.NET MVC, the easier way to cache the full rendered page is to use the OutputCacheAttribute, like so:

[Authorize]
public class DashboardController : Controller 
{
    [OutputCache(Duration = 3600)]
    public ActionResult Index() 
    {
       // Your awesome code goes here
    }
}

The previous code would make the Index action stay in cache for one hour. This works great for public content, but for user-specific content you must complement the cache key, so that different users don’t see each-other’s cache.

To do this, we use the VaryByCustom property of the OutputCacheAttribute, like this:

[Authorize]
public class DashboardController : Controller 
{
    [OutputCache(Duration = 3600, VaryByCustom = "User")]
    public ActionResult Index() 
    {
       // Your awesome code goes here
    }
}

And you also need to handle that “User” value in a method that is called over the HttpApplication: the GetVaryByCustomString method.
So, you need to go to your Global.asax.cs and override that method:

public override string GetVaryByCustomString(HttpContext context, string arg) 
{ 
    if (arg.Equals("User", StringComparison.InvariantCultureIgnoreCase)) 
    {
        var user = context.User.Identity.Name; // TODO here you have to pick an unique identifier from the current user identity
        return string.Format("{0}@{1}", userIdentifier.Name, userIdentifier.Container); 
    }

    return base.GetVaryByCustomString(context, arg); 
}

Or, if you don’t set a custom principal in your pipeline, you can look for the session id like so:

private static SessionStateSection SessionStateSection = (System.Web.Configuration.SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");

public override string GetVaryByCustomString(HttpContext context, string arg) 
{ 
    if (arg.Equals("User", StringComparison.InvariantCultureIgnoreCase)) 
    {
        var cookieName =  SessionStateSection.CookieName;
        var cookie = context.Request.Cookies[cookieName];
        return cookie.Value;
    }

    return base.GetVaryByCustomString(context, arg); 
}

I’m using the session state configuration section to get the session cookie name, so that if you changed the default “ASP.NET_SessionId” it will still work.

I hope you will find this handy. If you have more cache subjects you would like me to write about, please write in the comments.
In the next post I expect to demonstrate how to implement an OutputCacheAttribute that that enables you to choose another cache provider instead of the memory cache, so that you can use a distributed cache system like AppFabric or a Redis Cluster to store your rendered pages.

MEO Wallet API Client in .NET/C#

I’ve been playing with the MEO Wallet API that was released in a “preview” environment at the first day of Codebits.

In the very same day I had a working prototype of a slot machine, where you could buy credits to play with MEO Wallet. In the next day, we deployed it and added a redeem feature, so that users could cash-out after a jackpot.

Well, I decided to reuse some of the code that we did at Codebits to develop a generic MEO Wallet API Client. It was designed for .NET 4.5, uses HttpClient and has a demo project that you can play with.

Check it out: https://github.com/danielbcorreia/MeoWalletDotNetClient

 

Benchmark Driven Development and Parsing binary data in JavaScript

I’ve come across an interesting read on the development of a mysql client for Node.js. The full article can be found here:

https://github.com/felixge/faster-than-c

It’s a very interesting read on the competition among similar open-source projects nowadays, but what really made me think was the concept of Benchmark Driven Development. It is awesome, and i’ve seen projects like WebScaleSql use it but not naming it that.

Other thing that was impressive was the fact that in a given point in time, the mentioned mysql libraries had so much throughput that they could take down the actual mysql server. In fact, that could look that way with a single DB server, but with a cluster with many read-only slaves I think we could still use it (the article does not specify the type of commands that are being executed, so i’m assuming that they are talking about reads. scaling writes is much harder).

Anyway, I recommend that you read that article. It’s a 5 minute read, and it’s worth it.

Quick-start to MVC4 Bundling

After using MVC4’s bundling in a couple of web apps I got to a simple recipe:

  1. Add the NuGet package Microsoft.AspNet.Web.Optimization (http://nuget.org/packages/Microsoft.AspNet.Web.Optimization/1.0.0)
  2. On your Global.asax.cs file, add the following call on Application_Start:
    BundleConfig.RegisterBundles(BundleTable.Bundles);
  3. Create a class called BundleConfig in your App_Start folder, with a method named RegisterBundles:
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
        }
    }
  4. If you want to use optimizations on your debug environment, add the following line on top of the RegisterBundles method:
    BundleTable.EnableOptimizations = true; // force to show on debug mode
  5. Add your bundles to the RegisterBundles method, such as:
    bundles.Add(new StyleBundle("~/css/global").Include("~/Content/site.css"));
  6. If you are like me and you use virtual paths for css bundles that don’t match the real location of the files, you will have problems using the StyleBundle with relative image URIs. To solve this without changing your original css files, you can create a custom IBundleTransform that resolves the image path. My solution is largely based on this stackoverflow answer: http://stackoverflow.com/a/13019337/732733
    public class RelativePathResolverTransform : IBundleTransform
    {
    	public void Process(BundleContext context, BundleResponse response)
    	{
    		response.Content = String.Empty;
    
    		Regex pattern = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase);
    		// open each of the files
    		foreach (FileInfo cssFileInfo in response.Files)
    		{
    			if (cssFileInfo.Exists)
    			{
    				// apply the RegEx to the file (to change relative paths)
    				string contents = File.ReadAllText(cssFileInfo.FullName);
    				MatchCollection matches = pattern.Matches(contents);
    				// Ignore the file if no match 
    				if (matches.Count > 0)
    				{
    					string cssFilePath = cssFileInfo.DirectoryName;
    					string cssVirtualPath = RelativeFromAbsolutePath(context.HttpContext, cssFilePath);
    
    					foreach (Match match in matches)
    					{
    						// this is a path that is relative to the CSS file
    						string relativeToCSS = match.Groups[2].Value;
    						// combine the relative path to the cssAbsolute
    						string absoluteToUrl = Path.GetFullPath(Path.Combine(cssFilePath, relativeToCSS));
    
    						// make this server relative
    						string serverRelativeUrl = RelativeFromAbsolutePath(context.HttpContext, absoluteToUrl);
    
    						string quote = match.Groups[1].Value;
    						string replace = String.Format("url({0}{1}{0})", quote, serverRelativeUrl);
    						contents = contents.Replace(match.Groups[0].Value, replace);
    					}
    				}
    				// copy the result into the response.
    				response.Content = String.Format("{0}\r\n{1}", response.Content, contents);
    			}
    		}
    	}
    
    	private static string RelativeFromAbsolutePath(HttpContextBase context, string path)
    	{
    		var request = context.Request;
    		var applicationPath = request.PhysicalApplicationPath;
    		var virtualDir = request.ApplicationPath;
    		virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
    		return path.Replace(applicationPath, virtualDir).Replace(@"\", "/");
    	}
    }
  7. To make it easier to use, I also added a custom Bundle:
    public class ImageRelativeStyleBundle : StyleBundle
    {
        public ImageRelativeStyleBundle(string virtualPath)
            : base(virtualPath)
        {
            Transforms.Add(new RelativePathResolverTransform());
        }
    
        public ImageRelativeStyleBundle(string virtualPath, string cdnPath)
            : base(virtualPath, cdnPath)
        {
            Transforms.Add(new RelativePathResolverTransform());
        }
    }
  8. You can use it like this:
    bundles.Add(new ImageRelativeStyleBundle("~/css/jqueryui").Include
    (
    	"~/Content/themes/base/jquery.ui.core.css",
    	"~/Content/themes/base/jquery.ui.resizable.css",
    	"~/Content/themes/base/jquery.ui.selectable.css",
    	"~/Content/themes/base/jquery.ui.accordion.css",
    	"~/Content/themes/base/jquery.ui.autocomplete.css",
    	"~/Content/themes/base/jquery.ui.button.css",
    	"~/Content/themes/base/jquery.ui.dialog.css",
    	"~/Content/themes/base/jquery.ui.slider.css",
    	"~/Content/themes/base/jquery.ui.tabs.css",
    	"~/Content/themes/base/jquery.ui.datepicker.css",
    	"~/Content/themes/base/jquery.ui.progressbar.css",
    	"~/Content/themes/base/jquery.ui.theme.css"
    ));
  9. To use bundles in your views, I recommend adding the System.Web.Optimization namespace to /Views/Web.config, on the namespaces section:
    <namespaces>
    	...
    	<add namespace="System.Web.Optimization" />
    </namespaces>
  10. Now you just need to call Styles.Render(“~/css/jqueryui”) for the example above to work. For javascript you can use the Scripts.Render(“virtualpath”) call. If you need to specify custom attributes to your element, such as the media attribute for print css versions, you can build the element yourself and use the Styles.Url method, like so:
    <link href="@Styles.Url("~/css/print")" rel="stylesheet" type="text/css" media="print" />

I’ve successfully (but also painfully) integrated MVC4’s bundling and minification with dotless, for LESS CSS support. I’ll explain the necessary steps on the next blog post.



Update
In this post’s comments, Kenneth commented on the lack of support for debug mode when using Styles.Url in a link tag. To solve this issue, I’ve created some methods that add this functionality.

Notes: Because the Style class and its methods are static I can’t just overload their behavior nor add another extension method, so instead I added a separate class that you could use instead of Style. I took advantage of the DEBUG compilation constant to avoid some string manipulation on a production/release environment.

public static class Bundles
{
    public static IHtmlString Render(string path, object htmlAttributes)
    {
        return Render(path, new RouteValueDictionary(htmlAttributes));
    }

    public static IHtmlString Render(string path, IDictionary<string, object> htmlAttributes)
    {
        var attributes = BuildHtmlStringFrom(htmlAttributes);

#if DEBUG
        var originalHtml = Styles.Render(path).ToHtmlString();
        string tagsWithAttributes = originalHtml.Replace("/>", attributes + "/>");
        return MvcHtmlString.Create(tagsWithAttributes);
#endif

        string tagWithAttribute = string.Format(
            "<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\"{1} />", 
            Styles.Url(path), attributes);

        return MvcHtmlString.Create(tagWithAttribute);
    }

    private static string BuildHtmlStringFrom(IEnumerable<KeyValuePair<string, object>> htmlAttributes)
    {
        var builder = new StringBuilder();

        foreach (var attribute in htmlAttributes)
        {
            builder.AppendFormat(" {0}=\"{1}\"", attribute.Key, attribute.Value);
        }

        return builder.ToString();
    }
}

Usage:

@Bundles.Render("~/css/print", new { media = "print" })
 

Using RavenDB with ASP.NET Web API

Since the RC version of ASP.NET Web API came out I was having trouble using it with RavenDB, due to the latest’s JSON.Net version prerequisites.  Today I found out that there is a way to use both without having to use the unstable builds of RavenDB server (that support the same versions of JSON.Net as Web API).

You’ll probably want to run your RavenDB server instance on a separated process (not embedded), so you can now use a RavenDB client that supports the latest version on JSON.Net, thus resolving this issue. Then, if you need to configure the RavenDB server itself , you can just use the stable binaries.

RavenDB Client:
http://nuget.org/packages/RavenDB.Client/1.0.972

PS: If you still have troubles with JSON.Net’s version, be sure to try RavenDB Client Unstable/pre-release binaries from NuGet. The latest version is at http://nuget.org/packages/RavenDB.Client (select “Include Prerelease” in the Package Manager UI or add the “-Pre” parameter on the console). I’m running the latest unstable client binaries with a stable server build and I had no problems so far.

LINQ: To cache or not to cache

I’m now working more often with IEnumerables and IQueryables, and the more code I write the more nervous I get about the performance issues related to the transversal of these sequences. When writing code to fulfill a purpose I often forget about the multiple enumerations below LINQ’s syntactic sugar, but the feeling that something is not the way it is supposed to be emerges right after the first self-code review.

Today is a good day to talk about this, since I just read an article about Caching LINQ Results. In this article Chris Eargle talks about three techniques to use with LINQ:

  1. Delayed Execution (Lazy Loading)
  2. Materialization (Eager Loading)
  3. Memoization (Lazy Loading + Caching)

All these techniques have its own specific goals, but my purpose for this post is not to discuss when to use either. My real concern is about the limits of caching this kinds of sequences.

I know that memory nowadays is cheap, but if everyone made that assumption everyday we’d run out of memory on our servers faster than people can tweet “earthquake!” when the ground starts to move. What is the threshold for this kind of caching? Should there be a dedicated data-structure to host this information? What if the issue is not the memory that we use on this kind of caching, but the time it stays in memory before GC kicks in?

I will be experimenting with a few situations and searching to see if anyone has done the same. I’m thinking about exploring the following possibilities:

  • Create a data-structure to host the IEnumerable cache, limited to a specific size, and with a ring buffer-like strategy (removing the oldest cache) or probably some metric to evaluate the usage of a cache piece.
  • Use caching in several spots when needed, but use strategies like weak references, or even timeouts when the cache isn’t used in a specific time limit, to try to free up space as soon as possible.

I’d like to hear from you regarding these topics, do you have any experiences in this field?