Azure Redis Cache on ASP.NET Core


redisThe use of cache can increase application performance by storing strategic data in memory instead of having to obtain data for every request. Often, getting information from external resources, as database or services, can degrade application response time.

In this post, I'll show how to use the Azure Redis Cache to enable the use of cache on distributed servers, allowing the cache to be shared to more than one server. Azure Redis uses the open source framework Redis to implement the distributed cache.

To illustrate the use of Redis I will use the MyAppOnCloud application, created in post Publishing ASP.NET Core on Azure, where I published an ASP.NET Core application to three datacenters.

The first step is to create the cache service. In Portal Azure , you need to create a new Redis Cache as instructed in the following image:

 

pic01a

 

At the "New Redis Cache" blade, you need to provide the name of the cache that will compose the DNS, choose the signature, the resource group (I'm using the same set of the application), the data center and the consuming plan as:

 

pic02

 

Once the Azure Redis is set, it is now necessary to add the reference of the NuGet package Microsoft.Extensions.Caching.Redis.Core to the application. This reference can be added via NuGet Package Manager:

 

redis1

 

Or it can be added directly in the file project.json within the dependencies tag:

"Microsoft.Extensions.Caching.Redis.Core": "1.0.2"

 

After adding the reference, I double-check if it has been added successfully to the project:

 

ref

 

Now, we need to add the following code to the ConfigureServices method of the startup.cs class to configure the access to the cache Redis service.


services.AddDistributedRedisCache (option =>
{
option.Configuration = Configuration.GetConnectionString ("RedisConnection");
option.InstanceName = "master";
});


 

The AddDistributedRedisCache method, it is used to configure the service and it allows us to use the RegisCache via dependency injection (DI) in every part of the code that expects an instance object that implements the interface IDistributedCache. This association is performed by the services variable of the IServiceCollection type. I will illustrate this concept at the time of cache consumption further in this post.

 

Returning to the cache configuration, note that the connection setup with the Azure Redis service is obtained by RedisConnection configuration key. In this case, I added the key in appsettings.json file as:

 

“ConnectionStrings”: {
“RedisConnection”: “myapponcloud.redis…”
}

 

The follow image shows the full file:

 

appsettings

 

To populate the value of RedisConnection, you must go to Azure Portal and click on the settings of the Redis Cache service, click on the Access Key item and copy the primary key value, as shown:

 

rediskeys1

 

After setting the Redis service, I will implement the cache in HomeController class. Because the cache service has been added in DI container, now the Redis cache class (RedisCache) can be consumed anywhere in the application through dependency injection (DI).

 

I will add a constructor to the HomeController class to receive the instance of the object that implements the interface IDistributedCache. In this case, this instance is the RedisCache class that was configured through AddDistributedRedisCache method in the startup class.

 


private IDistributedCache _cache;

public HomeController (IDistributedCache cache)
{
     _cache = cache;
}

 

To exemplify the use of the cache, I will add the following code to the Index method to get the value of the "Time" key from the cache. If the value does not exist in cache, a value will be added to the cache:

 


public IActionResult Index ()

    string value = _cache.GetString("CacheTime");

            if (value == null)
            {
                value = DateTime.Now.ToString();

                var options = new DistributedCacheEntryOptions();
                options.SetSlidingExpiration(TimeSpan.FromMinutes(1));
                _cache.SetString("CacheTime", value, options );
            }
            ViewData["CacheTime"] = value;
            ViewData["CurrentTime"] = DateTime.Now.ToString();
   return View();
}

 

The next step is to change the Index page (Views / Home / Index.cshtml) to get the value returned from the cache. As I added the value of the cache in a ViewData, I just need to use it in the page as follows:

 

<H2> Azure Redis </ h2>
<Ul>
<Li> Value read from cache is: </ li>
@ViewData [ "CacheTime"]
</ Ul>
<br/>
<Ul>
<Li> Current value is: </ li>
@ViewData [ "CurrentTime"]
</ Ul>

 

