Databases, How to, Redis Cache
MVC movie app with Azure Redis Cache in 15 minutes
By Rick Anderson Programmer writer for Azure and ASP.NET MVC
Posted on
3 min read
Updated 25 October 2014 – The Redis Cache in now GA
The new Azure Redis Cache is really easy to plug into your Azure web app I had it plugged into my MVC Movie sample app, deployed to Azure and running in under 17 minutes (15 minutes to plug it in and test locally)
The cache is about 100 times faster than banging on a database By fetching hot data from the cache, you not only speed up your app but you can reduce the DB load and increase its responsiveness for other queries
You can download my completed sample here
This is what I did to plug the Redis cache into my MVC movie sample
- Log on to the Azure portal and select create a new cache
This step can take up to 15 minutes, but I’m not counting that in my time For complete instructions see How to Use Azure Redis Cache It’s critical you create the cache is the same location (data center) that you create your web site I tested this by moving my web site to a different location, and cache latency increased by a factor of 25 For detailed instructions see Create a Redis Cache You can download my MvcMovie as a starter sample Alternatively, you can download my completed sample and update the cache endpoint ( URL ) and credentials, then follow along - Copy the cache name
rediscachewindowsnet and the password (hit the keys button in the properties blade of the portal to see the cache name and password) - Add the NuGet package StackExchangeRedis You’ll also need to restore the NuGet packages in my sample if you’re using that
- From the package manager console, run Update-Database You might have to exit and restart Visual Studio after restoring NuGet packages to see the Update-Database command
- Plug the connection info into your controller:
public class MoviesController : Controller { private MovieDBContext db = new MovieDBContext(); private static LazylazyConnection = new Lazy (() => { return ConnectionMultiplexerConnect(KeysconStr); }); public static ConnectionMultiplexer Connection { get { return lazyConnectionValue; } }
Warning: Never store credentials is source code To keep this sample simple, I’m showing them in the source code See Windows Azure Web Sites: How Application Strings and Connection Strings Work for information on how to store credentials
Note that the connection is stored as a static variable so you don’t have to create a new connection on each request A get method is used so you can check that the connection is valid, and if the connection has been dropped, the connection is reestablished
Create a new class containing the SampleStackExchangeRedisExtensions class:
public static class SampleStackExchangeRedisExtensions { public static T Get(this IDatabase cache, string key) { return Deserialize (cacheStringGet(key)); } public static object Get(this IDatabase cache, string key) { return Deserialize
The SampleStackExchangeRedisExtensions class makes it easy to cache any serializable type You’ll need to add the [Serializable] attribute to your model
[Serializable] public class Movie
Find all the instances of Movie movie = dbMoviesFind(id);
and replace them with:
//Movie movie = dbMoviesFind(id); Movie movie = getMovie((int)id);
In the POST Edit and Delete methods, evict the cache with the following call:
ClearMovieCache(movieID);
Add the following code to the movie controller The getMovie method uses the standard on demand cache aside approach
Movie getMovie(int id) { Stopwatch sw = StopwatchStartNew(); IDatabase cache = ConnectionGetDatabase(); Movie m = (Movie)cacheGet(idToString()); if (m == null) { Movie movie = dbMoviesFind(id); cacheSet(idToString(), movie); StopWatchMiss(sw); return movie; } StopWatchHit(sw); return m; } private void ClearMovieCache(int p) { IDatabase cache = connectionGetDatabase(); if (cacheKeyExists(pToString())) cacheKeyDelete(pToString()); } void StopWatchEnd(Stopwatch sw, string msg) { swStop(); double ms = swElapsedTicks / (StopwatchFrequency / (10000)); ViewBagcacheMsg = msg + msToString() + ” PID: ” + ProcessGetCurrentProcess()IdToString(); } void StopWatchMiss(Stopwatch sw) { StopWatchEnd(sw, “Miss – MS:”); } void StopWatchHit(Stopwatch sw) { StopWatchEnd(sw, “Hit – MS:”); }
Add the ViewBagcacheMsg code to the ViewsShared_Layoutcshtml file so you get timing information on every page:
@RenderBody()@ScriptsRender("~/bundles/jquery") @ScriptsRender("~/bundles/bootstrap") @RenderSection("scripts", required: false)