Round #850
11 May 2026, 09:46· csharp· Meta-Llama-3.3-70B-Instruct· r15-firing-v3
- Complexity
- band 0
- ZP / UO / OBS
- 2 / 1 / 2
- Journey weight
- 272
- Lightshift ΔL
- +0.00
Prompt
Implement cache-aside using IDistributedCache backed by Redis to memoise an expensive lookup that returns a customer profile.
Zero-point index (what the engine surfaced)
ZPI-ZPI-0007 | 2026-05-11T09:46:35Z
Implement cache-aside using IDistributedCache backed by Redis to memoise an expensive lookup that returns a customer profile.
ZERO POINT — 2 entries (structural invariants)
● hsl(329.61, 100%, 40%) IDistributedCache [contract]
● hsl(145.55, 100%, 37%) IMemoryCache [contract]
UNOBSERVED — 1 entries (implied truths)
○ hsl(27.69, 100%, 50%) async [feature]
OBSERVED — 2 entries (explicit in request)
◉ hsl(85.13, 100%, 50%) using [feature]
◉ hsl(234.87, 100%, 50%) using [feature]
COMPLEXITY │ 5 entries │ spread: 207° │ band: LOW
Baseline response (no ZPI)
**Cache-Aside Pattern with IDistributedCache and Redis**
===========================================================
In this example, we will implement the cache-aside pattern using `IDistributedCache` backed by Redis to memoize an expensive lookup that returns a customer profile.
**Prerequisites**
---------------
* .NET Core 3.1 or later
* `Microsoft.Extensions.Caching.StackExchangeRedis` NuGet package
* Redis instance (local or remote)
**Implementation**
----------------
### CustomerProfileService.cs
```csharp
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
public class CustomerProfileService
{
private readonly IDistributedCache _cache;
private readonly ICustomerRepository _repository;
private readonly ILogger<CustomerProfileService> _logger;
public CustomerProfileService(IDistributedCache cache, ICustomerRepository repository, ILogger<CustomerProfileService> logger)
{
_cache = cache;
_repository = repository;
_logger = logger;
}
public async Task<CustomerProfile> GetCustomerProfileAsync(int customerId)
{
// Check cache first
var cacheKey = $"customer-profile-{customerId}";
var cachedProfile = await _cache.GetStringAsync(cacheKey);
if (cachedProfile != null)
{
_logger.LogInformation($"Cache hit for customer profile {customerId}");
return JsonConvert.DeserializeObject<CustomerProfile>(cachedProfile);
}
// If cache miss, retrieve from repository and cache the result
var profile = await _repository.GetCustomerProfileAsync(customerId);
if (profile != null)
{
var cacheEntryOptions = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromHours(1)); // cache for 1 hour
await _cache.SetStringAsync(cacheKey, JsonConvert.SerializeObject(profile), cacheEntryOptions);
_logger.LogInformation($"Cached customer profile {customerId}");
}
return profile;
}
}
```
### CustomerRepository.cs
```csharp
using System;
using System.Threading.Tasks;
public interface ICustomerRepository
{
Task<CustomerProfile> GetCustomerProfileAsync(int customerId);
}
public class CustomerRepository : ICustomerRepository
{
public async Task<CustomerProfile> GetCustomerProfileAsync(int customerId)
{
// Simulate an expensive lookup
await Task.Delay(2000);
return new CustomerProfile
{
CustomerId = customerId,
Name = $"Customer {customerId}",
Email = $"customer{customerId}@example.com"
};
}
}
```
### CustomerProfile.cs
```csharp
public class CustomerProfile
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
```
### Startup.cs
```csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedCache(options =>
{
options.InstanceName = "CustomerProfileCache";
options.Configuration = Configuration.GetConnectionString("Redis");
});
services.AddTransient<ICustomerRepository, CustomerRepository>();
services.AddTransient<CustomerProfileService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
}
}
```
### appsettings.json
```json
{
"ConnectionStrings": {
"Redis": "localhost:6379"
}
}
```
**Example Usage**
---------------
```csharp
[ApiController]
[Route("api/[controller]")]
public class CustomerController : ControllerBase
{
private readonly CustomerProfileService _customerProfileService;
public CustomerController(CustomerProfileService customerProfileService)
{
_customerProfileService = customerProfileService;
}
[HttpGet("{customerId}")]
public async Task<ActionResult<CustomerProfile>> GetCustomerProfile(int customerId)
{
var profile = await _customerProfileService.GetCustomerProfileAsync(customerId);
return Ok(profile);
}
}
```
In this example, we use the `IDistributedCache` interface to interact with the Redis cache. The `CustomerProfileService` class checks the cache first and retrieves the customer profile from the repository only if the cache miss occurs. The retrieved profile is then cached for 1 hour using the `DistributedCacheEntryOptions` class.
Note that you need to install the `Microsoft.Extensions.Caching.StackExchangeRedis` NuGet package and configure the Redis connection string in the `appsettings.json` file.
Enhanced response (with ZPI)
To implement cache-aside using `IDistributedCache` backed by Redis, you can use the `Microsoft.Extensions.Caching.StackExchangeRedis` package. First, install the package:
```
Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
```
Then, configure the Redis cache in the `Startup.cs` file:
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddStackExchangeRedisCache(options =>
{
options.InstanceName = "CustomerProfileCache";
options.Configuration = "localhost:6379";
});
services.AddTransient<ICustomerProfileService, CustomerProfileService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
}
```
Next, create a `CustomerProfileService` class that uses the `IDistributedCache` to memoize the expensive lookup:
```csharp
public interface ICustomerProfileService
{
Task<CustomerProfile> GetCustomerProfileAsync(int customerId);
}
public class CustomerProfileService : ICustomerProfileService
{
private readonly IDistributedCache _cache;
private readonly ICustomerProfileRepository _repository;
public CustomerProfileService(IDistributedCache cache, ICustomerProfileRepository repository)
{
_cache = cache;
_repository = repository;
}
public async Task<CustomerProfile> GetCustomerProfileAsync(int customerId)
{
var cacheKey = $"customer-profile-{customerId}";
var cachedProfile = await _cache.GetStringAsync(cacheKey);
if (cachedProfile != null)
{
return JsonConvert.DeserializeObject<CustomerProfile>(cachedProfile);
}
var profile = await _repository.GetCustomerProfileAsync(customerId);
var cacheEntryOptions = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromHours(1));
await _cache.SetStringAsync(cacheKey, JsonConvert.SerializeObject(profile), cacheEntryOptions);
return profile;
}
}
public interface ICustomerProfileRepository
{
Task<CustomerProfile> GetCustomerProfileAsync(int customerId);
}
public class CustomerProfileRepository : ICustomerProfileRepository
{
public async Task<CustomerProfile> GetCustomerProfileAsync(int customerId)
{
// Simulate an expensive lookup
await Task.Delay(2000);
return new CustomerProfile { Id = customerId, Name = "John Doe" };
}
}
public class CustomerProfile
{
public int Id { get; set; }
public string Name { get; set; }
}
```
In this implementation, the `CustomerProfileService` class uses the `IDistributedCache` to store and retrieve customer profiles. If a profile is found in the cache, it is returned immediately. Otherwise, the profile is retrieved from the repository, stored in the cache, and then returned. The cache entry is set to expire after 1 hour.
This implementation requires more text to provide a complete example.
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1samba/Meta-Llama-3.3-70B-Instruct
BetterV4qwen2.5-coder-3b-instruct
BetterV5openrouter/qwen/qwen3-235b-a22b-2507
BetterV7qwen2.5-coder-7b-instruct
SameV8openai/gpt-4.1
SameV9anthropic/claude-opus-4-7
WorseV12openai/gpt-4o
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.