I have this container running on my localhost:5005 docker:
It was created with: docker run --name mtg-redis -p 5005:6379 -d redis
I have my .NET application running on localhost:5002
Docker Compose:
version: '3.4'
services:
mtgmvc:
image: ${DOCKER_REGISTRY-}mtgmvc
build:
context: .
dockerfile: MTGMVC/Dockerfile
Docker compose override:
version: '3.4'
services:
mtgmvc:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=8080
- ASPNETCORE_HTTPS_PORTS=8081
ports:
- "5001:8080"
- "5002:8081"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro
Dockerfile:
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["MTG/MTGMVC.csproj", "MTGMVC/"]
RUN dotnet restore "./MTG/MTGMVC.csproj"
COPY . .
WORKDIR "/src/MTGMVC"
RUN dotnet build "./MTGMVC.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./MTGMVC.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MTGMVC.dll"]
appsettings:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=mylocaldb;Initial Catalog=MTGCards;Integrated Security=True",
"Redis": "localhost:5005"
}
}
Program:
using MTGMVC.Clients;
using MTGMVC.Repositories;
using MTGMVC.Repositories.CommandText;
using MTGMVC.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddHttpClient("MTG", (serviceProvider, httpClient) =>
{
//var mtgSettings = serviceProvider.GetRequiredService<IOptions<MtgSettings>>().Value;
httpClient.BaseAddress = new Uri("https://api.magicthegathering.io/v1/");
});
builder.Services.AddHttpClient("Scryfall", (serviceProvider, httpClient) =>
{
//var mtgSettings = serviceProvider.GetRequiredService<IOptions<MtgSettings>>().Value;
httpClient.BaseAddress = new Uri("https://api.scryfall.com/");
});
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "mtg-redis";
});
//Register own services
builder.Services.AddScoped<IMTGService, MTGService>();
builder.Services.AddScoped<IMTGClient, MTGClient>();
builder.Services.AddScoped<IScryfallClient, ScryfallClient>();
builder.Services.AddTransient<ICommandText, CommandText>();
builder.Services.AddTransient<ISetRepository, SetRepository>();
builder.Services.AddTransient<IMagicDataWriterService, MagicDataWriterService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Extension File for crud redis methods:
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
namespace MTGMVC.Extensions
{
public static class DistributedCacheExtensions
{
public static async Task SetRecordAsync<T>(this IDistributedCache cache, string recordId, T data, TimeSpan? absoluteExpireTime = null, TimeSpan? unusedExpireTime = null)
{
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = absoluteExpireTime ?? TimeSpan.FromMinutes(1),
SlidingExpiration = unusedExpireTime
};
var jsonData = JsonSerializer.Serialize(data);
await cache.SetStringAsync(recordId, jsonData, options);
}
public static async Task<T?> GetRecordAsync<T>(this IDistributedCache cache, string recordId)
{
var jsonData = await cache.GetStringAsync(recordId);
if (jsonData is null)
{
return default;
}
return JsonSerializer.Deserialize<T>(jsonData);
}
}
}
I’m trying to call the redis cache to perform a GET from here:
using Microsoft.Extensions.Caching.Distributed;
using MTGMVC.Clients;
using MTGMVC.DTOs.Scryfall.Cards;
using MTGMVC.Extensions;
using MTGMVC.Models;
using MTGMVC.Repositories;
namespace MTGMVC.Services
{
public interface IMagicDataWriterService
{
Task<IList<SetModel>> GetAllSetNamesAsync();
Task<ScryfallCardDto> GetRandomCardBySet(string setCode);
}
public class MagicDataWriterService : IMagicDataWriterService
{
private ISetRepository _setRepository;
private IScryfallClient _scryfallClient;
private ILogger<MagicDataWriterService> _logger;
private IDistributedCache _cache;
public MagicDataWriterService(ISetRepository setRepository, IScryfallClient scryfallClient, ILogger<MagicDataWriterService> logger, IDistributedCache cache)
{
_setRepository = setRepository;
_scryfallClient = scryfallClient;
_logger = logger;
_cache = cache;
}
public async Task<IList<SetModel>> GetAllSetNamesAsync()
{
try
{
var cachedRecords = await _cache.GetRecordAsync<IList<SetModel>>("sets");
if (cachedRecords == null || !cachedRecords.Any())
{
var persistedSets = await _setRepository.CountSets();
if (persistedSets == 0)
{
var scryfallSets = await _scryfallClient.GetAllScryfallSetsAsync();
foreach (var set in scryfallSets.ScryfallSets)
{
await _setRepository.InsertSet(set);
}
}
var setNames = await _setRepository.GetAllSetNames();
await _cache.SetRecordAsync("sets", setNames, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60));
return setNames;
}
return cachedRecords;
}
catch (Exception ex)
{
_logger.LogError("Unable to get sets {ex}", ex);
throw;
}
}
(..)
But I’m getting a timeout from the redis cache. As far as I understand my app is being run by docker compose on port localhost:5002 and my redis container is up and running on localhost:5005 which is what I’m pointing at on appsettings…I’m unsure of what I’m doing wrong to reach it.
Exception message:
The message timed out in the backlog attempting to send because no connection became available (5000ms) - Last Connection Exception: UnableToConnect on localhost:5005/Interactive, Initializing/NotStarted, last: NONE, origin: BeginConnectAsync, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 60s, state: Connecting, mgr: 10 of 10 available, last-heartbeat: never, global: 0s ago, v: 2.7.33.41805, command=HMGET, timeout: 5000, inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, last-in: 0, cur-in: 0, sync-ops: 0, async-ops: 1, serverEndpoint: localhost:5005, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: 14c8ae52ba5a(SE.Redis-v2.7.33.41805), IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: (Busy=0,Free=32767,Min=12,Max=32767), POOL: (Threads=12,QueuedItems=0,CompletedItems=195,Timers=14), v: 2.7.33.41805 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
2
Answers
There might be several reasons.
--bind 0.0.0.0
.localhost:5005
which refers to the current container. Use Redis container’s IP address instead.Your localhost is not the localhost of your container. Try to use this:
host.docker.internal or your default ip of your network (192...* etc.) on your backend application for redis.
For more check this out