Files
baya-monorepo/server/src/Infrastructure/Baya.Infrastructure.CrossCutting/Seams/MemoryCacheService.cs
T
hamid 765cc632d5 backend phase 0: foundation, cross-cutting seams & starter cleanup
Remove the Order demo (entity/feature/repo/config/gRPC/proto) and the three
pre-marketplace migrations; regenerate a fresh InitialBaseline migration.

Stand up the REST surface (PingController + System/Ping CQRS) proving the
Mediator -> behaviors -> OperationResult -> ApiResult envelope end to end.

Close wiring gaps: register LoggingBehavior (outermost) and add the built-in
rate limiter (per-IP global + otp/auth/sensitive policies), placed before
authentication.

Add current-user + audit plumbing: ICurrentUser (HttpContext + null impls),
rename BaseEntity audit fields to CreatedAt/ModifiedAt (DateTimeOffset) +
CreatedById/ModifiedById, stamped by a new AuditFieldInterceptor.

Introduce five cross-cutting seams (IDateTimeProvider, IFieldEncryptor,
ICacheService, IObjectStorage, INotificationDispatcher) with in-memory/local
mocks registered via AddCrossCuttingSeams.

Add Baya.Test.Foundation (encryptor, audit interceptor, ping handler) and
update docs, contracts (swagger.v1.json), handoff, report, and mocks registry.
2026-06-30 22:48:41 +03:30

48 lines
1.6 KiB
C#

#nullable enable
using Baya.Application.Contracts.Common;
using Microsoft.Extensions.Caching.Memory;
namespace Baya.Infrastructure.CrossCutting.Seams;
/// <summary>
/// In-process <see cref="IMemoryCache"/> implementation of <see cref="ICacheService"/> — the mock seam.
/// The real implementation swaps to Redis (StackExchange.Redis) while keeping the same key/TTL scheme.
/// </summary>
public sealed class MemoryCacheService(IMemoryCache cache) : ICacheService
{
public ValueTask<T?> GetAsync<T>(string key, CancellationToken cancellationToken = default)
{
return ValueTask.FromResult(cache.TryGetValue(key, out T? value) ? value : default);
}
public ValueTask SetAsync<T>(string key, T value, TimeSpan? ttl = null, CancellationToken cancellationToken = default)
{
var options = new MemoryCacheEntryOptions();
if (ttl is { } expiry)
options.AbsoluteExpirationRelativeToNow = expiry;
cache.Set(key, value, options);
return ValueTask.CompletedTask;
}
public ValueTask RemoveAsync(string key, CancellationToken cancellationToken = default)
{
cache.Remove(key);
return ValueTask.CompletedTask;
}
public async ValueTask<T> GetOrCreateAsync<T>(
string key,
Func<CancellationToken, ValueTask<T>> factory,
TimeSpan? ttl = null,
CancellationToken cancellationToken = default)
{
if (cache.TryGetValue(key, out T? cached) && cached is not null)
return cached;
var value = await factory(cancellationToken);
await SetAsync(key, value, ttl, cancellationToken);
return value;
}
}