Key Takeaways
- ASP.NET Core has a built-in distributed caching interface.
- Performance, shared data, and durability are the primary benefits of distributed caching.
- Couchbase Server is a memory-first database that is great for use as a distributed cache.
- NuGet packages make it easy to add Couchbase Server to your application.
- Using the "IDistrubutedCache" interface abstracts away the details and makes it easy to interact with cache in your ASP.NET Core controllers.
With the release of .NET Core 2.0, Microsoft has the next major version of the general purpose, modular, cross-platform and open source platform that was initially released in 2016. .NET Core has been created to have many of the APIs that are available in the current release of .NET Framework. It was initially created to allow for the next generation of ASP.NET solutions but now drives and is the basis for many other scenarios including IoT, cloud and next generation mobile solutions. In this series, we will explore some of the benefits .NET Core and how it can benefit not only traditional .NET developers but all technologists that need to bring robust, performant and economical solutions to market.
This InfoQ article is part of the series ".NET Core". You can subscribe to receive notifications via RSS.
Caching can help improve the performance of an ASP.NET Core application. Distributed caching is helpful when working with an ASP.NET application that’s deployed to a server farm or scalable cloud environment. Microsoft documentation contains examples of doing this with SQL Server or Redis, but in this post, I’ll show you an alternative. Couchbase Server is a distributed database with a memory-first (or optionally memory-only) storage architecture that makes it ideal for caching. Unlike Redis, it has a suite of richer capabilities that you can use later on as your use cases and your product expands. But for this blog post, I’m going to focus on it’s caching capabilities and integration with ASP.NET Core. You can follow along with all the code samples on Github.
Benefits of distributed caching
- Performance. A cache stores data in RAM for quick and easy retrieval. It will often be faster to retrieve data from this cache, rather than use the original source every time.
- Shared cache data. If you are using a multi-server deployment for your ASP.NET Core application, a load balancer could direct your user to any one of your ASP.NET Core servers. If the cached data is on the web servers themselves, then you need to turn on sticky sessions to make sure that user is always directed to the same ASP.NET Core server. This can lead to uneven loads and other networking issues - see this Stack Overflow answer for more details).
- Durability. If an ASP.NET Core web server goes down or you need to restart it for any reason, this won’t affect your cached data. It will still be in the distributed cache after the restart.
No matter which tool you use as a distributed cache (Couchbase, Redis, or SQL Server), ASP.NET Core provides a consistent interface for any caching technology you wish to use.
Installing Couchbase
The first step is to get the distributed cache server running. Choose the installation method that’s most convenient for you. You can use Docker or a cloud provider, or you can install it on your local machine (which is what I did for this blog post). It’s a free download, and you can use the free Couchbase Community edition. (The Enterprise Edition is also free and unlimited for pre-production use, but I’ll be using the Community edition in this blog post).
When you install Couchbase, you’ll open up your web browser and go through a short wizard. The default settings are fine for this blog post.
Once you’ve installed Couchbase, create a "bucket". This is where you will store your cached data. I called my bucket "infoqcache". I created an "Ephemeral" bucket (which is a memory-only option). You can also use a "Couchbase" bucket (which will store the data in memory first and persist to disk asynchronously).
The last step of setting up Couchbase is security. Add a Couchbase user with appropriate permissions to that bucket. I called my user "infoq" and gave it a password of "password" (please use something stronger in production!). In the Enterprise edition, there are a lot of roles to choose from, but for this simple use case we don’t need them. "Bucket Full Access" for infoq cache is enough.
Make sure you’ve completed all these installation steps before moving on to ASP.NET Core. Here are the steps with links to more detailed documentation.
- Install Couchbase (Follow the instructions on the downloads page)
- Setup Couchbase (Explore the Server Configuration)
- Created a bucket (Creating a Bucket)
- Created a user with permission to the bucket. (Creating and Managing Users with the UI)
Create a new ASP.NET Core Application
I’m going to create a sample ASP.NET Core API application to show the distributed caching capabilities of ASP.NET Core. This will be a small, simple application with two end points.
I’m using Visual Studio 2017. From there, I select File→New→Web→ASP.NET Core Web Application.
The next step is to select what kind of ASP.NET Core project template to use. I’m using a bare-bones "API" with no authentication and no Docker support.
This project has a ValuesController.cs
file. I’m going to replace most of the code in this class with my own code. Here is the first endpoint that I will create. It doesn’t use any caching and has a Thread.Sleep
to simulate high-latency data access (imagine replacing that Thread.Sleep
with a call to a slow web-service or a complex database query).
[Route("api/get")]
public string Get()
{
// generate a new string
var myString = Guid.NewGuid() + " " + DateTime.Now;
// wait 5 seconds (simulate a slow operation)
Thread.Sleep(5000);
// return this value
return myString;
}
Start that website (Ctrl+F5 in Visual Studio). You can use a tool like Postman to interact with the endpoint. But for this example, a browser is good enough. In my sample project, the site will launch to localhost:64921
, and I configured the endpoint with a route of api/get. So, in a browser I go to localhost:64921/api/get
:
This a trivial example, but it shows that this endpoint is a) getting some unique string value, and b) taking a long time to do it. Every time you refresh will be at least a 5-second wait. This would be a great place to introduce caching to improve latency and performance.
ASP.NET Core and Couchbase Integration
We now have an ASP.NET Core application that needs caching and a Couchbase Server instance that wants to help out. Let’s get them to work together.
The first step is to install a package from NuGet. You can use the NuGet UI to search for Couchbase.Extensions.Caching, or you can run this command in the Package Manager Console: Install-Package Couchbase.Extensions.Caching -Version 1.0.1
. This is an open-source project, and the full source code is available on Github.
NuGet will install all the packages you need for your ASP.NET Core application to talk to Couchbase Server and to integrate with ASP.NET Core’s built-in distributed caching capabilities.
Now open up the Startup.cs
file in the project. You will need to add some setup code to the ConfigureServices
method here.
services.AddCouchbase(opt =>
{
opt.Servers = new List<Uri>
{
new Uri("http://localhost:8091")
};
opt.Username = "infoq";
opt.Password = "password";
});
services.AddDistributedCouchbaseCache("infoqcache", opt => { });
(I also added using Couchbase.Extensions.Caching;
and using Couchbase.Extensions.DependencyInjection;
at the top of the file, but I use ReSharper to identify and add those for me automatically).
In the above code, AddCouchbase
and AddDistributedCouchbaseCache
are extension methods that add to the built-in ASP.NET Core IServiceCollection
interface.
With AddCouchbase
, I’m telling ASP.NET Core how to connect to Couchbase, giving it the user/password I mentioned earlier in the post.
With AddDistributedCouchbaseCache
, I’m telling ASP.NET Core how to use Couchbase as a distributed cache, specifying the name of the bucket I mentioned earlier in the post.
Documentation for this extension is available on Github. Don’t forget to add cleanup/tear downcode in the ConfigureServicesmethod.
Using ASP.NET Core’s distributed caching
Now that we’ve configured ASP.NET Core to know how to cache let’s put it to use in a simple example.
The simplest thing we can do with distributed caching is to injectit into the ValuesController and use an IDistributedCachedirectly.
First, add IDistributedCacheas a parameter to the constructor.
public ValuesController(IDistributedCachecache)
{
_cache = cache;
}
Since we already configured the distributed cache in Startup.cs
, ASP.NET Coreknows how to set this parameter (using dependency injection). Now,_cache is available in ValuesController
to get/set values in the cache. I wrote another endpoint called GetUsingCache
. This will be just like the Get endpoint earlier, except it will use caching. After the first call, it will store the value and subsequent calls will no longer reach the Thread.Sleep
.
[Route("api/getfast")]
public string GetUsingCache()
{
// is the string already in the cache?
var myString = _cache.GetString("CachedString1");
if (myString == null)
{
// string is NOT in the cache
// generate a new string
myString = Guid.NewGuid() + " " + DateTime.Now;
// wait 5 seconds (simulate a slow operation)
Thread.Sleep(5000);
// put the string in the cache
_cache.SetString("CachedString1", myString);
// cache only for 5 minutes
/*
_cache.SetString("CachedString1", myString,
new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(5)});
*/
}
return myString;
}
The first request to /api/getfast will still be slow but refresh the page, and the next reques twill pull from the cache. Switch back to the Couchbase console, click "Buckets" in the menu, and you’ll see that the "infoqcache" bucket now has 1 item.
One important thing to point out in ValuesController
is that none if it is directly coupled to any Couchbase library. It all depends on the ASP.NET Core libraries. This common interface gives you the ability to use Couchbase distributed caching any place else that uses the standard Microsoft ASP.NET Core libraries. Also, it’s all encapsulated behind the IDistributedCache interface, which makes it easier for you to write tests.
In the above example, the cached data will live in the cache indefinitely. But you can also specify an expiration for the cache. In the below example, the endpoint will cache data for 5 minutes (on a sliding expiration).
_cache.SetString("CachedString1", myString,
new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(5)});
Summary
ASP.NET Core can work hand-in-hand with Couchbase Server for distributed caching. ASP.NET Core’s standard distributed cache interface makes it easy for you start working with the cache. Next, get your ASP.NET Core distributed applications up to speed with caching.
If you have questions or comments about the Couchbase.Extensions.Caching project, make sure to check out the GitHub repository or the Couchbase .NET SDK forums.
About the Author
Matthew D. Groves is a guy who loves to code. It doesn't matter if it's C#, jQuery, or PHP: he'll submit pull requests for anything. He has been coding professionally ever since he wrote a QuickBASIC point-of-sale app for his parent's pizza shop back in the 90s. He currently works as a Developer Advocate for Couchbase. He is the author of AOP in .NET (published by Manning), and is also a Microsoft MVP.
With the release of .NET Core 2.0, Microsoft has the next major version of the general purpose, modular, cross-platform and open source platform that was initially released in 2016. .NET Core has been created to have many of the APIs that are available in the current release of .NET Framework. It was initially created to allow for the next generation of ASP.NET solutions but now drives and is the basis for many other scenarios including IoT, cloud and next generation mobile solutions. In this series, we will explore some of the benefits .NET Core and how it can benefit not only traditional .NET developers but all technologists that need to bring robust, performant and economical solutions to market.
This InfoQ article is part of the series ".NET Core". You can subscribe to receive notifications via RSS.