3 Commits

Author SHA1 Message Date
2ede7baae6 feat:nuget 2025-09-02 13:57:44 -06:00
c42fb5eb00 Deactivate redis using a flag 2025-08-29 18:46:41 -06:00
dbc21959eb Fix Retrieve updated document in ReplaceOneAsync method 2025-08-07 17:23:44 -06:00
5 changed files with 98 additions and 50 deletions

View File

@@ -104,11 +104,13 @@ namespace Core.Blueprint.Mongo
void ReplaceOne(TDocument document); void ReplaceOne(TDocument document);
/// <summary> /// <summary>
/// Asynchronously replaces an existing document with a new one. /// Asynchronously replaces an existing document in the collection and returns the updated version.
/// </summary> /// </summary>
/// <param name="document">The document to replace the existing one.</param> /// <param name="document">The document with the updated data. Its _Id is used to locate the existing document.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <returns>
Task ReplaceOneAsync(TDocument document); /// The updated document if the replacement was successful; otherwise, <c>null</c> if no matching document was found.
/// </returns>
Task<TDocument?> ReplaceOneAsync(TDocument document);
/// <summary> /// <summary>
/// Deletes a single document by the provided filter expression. /// Deletes a single document by the provided filter expression.

View File

@@ -175,16 +175,27 @@ namespace Core.Blueprint.Mongo
} }
/// <summary> /// <summary>
/// Asynchronously replaces an existing document in the collection. /// Asynchronously replaces an existing document in the collection and returns the updated version.
/// </summary> /// </summary>
/// <param name="document">The document with the updated data.</param> /// <param name="document">The document with the updated data. Its _Id is used to locate the existing document.</param>
/// <returns>A task that represents the asynchronous operation.</returns> /// <returns>
public virtual async Task ReplaceOneAsync(TDocument document) /// The updated document if the replacement was successful; otherwise, <c>null</c> if no matching document was found.
/// </returns>
public virtual async Task<TDocument?> ReplaceOneAsync(TDocument document)
{ {
var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, document._Id); var filter = Builders<TDocument>.Filter.Eq(doc => doc._Id, document._Id);
await _collection.FindOneAndReplaceAsync(filter, document);
var options = new FindOneAndReplaceOptions<TDocument>
{
ReturnDocument = ReturnDocument.After // return the updated document
};
var result = await _collection.FindOneAndReplaceAsync(filter, document, options);
return result;
} }
/// <summary> /// <summary>
/// Deletes a single document from the collection based on the provided filter expression. /// Deletes a single document from the collection based on the provided filter expression.
/// </summary> /// </summary>

View File

@@ -27,7 +27,7 @@ namespace Core.Blueprint.Redis.Configuration
// Register RedisCacheProvider // Register RedisCacheProvider
services.AddSingleton<IRedisCacheProvider>(provider => services.AddSingleton<IRedisCacheProvider>(provider =>
new RedisCacheProvider(redisConnectionString, provider.GetRequiredService<ILogger<RedisCacheProvider>>())); new RedisCacheProvider(redisConnectionString, provider.GetRequiredService<ILogger<RedisCacheProvider>>(), configuration));
// Get CacheSettings and register with the ICacheSettings interface // Get CacheSettings and register with the ICacheSettings interface
var cacheSettings = configuration.GetSection("CacheSettings").Get<CacheSettings>(); var cacheSettings = configuration.GetSection("CacheSettings").Get<CacheSettings>();

View File

