Skip to main content

How to connect to Google Cloud Redis using AUTH and TLS/SSL, and provide a local development environment using Docker Compose. The API controller allows you to perform CRUD operations on the Redis database.

---
title: How to connect to GCP Redis Instance in .NET Core
subtitle: How to connect to Google Cloud Redis using AUTH and TLS/SSL, and provide a local development environment using Docker Compose. The API controller allows you to perform CRUD operations on the Redis database.
author: Jon LaBelle
date: September 18, 2024
snippet: https://jonlabelle.com/snippets/view/markdown/how-to-connect-to-gcp-redis-instance-in-net-core
notoc: false
---

Let's go through the steps to achieve this:

1. **Install Required Packages**: Install the `StackExchange.Redis` package.
2. **Configure Redis Connection**: Set up the connection to Google Cloud Redis using the AUTH string and TLS/SSL.
3. **Dependency Injection**: Create a Redis client class for CRUD operations and register it with the dependency injection container.
4. **Docker Compose**: Create a `docker-compose.yml` file for local development with services for Redis, PostgreSQL, .NET Core API, and Vue.js UI.
5. **Example `appsettings.json`**: Include the required Redis connection settings for SSL/TLS.
6. **API Controller**: Create an API controller for CRUD operations.
7. **Dispose of ConnectionMultiplexer**: Ensure the `ConnectionMultiplexer` is disposed of properly.
8. **Dockerfiles**: Create Dockerfiles for each service.

### Step 1: Install Required Packages

Run the following command to install the necessary package:

```sh
dotnet add package StackExchange.Redis
```

### Step 2: Configure Redis Connection

Create a configuration class and a service to manage the Redis connection.

#### RedisConfig.cs

```csharp
public class RedisConfig
{
    public string ConnectionString { get; set; }
    public string AuthString { get; set; }
    public bool UseSsl { get; set; }
    public bool ValidateServerCertificate { get; set; }
}
```

#### RedisService.cs

```csharp
using StackExchange.Redis;
using System;
using System.Security.Cryptography.X509Certificates;

public class RedisService : IDisposable
{
    private readonly ConnectionMultiplexer _redis;

    public RedisService(RedisConfig config)
    {
        var options = ConfigurationOptions.Parse(config.ConnectionString);
        options.Password = config.AuthString;
        options.Ssl = config.UseSsl;
        options.CertificateValidation += (sender, certificate, chain, sslPolicyErrors) =>
        {
            if (config.ValidateServerCertificate)
            {
                // Implement your certificate validation logic here
                return sslPolicyErrors == System.Net.Security.SslPolicyErrors.None;
            }
            return true;
        };

        _redis = ConnectionMultiplexer.Connect(options);
    }

    public IDatabase GetDatabase() => _redis.GetDatabase();

    public void Dispose()
    {
        _redis?.Dispose();
    }
}
```

### Step 3: Dependency Injection

Create a Redis client class for CRUD operations and register it with the dependency injection container.

#### RedisClient.cs

```csharp
using StackExchange.Redis;

public class RedisClient
{
    private readonly IDatabase _database;

    public RedisClient(RedisService redisService)
    {
        _database = redisService.GetDatabase();
    }

    public void Create(string key, string value)
    {
        _database.StringSet(key, value);
    }

    public string Read(string key)
    {
        return _database.StringGet(key);
    }

    public void Update(string key, string value)
    {
        _database.StringSet(key, value);
    }

    public void Delete(string key)
    {
        _database.KeyDelete(key);
    }
}
```

#### Startup.cs

```csharp
public void ConfigureServices(IServiceCollection services)
{
    var redisConfig = Configuration.GetSection("RedisConfig").Get<RedisConfig>();
    services.AddSingleton(redisConfig);
    services.AddSingleton<RedisService>();
    services.AddSingleton<RedisClient>();

    // Other service registrations
}
```

### Step 4: Docker Compose

Create a `docker-compose.yml` file for local development with services for
Redis, PostgreSQL, .NET Core API, and Vue.js UI.

