Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating a Very Simple Console Chat App using C# and Redis Pub/Sub

0.00/5 (No votes)
20 Dec 2017 1  
Creating a very simple console chat app using C# (.NET Core) and Redis pub/sub feature, just with 55 lines of code

Introduction

This article is for beginners in Redis Pub/Sub. Actually, Redis itself from its pub/sub documentation has a nice sample chat app written in Ruby here (try check it out), but in this article, we are going to learn about Redis pub/sub and create a very simple chat app (55 lines of code including newlines and comments) using C# (.NET Core) and Redis, we'll see the things that we need to consider from this application as well later.

Background

Redis is an open source, in-memory data structure store, used as a database, cache and message broker. It's one of NoSQL databases. Basically, it's a key/value store with some other powerful features (one of them is pub/sub).

Requirements

In order to follow this article and make our hands dirty with the code, we need to have:

  • Redis. We can have Redis server ready from Microsoft Azure or Amazon Web Services, or if you don't want to sign up to any cloud service, you can install Redis server on your computer. This also assumes that you already know how to use -at least the basic of- redis-cli.

  • .NET Core. As we know, .NET Core runs on Windows, Linux, and macOS / OS X.

  • Source Code Editor or IDE. We need this of course, but for Windows (or Mac), it's recommended to use Visual Studio. We can use other source code editor other than Visual Studio if we want as long as we have .NET Core installed.

Redis Pub/Sub Basic

Citing from Wikipedia, publish–subscribe is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.

As we mentioned before, Redis is not only key/value server, but it's also a messaging server. With Redis, we can do publish-subscribe. Redis has a good documentation for its pub/sub (or publish-subscribe) feature here. But in simple sentence, Redis publish-subscribe enables us to do quick messaging and communication between processes.

It needs to be mentioned that Redis pub/sub has no relation to the key space. It was made to not interfere with it on any level, including database numbers.

Redis has simple commands to enable publish-subscribe. In Redis CLI, the command to subscribe to a channel is pretty simple.

SUBSCRIBE channel_one channel_two

In the example above, client subscribes to channels with name channel_one and channel_two. A client can subscribe to more than one channel.

If we open another client (redis-cli or other interactive tool for Redis) without closing the other client for subscribing and try PUBLISH command like this.

PUBLISH channel_one "Hey Guys!"

The message will be heard to the subscribers. We can see the example below (gif).

Redis Pub/Sub Demo (gif)

Alright, that's for the basic. Actually, Redis has other commands related with pub/sub, they are UNSUBSCRIBE for unsubscribing channel(s), PSUBSCRIBE for pattern matching subscription for channel name (using glob-style pattern), and PUNSUBSCRIBE. Let's go to our very simple chat app.

Creating Simple Chat App

In this section, we are going to create a very simple chat app using C# with only 55 lines of code. This article assumes you're using Visual Studio.

Let's begin. First things first, create a console app using .NET Core, you can name it "SimpleChatApp". After that, we need to get/install this nuget package: StackExchange.Redis to communicate with Redis, this is Redis client library for .NET Languages (C#, etc.), I recommend you to see the documentations.

We'll do it step by step. First step, we need to create the connection to Redis.

using StackExchange.Redis;
using System;

namespace SimpleChatApp
{
      class Program
      {
            private const string RedisConnectionString = "localhost";
            private static ConnectionMultiplexer connection =
              ConnectionMultiplexer.Connect(RedisConnectionString);

            private const string ChatChannel =
                    "Chat-Simple-Channel"; // Can be anything we want.
            private static string userName = string.Empty;

            static void Main()
            {
                  Console.WriteLine("Hello World!");
            }
      }
}

It's good to know that ConnectionMultiplexer implements IDisposable, normally we need to reuse the object for the entire application lifetime. In the above code, we don't use using block, because after we close the console application, it will be disposed automatically.

For the connection string configuration, instead of using localhost, we can use Microsoft Azure Cache or other cloud service for Redis. For the configuration documentation, we can check it here.

Let's continue. In Main() method, write this code:

static void Main()
{
      // Enter name and put it into variable userName
      Console.Write("Enter your name: ");
      userName = Console.ReadLine();

      // Create pub/sub
      var pubsub = connection.GetSubscriber();

      // Subscriber subscribes to a channel
      pubsub.Subscribe(ChatChannel, (channel, message) => MessageAction(message));

      // Notify subscriber(s) if you're joining
      pubsub.Publish(ChatChannel, $"'{userName}' joined the chat room.");

      // Messaging here
      while (true)
      {
            pubsub.Publish(ChatChannel, $"{userName}: {Console.ReadLine()}  " +
              $"({DateTime.Now.Hour}:{DateTime.Now.Minute})");
      }
}

private static void MessageAction(RedisValue message)
{
      // We'll implement it later, to show the message.
      throw new NotImplementedException();
}

We can see that from the code above, in order to subscribe, we need to pass the channel name as the first parameter and then the handler/callback as the second parameter. For the second parameter, we pass Action with two parameter, the channel and the message. For the action, we create MessageAction. We don't need channel object here since we are only concerned about the message. For publishing the message, just like PUBLISH command before, we need to pass the channel name and then the message itself.

We use MessageAction to print the message, let's write our method with the code below:

static void MessageAction(string message)
{
      int initialCursorTop = Console.CursorTop;
      int initialCursorLeft = Console.CursorLeft;

      Console.MoveBufferArea(0, initialCursorTop, Console.WindowWidth,
                             1, 0, initialCursorTop + 1);
      Console.CursorTop = initialCursorTop;
      Console.CursorLeft = 0;

      // Print the message here
      Console.WriteLine(message);

      Console.CursorTop = initialCursorTop + 1;
      Console.CursorLeft = initialCursorLeft;
}

Let's put it all together, the code will look like this:

using StackExchange.Redis;
using System;

namespace SimpleChatApp
{
      class Program
      {
            private const string RedisConnectionString = "localhost";
            private static ConnectionMultiplexer connection =
              ConnectionMultiplexer.Connect(RedisConnectionString);

            private const string ChatChannel = "Chat-Simple-Channel";
            private static string userName = string.Empty;

            static void Main()
            {
                  // Enter name and put it into variable userName
                  Console.Write("Enter your name: ");
                  userName = Console.ReadLine();

                  // Create pub/sub
                  var pubsub = connection.GetSubscriber();

                  // Subscriber subscribes to a channel
                  pubsub.Subscribe(ChatChannel,
                        (channel, message) => MessageAction(message));

                  // Notify subscriber(s) if you're joining
                  pubsub.Publish(ChatChannel, $"'{userName}' joined the chat room.");

                  // Messaging here
                  while (true)
                  {
                      pubsub.Publish(ChatChannel, $"{userName}: {Console.ReadLine()}  " +
                          $"({DateTime.Now.Hour}:{DateTime.Now.Minute})");
                  }
            }

            static void MessageAction(string message)
            {
                  int initialCursorTop = Console.CursorTop;
                  int initialCursorLeft = Console.CursorLeft;

                  Console.MoveBufferArea(0, initialCursorTop, Console.WindowWidth,
                      1, 0, initialCursorTop + 1);
                  Console.CursorTop = initialCursorTop;
                  Console.CursorLeft = 0;

                  // Print the message here
                  Console.WriteLine(message);

                  Console.CursorTop = initialCursorTop + 1;
                  Console.CursorLeft = initialCursorLeft;
            }
      }
}

That's it! Build the project.

Note that if we use .NET Core, we can run the application using this command (in the output DLL directory, bin/Debug or bin/Release) using Command Prompt or Terminal if you're using Linux:

dotnet SimpleChatApp.dll

Let's see how it works.

Simple Chat App with Redis Pub-Sub Demo (gif)

We've created a chat app, just for fun! As long as it's connected to Redis (or Redis in the cloud service), we can chat.

Things We Need to Consider

We need to know that with this application, Redis connections are opened/created per application by default, and it's not ideal. If we use Redis from Microsoft Azure service or some other cloud services for Redis, there is a maximum number of client connections there.

It's also good to mention that StackExchange.Redis client library by default opens two connections to Redis, one for interactive command, and one for pub/sub. So, this application creates two connections to Redis (per application). If we have Redis installed, we can see the statistics of Redis connections using this command:

redis-cli --stat

Remember, this is just a very simple chat app, but we can still use it for fun knowing the caveats. It would be better if we use client-server application, and host it somewhere.

Have fun! :)

History

  • 21st December, 2017: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here