CSharp Configuration Handling

From bibbleWiki
Revision as of 23:43, 15 December 2025 by Iwiseman (talk | contribs) (Created page with "=Introduction= Struggled with the right way to do configuration as there were two approaches so thought I would right down the one that works for me in 2025 =Example Redis Service= ==Create a Config to hold the Setting== <syntaxhighlight lang="c#"> namespace Infrastructure.Caching.Configuration; using Domain.Interfaces.Configuration; public class CacheOptions : ICacheConfig { public string ConnectionString { get; set; } = string.Empty; public string InstanceNam...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

Struggled with the right way to do configuration as there were two approaches so thought I would right down the one that works for me in 2025

Example Redis Service

Create a Config to hold the Setting

namespace Infrastructure.Caching.Configuration;

using Domain.Interfaces.Configuration;

public class CacheOptions : ICacheConfig
{
    public string ConnectionString { get; set; } = string.Empty;
    public string InstanceName { get; set; } = "MyApp:";
    public TimeSpan DefaultTtl { get; set; } = TimeSpan.FromMinutes(5);
}

Create a Service to do it

namespace Infrastructure.Caching.Services;

using System.Text.Json;
using Domain.Interfaces.Caching;
using Domain.Interfaces.Configuration;
using Microsoft.Extensions.Caching.Distributed;

public class RedisCacheService(IDistributedCache cache, ICacheConfig config) : ICacheService
{
    private readonly IDistributedCache _cache = cache;
    private readonly ICacheConfig _config = config;

    public async Task<T?> GetAsync<T>(string key, CancellationToken ct = default)
    {
        var namespacedKey = $"{_config.InstanceName}{key}";
        var cached = await _cache.GetStringAsync(namespacedKey, ct);
        return cached is null ? default : JsonSerializer.Deserialize<T>(cached);
    }

    public async Task SetAsync<T>(string key, T value, TimeSpan? ttl = null, CancellationToken ct = default)
    {
        var namespacedKey = $"{_config.InstanceName}{key}";
        var serialized = JsonSerializer.Serialize(value);

        await _cache.SetStringAsync(
            namespacedKey,
            serialized,
            new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = ttl ?? _config.DefaultTtl
            },
            ct);
    }

    public Task RemoveAsync(string key, CancellationToken ct = default)
    {
        var namespacedKey = $"{_config.InstanceName}{key}";
        return _cache.RemoveAsync(namespacedKey, ct);
    }
}

Add IServiceCollection Extension for Startup

    public static IServiceCollection AddCachingService(this IServiceCollection services, IConfiguration config)
    {
        // Read Cache Options from appsettings.json
        services.Configure<CacheOptions>(config.GetSection("Cache"));

        // Register ICacheConfig for DI
        services.AddSingleton<ICacheConfig>(sp => sp.GetRequiredService<IOptions<CacheOptions>>().Value);

        // Register Redis as IDistributedCache
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = config["Cache:ConnectionString"];
            options.InstanceName = config["Cache:InstanceName"];
        });

        // Register RedisCacheService
        services.AddSingleton<ICacheService, RedisCacheService>();

        return services;
    }

Make an appsetting.json

Here is my example appsetting.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "System.Net.Http": "Warning",
      "Microsoft": "Warning",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "Cache": {
    "ConnectionString": "localhost:6379",
    "InstanceName": "DvdrentalApi_"
  }
}

Next read them in with a IServiceCollection extension

    public static IServiceCollection AddCachingService(this IServiceCollection services, IConfiguration config)
    {
        // Read Cache Options from appsettings.json
        services.Configure<CacheOptions>(config.GetSection("Cache"));

        // Register ICacheConfig for DI
        services.AddSingleton<ICacheConfig>(sp => sp.GetRequiredService<IOptions<CacheOptions>>().Value);

        // Register Redis as IDistributedCache
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = config["Cache:ConnectionString"];
            options.InstanceName = config["Cache:InstanceName"];
        });

        // Register RedisCacheService
        services.AddSingleton<ICacheService, RedisCacheService>();

        return services;
    }