#### docker-compose.yml

```yaml
version: '3.8'

services:
  redis:
    image: redis:alpine
    ports:
      - '6379:6379'
    environment:
      - REDIS_PASSWORD=yourpassword
    command: ['redis-server', '--requirepass', 'yourpassword']

  postgres:
    image: postgres:alpine
    environment:
      POSTGRES_USER: yourusername
      POSTGRES_PASSWORD: yourpassword
      POSTGRES_DB: yourdatabase
    ports:
      - '5432:5432'

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    ports:
      - '5000:80'
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    depends_on:
      - redis
      - postgres

  ui:
    build:
      context: ./ui
      dockerfile: Dockerfile
    ports:
      - '8080:8080'
    depends_on:
      - api

networks:
  default:
    driver: bridge
```

### Step 5: Example `appsettings.json`

Include the required Redis connection settings for SSL/TLS.

#### appsettings.json

```json
{
  "RedisConfig": {
    "ConnectionString": "your-redis-instance-ip:6379",
    "AuthString": "your-auth-string",
    "UseSsl": true,
    "ValidateServerCertificate": true
  },

  "ConnectionStrings": {
    "PostgresConnection": "Host=postgres;Database=yourdatabase;Username=yourusername;Password=yourpassword"
  }
}
```

### Step 6: API Controller

Create an API controller for CRUD operations.

#### ExampleController.cs

```csharp
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("[controller]")]
public class ExampleController : ControllerBase
{
    private readonly RedisClient _redisClient;

    public ExampleController(RedisClient redisClient)
    {
        _redisClient = redisClient;
    }

    [HttpPost]
    public IActionResult Create([FromBody] KeyValuePair<string, string> item)
    {
        _redisClient.Create(item.Key, item.Value);

        return Ok();
    }

    [HttpGet("{key}")]
    public IActionResult Read(string key)
    {
        var value = _redisClient.Read(key);

        if (string.IsNullOrEmpty(value))
        {
            return NotFound();
        }

        return Ok(value);
    }

    [HttpPut]
    public IActionResult Update([FromBody] KeyValuePair<string, string> item)
    {
        if (string.IsNullOrEmpty(_redisClient.Read(item.Key)))
        {
            return NotFound();
        }

        _redisClient.Update(item.Key, item.Value);

        return Ok();
    }

    [HttpDelete("{key}")]
    public IActionResult Delete(string key)
    {
        if (string.IsNullOrEmpty(_redisClient.Read(key)))
        {
            return NotFound();
        }

        _redisClient.Delete(key);

        return Ok();
    }
}
```

### Step 7: Dockerfiles

Create Dockerfiles for each service.

#### api/Dockerfile

```Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build
WORKDIR /src
COPY ["YourApiProject.csproj", "./"]
RUN dotnet restore "./YourApiProject.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "YourApiProject.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "YourApiProject.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "YourApiProject.dll"]
```

#### ui/Dockerfile

```Dockerfile
FROM node:alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["npm", "run", "serve"]
```

### Final Code Structure

1. **RedisConfig.cs**: Configuration class for Redis.
2. **RedisService.cs**: Service class to manage Redis connection.
3. **RedisClient.cs**: Client class for Redis CRUD operations.
4. **Startup.cs**: Register Redis service and client with dependency injection.
5. **docker-compose.yml**: Docker Compose file for local development.
6. **appsettings.json**: Configuration file with Redis connection settings.
7. **ExampleController.cs**: API controller for CRUD operations.
8. **api/Dockerfile**: Dockerfile for .NET Core API.
9. **ui/Dockerfile**: Dockerfile for Vue.js UI.

This setup should help you connect to Google Cloud Redis with AUTH and TLS/SSL,
and also provide a local development environment using Docker Compose. The API
controller allows you to perform CRUD operations on the Redis database. The
`ConnectionMultiplexer` is properly disposed of when the singleton is disposed.
All services in the Docker Compose file can communicate with each other on the
same network using the respective Alpine variant for all Docker base images.