@@ -1,7 +1,7 @@
using Azure.Identity; using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using StackExchange.Redis; using StackExchange.Redis;
using System;
using System.Text.Json; using System.Text.Json;
namespace Core.Blueprint.Redis namespace Core.Blueprint.Redis
@@ -13,6 +13,7 @@ namespace Core.Blueprint.Redis
{ {
private IDatabase _cacheDatabase = null!; private IDatabase _cacheDatabase = null!;
private readonly ILogger<RedisCacheProvider> _logger; private readonly ILogger<RedisCacheProvider> _logger;
private readonly bool _useRedis;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RedisCacheProvider"/> class. /// Initializes a new instance of the <see cref="RedisCacheProvider"/> class.
@@ -20,12 +21,13 @@ namespace Core.Blueprint.Redis
/// <param name="connectionString">The Redis connection string.</param> /// <param name="connectionString">The Redis connection string.</param>
/// <param name="logger">The logger instance for logging operations.</param> /// <param name="logger">The logger instance for logging operations.</param>
/// <exception cref="ArgumentNullException">Thrown when connection string is null or empty.</exception> /// <exception cref="ArgumentNullException">Thrown when connection string is null or empty.</exception>
public RedisCacheProvider(string connectionString, ILogger<RedisCacheProvider> logger) public RedisCacheProvider(string connectionString, ILogger<RedisCacheProvider> logger, IConfiguration configuration)
{ {
if (string.IsNullOrWhiteSpace(connectionString)) if (string.IsNullOrWhiteSpace(connectionString))
throw new ArgumentNullException(nameof(connectionString), "Redis connection string cannot be null or empty."); throw new ArgumentNullException(nameof(connectionString), "Redis connection string cannot be null or empty.");
_logger = logger; _logger = logger;
_useRedis = configuration.GetValue<bool>("UseRedisCache", false);
_cacheDatabase = InitializeRedisAsync(connectionString).GetAwaiter().GetResult(); _cacheDatabase = InitializeRedisAsync(connectionString).GetAwaiter().GetResult();
} }
@@ -36,30 +38,35 @@ namespace Core.Blueprint.Redis
/// <param name="connectionString">The Redis connection string.</param> /// <param name="connectionString">The Redis connection string.</param>
/// <returns>An <see cref="IDatabase"/> instance representing the Redis cache database.</returns> /// <returns>An <see cref="IDatabase"/> instance representing the Redis cache database.</returns>
/// <exception cref="Exception">Thrown when the connection to Redis fails.</exception> /// <exception cref="Exception">Thrown when the connection to Redis fails.</exception>
async Task<IDatabase> InitializeRedisAsync(string connectionString) async Task<IDatabase?> InitializeRedisAsync(string connectionString)
{ {
try try
{ {
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; if (_useRedis)
ConnectionMultiplexer connectionMultiplexer;
if (environment.Equals("Local", StringComparison.OrdinalIgnoreCase))
{ {
connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(connectionString); var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
} ConnectionMultiplexer connectionMultiplexer;
else
{
var configurationOptions = await ConfigurationOptions.Parse(connectionString)
.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
configurationOptions.AbortOnConnectFail = false; if (environment.Equals("Local", StringComparison.OrdinalIgnoreCase))
{
connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(connectionString);
}
else
{
var configurationOptions = await ConfigurationOptions.Parse(connectionString)
.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions); configurationOptions.AbortOnConnectFail = false;
connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions);
}
_logger.LogInformation("Successfully connected to Redis.");
return connectionMultiplexer.GetDatabase();
} }
_logger.LogInformation("Successfully connected to Redis."); return null;
return connectionMultiplexer.GetDatabase();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -78,15 +85,21 @@ namespace Core.Blueprint.Redis
{ {
try try
{ {
var value = await _cacheDatabase.StringGetAsync(key); if (_useRedis is not false)
if (value.IsNullOrEmpty)
{ {
_logger.LogInformation($"Cache miss for key: {key}"); var value = await _cacheDatabase.StringGetAsync(key);
return default;
if (value.IsNullOrEmpty)
{
_logger.LogInformation($"Cache miss for key: {key}");
return default;
}
_logger.LogInformation($"Cache hit for key: {key}");
return JsonSerializer.Deserialize<TEntity>(value);
} }
_logger.LogInformation($"Cache hit for key: {key}"); return default;
return JsonSerializer.Deserialize<TEntity>(value);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -105,9 +118,12 @@ namespace Core.Blueprint.Redis
{ {
try try
{ {
var json = JsonSerializer.Serialize(value); if (_useRedis is not false)
await _cacheDatabase.StringSetAsync(key, json, expiry); {
_logger.LogInformation($"Cache item set with key: {key}"); var json = JsonSerializer.Serialize(value);
await _cacheDatabase.StringSetAsync(key, json, expiry);
_logger.LogInformation($"Cache item set with key: {key}");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -124,8 +140,11 @@ namespace Core.Blueprint.Redis
{ {
try try
{ {
await _cacheDatabase.KeyDeleteAsync(key); if (_useRedis is not false)
_logger.LogInformation($"Cache item removed with key: {key}"); {
await _cacheDatabase.KeyDeleteAsync(key);
_logger.LogInformation($"Cache item removed with key: {key}");
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -143,9 +162,13 @@ namespace Core.Blueprint.Redis
{ {
try try
{ {
var exists = await _cacheDatabase.KeyExistsAsync(key); if (_useRedis is not false)
_logger.LogInformation($"Cache item exists check for key: {key} - {exists}"); {
return exists; var exists = await _cacheDatabase.KeyExistsAsync(key);
_logger.LogInformation($"Cache item exists check for key: {key} - {exists}");
}
return false;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -163,15 +186,18 @@ namespace Core.Blueprint.Redis
{ {
try try
{ {
var value = await _cacheDatabase.StringGetAsync(key); if (_useRedis is not false)
if (!value.IsNullOrEmpty)
{ {
await _cacheDatabase.StringSetAsync(key, value, expiry); var value = await _cacheDatabase.StringGetAsync(key);
_logger.LogInformation($"Cache item refreshed with key: {key}"); if (!value.IsNullOrEmpty)
} {
else await _cacheDatabase.StringSetAsync(key, value, expiry);
{ _logger.LogInformation($"Cache item refreshed with key: {key}");
_logger.LogWarning($"Cache item with key: {key} does not exist, cannot refresh"); }
else
{
_logger.LogWarning($"Cache item with key: {key} does not exist, cannot refresh");
}
} }
} }
catch (Exception ex) catch (Exception ex)

9
nuget.config Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!-- Tu BaGet primero -->
<add key="BaGet" value="https://nuget.dream-views.com/v3/index.json" protocolVersion="3" />
<!-- NuGet oficial como fallback (si quieres) -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>