How to use Redis and Lua Scripts in a C# ASP.NET Core Microservice Architecture
Tags: dotnet, redis, microservices, architecture
Published: 2021-07-22 20:23:33

Use StackExchange.Redis and run Redis in Docker to Cache Aggregated Database Data for a Scaled C# Application

![](https://cdn-images-1.medium.com/max/2722/1*aO2_ixUXznFFlGZoWuUtnw.png)

**Redis has many great use-cases** like session or full page **caching**, **queues**, **pub/sub** and **leaderboards/counting**, etc. Usable in your applications and microservice architectures.

In this article, I show you how to use **[StackExchange.Redis](https://stackexchange.github.io/StackExchange.Redis/) in ASP.NET Core** to access a **Redis server running in Docker**.

The **[example application](https://dev.to/christianzink/how-to-use-database-sharding-and-scale-an-asp-net-core-microservice-architecture-5h5l) lets users write posts in categories**. It uses Redis to **cache aggregated data** for top categories and users while the **database stores the item/line data as “source of truth”**.

This article starts with a **simple first use-case** and then advances to a more **complex one with Lua scripting** and **the inbox pattern**.

### Contents

1. Setup Redis in Docker and Prepare the .NET Core Project

1. Implement the Top Categories

1. Top Users, the Inbox Pattern, and Lua Scripting for Atomicity

1. Final Thoughts and Outlook

-----------


## 1. Setup Redis in Docker and Prepare the .NET Core Project

**Install [Docker Desktop](https://hub.docker.com/editions/community/docker-ce-desktop-windows)**

Create the Redis container:

    C:\dev>docker run --name redis -d redis

**Use [Visual Studio Community](https://visualstudio.microsoft.com/en/vs/community/)** (it’s free) with the ASP.NET and web development workload. Open an ASP.NET Core 5 Web API project with EntityFramework.

**Install the following NuGet packages**:

* Microsoft.EntityFrameworkCore.Tools

* StackExchange.Redis

**Create the following entities:**

{% gist https://gist.github.com/Chriz76/78c045f6f71bd68b69adef4230ff4cda
%}

-----------


## 2. Implement the Top Categories

### Add Top Categories

Increment the count for a category when inserting a new post.

* Line 1: Connect a Redis multiplexer

* Lines 7–11: Insert the post and update the category count in a transaction

* Lines 13–15: Read the latest count for the category and add/update the entry in the Redis [sorted set](https://redislabs.com/ebook/part-2-core-concepts/chapter-3-commands-in-redis/3-5-sorted-sets/) “*CategoriesByPostCount*”

{% gist https://gist.github.com/Chriz76/1d7c196b9dbfb5c2095d4fd82ac90c63
%}

> The [ZADD](https://redis.io/commands/ZADD) command has an optional *GT* parameter: The value is only updated if it is greater than the current value. This prevents race conditions where another thread also increased and updated the count.

### Read Top Categories

*SortedSetRangeByRankWithScore* is a wrapper for the Redis [ZRANGE](https://redis.io/commands/zrange) command. It reads the category and the count. Use the *start* and *end* parameters for paging.

{% gist https://gist.github.com/Chriz76/9260a4b11dae6eed77117a5bff2519ac
%}

-----------


## 3. Top Users, the Inbox Pattern, and Lua Scripting for Atomicity

For the users, I show you how to count the posts in Redis instead of the DB. This is e.g. needed in a sharded environment where the user’s posts are scattered over all shards.

### Atomically Add Posts with Lua Scripting

The *PublishOutstandingPosts* method sends new posts to Redis. It uses the inbox pattern and a [Lua script](https://redislabs.com/ebook/part-3-next-steps/chapter-11-scripting-redis-with-lua/) to make the operation “idempotent”.

*Further reading: [Outbox, Inbox patterns and delivery guarantees explained](https://event-driven.io/en/outbox_inbox_patterns_and_delivery_guarantees_explained/)*

* Line 3–8: Prepare the Lua script

* Line 13: Read the last sent post ID from Redis

* Line 15: Load the unsent posts from the DB

* Line 17–21: Execute the Lua script to add the post to the user

* Line 22: Set the post count for the user in *UsersByPostCount*

* Line 25: Update the last sent ID after all operations are finished

{% gist https://gist.github.com/Chriz76/b576fd5c2b8c648af3f54dabe59a5a96
%}

The Lua script tries to add the post ID and timestamp to the *PostsByTimestamp* sorted set of the user.

If it can add the key, it also increments the *PostCount* of the user. The script makes the ZADD and ZINCRBY commands atomic. If the post ID already exists, it returns the existing *PostCount*.
> An extra counter per user is needed so that all key parameters map to the same [Redis hash tag](https://redislabs.com/blog/redis-clustering-best-practices-with-keys/). And therefore would be placed on the same Redis shard. The curly braces like in the key “{User:5}:PostsByTimestamp” are signifiers for a Redis hash tag.

### Read the Top Users

Use *SortedSetRangeByRankWithScore* to read the IDs of the top users. Then read the names:

{% gist https://gist.github.com/Chriz76/ceccec7740ec5dd65a9df89a07db5d4e
%}

-----------


## 4. Final Thoughts and Outlook

You used **StackExchange.Redis to access Redis from C#**. See [my previous article](https://dev.to/christianzink/how-to-cache-aggregated-data-with-redis-and-lua-scripts-for-a-scaled-microservice-architecture-4k3e) if you want to **manually access Redis via redis-cli** or want **more information about the example data model and use-cases**.

The code in this article focuses on the Redis-related part. The **basis for the code can be found in the solution from [my article about database sharding](https://dev.to/christianzink/how-to-use-database-sharding-and-scale-an-asp-net-core-microservice-architecture-5h5l)** if you want to build and run the service.

There are **many other use-cases for you to use Redis in your applications!**

**Please contact me if you have any questions, ideas, or suggestions.**