Note that the view now shows the values of the cache and the current time obtained by the application:

 

view

 

Note the result of using the cache after updating the application in three data centers that I mentioned at the beginning of the post:

 

final

 

I hope you enjoyed.

 

More information on:
How to Use Azure Redis Cache
References:

Azure Redis Cache 101 - Introduction to Redis

Azure Redis Cache 102 - Application Patterns

Azure Redis Cache 103 - Failover and Monitoring

 

Comments (7)

  1. Sam says:

    You missed a vital piece of information here. What should the connection string look like?

    1. Great question, Sam. In this case, as I am using the Azure Redis, the connection string is generated automatically in the Azure Redis settings portal. Example: “myapponcloud.redis.cache.windows.net:6380,password=5JaumPds+uTqfnW3xL/Asdh/4wY8SRGVyp36cajxy50=,ssl=True,abortConnect=False”

  2. MichaCo says:

    Is there a workaround for using Azure Redis cache with DotnetCore on Linux?
    So far we are getting NotSupported Exceptions due to the DNS name in the connection string. Using IP address seems to not work with SSL

    Stacktrace if you want:

    Unhandled Exception: System.AggregateException: One or more errors occurred. (This platform does not support connecting sockets to DNS endpoints via the instance Connect and ConnectAsync methods, due to the potential for a host name to map to multiple IP addresses and sockets becoming invalid for use after a failed connect attempt. Use the static ConnectAsync method, or provide to the instance methods the specific IPAddress desired.) —> System.PlatformNotSupportedException: This platform does not support connecting sockets to DNS endpoints via the instance Connect and ConnectAsync methods, due to the potential for a host name to map to multiple IP addresses and sockets becoming invalid for use after a failed connect attempt. Use the static ConnectAsync method, or provide to the instance methods the specific IPAddress desired.
    at System.Net.Sockets.Socket.ThrowIfNotSupportsMultipleConnectAttempts()
    at System.Net.Sockets.Socket.BeginConnect(String host, Int32 port, AsyncCallback requestCallback, Object state)
    at System.Net.Sockets.SocketTaskExtensions.c.b__5_0(String targetHost, Int32 targetPort, AsyncCallback callback, Object state)
    at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2](Func`5 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, Object state, TaskCreationOptions creationOptions)
    at System.Threading.Tasks.TaskFactory.FromAsync[TArg1,TArg2](Func`5 beginMethod, Action`1 endMethod, TArg1 arg1, TArg2 arg2, Object state)
    at System.Net.Sockets.SocketTaskExtensions.ConnectAsync(Socket socket, String host, Int32 port)
    at StackExchange.Redis.SocketManager.BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log)
    at StackExchange.Redis.PhysicalConnection.BeginConnect(TextWriter log)
    at StackExchange.Redis.PhysicalBridge.GetConnection(TextWriter log)
    at StackExchange.Redis.ServerEndPoint..ctor(ConnectionMultiplexer multiplexer, EndPoint endpoint, TextWriter log)
    at StackExchange.Redis.ConnectionMultiplexer.d__119.MoveNext()
    — End of inner exception stack trace —
    at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
    at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
    at StackExchange.Redis.ConnectionMultiplexer.ConnectImpl(Func`1 multiplexerFactory, TextWriter log)
    at Microsoft.Extensions.Caching.Redis.RedisCache.Connect()
    at Microsoft.Extensions.Caching.Redis.RedisCache.GetAndRefresh(String key, Boolean getData)

    1. Are you using the Azure Redis Cache or do you have your own Redis Server?

  3. Steve W. says:

    Is there a way to set the SyncTimeout for the cache? It doesn’t appear the RedisCacheOptions support setting this value?

    1. In this case, you can add in the Redis Connection string:

      “RedisConnection”: “syncTimeout=2000,YOURREDISSERVER.redis.cache.windows.net:6380,…”

Skip to main content