Background and Motivation
If you're declaring your own Configuration section like this:
{
"MyOwnRedis": {
"DefaultLease": "00:10:00",
"KeyPrefix": "my-app"
"ConnectionString": "this is the actual connection string for RedisCacheOptions"
}
}
and thus doing:
public class MyOwnRedisOptions
{
public const string SectionName = "MyOwnRedis";
public TimeSpan DefaultLease { get; set; }
public string KeyPrefix { get; set; } = default!;
public string ConnectionString { get; set; } = default!;
}
services
.AddOptions<MyOwnRedisOptions>
.BindConfiguration(MyOwnRedisOptions.SectionName)
.Validate(options => !string.IsNullOrWhiteSpace(options.ConnectionString), $"The configuration key for {MyOwnRedisOptions.SectionName}:{nameof(MyOwnRedisOptions.ConnectionString)} cannot be null or whitespace.")
.Validate(options => options...............);
//...
the moment you're trying to call AddStackExchangeRedisCache you're ending up in a weird situation:
services.AddStackExchangeRedisCache(options =>
{
option.Connection = builders.Configuration.Get<string>($"{MyOwnRedisOptions.SectionName}:{nameof(MyOwnRedisOptions.ConnectionString)})
};
or
// this has the benefits or still running your Options Validation entiely
services.AddStackExchangeRedisCache(_ => {}) // this is super weird
services
.AddOptions<RedisCacheOptions>()
.Configure<IOptions<MyOwnRedisOptions>>((redisCacheOptions, myOwnRedisOptions) =>
{
redisCacheOptions.Configuration = myOwnRedisOptions.Value.ConnectionString;
});
};
Proposed API
- Add an overload where the
setupAction is not required
- Avoid nullable on
setupAction
Please provide the specific public API signature diff that you are proposing. For example:
namespace Microsoft.Extensions.DependencyInjection;
public static class StackExchangeRedisCacheServiceCollectionExtensions
{
+ public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services)
+ public static IServiceCollection AddStackExchangeRedisOutputCache(this IServiceCollection services)
}
Usage Examples
services
.AddOptions<MyOwnRedisOptions>
.BindConfiguration(MyOwnRedisOptions.SectionName)
.Validate(options => !string.IsNullOrWhiteSpace(options.ConnectionString), "configuration for redis ConnectionString cannot be null or ...... ")
.Validate(options => options...............);
//...
services
.AddOptions<RedisCacheOptions>()
.Configure<IOptions<MyOwnRedisOptions>>((redisCacheOptions, myOwnRedisOptions) =>
{
redisCacheOptions.Configuration = myOwnRedisOptions.Value.ConnectionString;
});
};
services.AddStackExchangeRedisCache()
Alternative Designs
Not exactly a fan of using null as optional overload in general. It opens the code to more nullability check or bug tracking NRE like "well I was sure I gave it a value".
PS: Only writing it for AddStackExchangeRedisCache but it would be the the same for the OutputCache as well
namespace Microsoft.Extensions.DependencyInjection;
public static class StackExchangeRedisCacheServiceCollectionExtensions
{
+ public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction = null)
{
ArgumentNullThrowHelper.ThrowIfNull(services);
- ArgumentNullThrowHelper.ThrowIfNull(setupAction);
services.AddOptions();
- services.Configure(setupAction);
+ if(setupAction != null)
+ {
+ services.Configure(setupAction);
+ }
services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>());
return services;
}
or
namespace Microsoft.Extensions.DependencyInjection;
public static class StackExchangeRedisCacheServiceCollectionExtensions
{
+ public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction = null)
{
ArgumentNullThrowHelper.ThrowIfNull(services);
- ArgumentNullThrowHelper.ThrowIfNull(setupAction);
services.AddOptions();
- services.Configure(setupAction);
+ services.Configure(setupAction ?? _ => {});
services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>());
return services;
}
Risks
The risk of bad setup/configuration is still owned by inner implementation such as RedisCache / RedisCacheImpl etc ...
Background and Motivation
If you're declaring your own Configuration section like this:
{ "MyOwnRedis": { "DefaultLease": "00:10:00", "KeyPrefix": "my-app" "ConnectionString": "this is the actual connection string for RedisCacheOptions" } }and thus doing:
the moment you're trying to call
AddStackExchangeRedisCacheyou're ending up in a weird situation:or
// this has the benefits or still running your Options Validation entiely
Proposed API
setupActionis not requiredsetupActionPlease provide the specific public API signature diff that you are proposing. For example:
namespace Microsoft.Extensions.DependencyInjection; public static class StackExchangeRedisCacheServiceCollectionExtensions { + public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services) + public static IServiceCollection AddStackExchangeRedisOutputCache(this IServiceCollection services) }Usage Examples
Alternative Designs
Not exactly a fan of using
nullas optional overload in general. It opens the code to more nullability check or bug tracking NRE like "well I was sure I gave it a value".PS: Only writing it for
AddStackExchangeRedisCachebut it would be the the same for theOutputCacheas wellnamespace Microsoft.Extensions.DependencyInjection; public static class StackExchangeRedisCacheServiceCollectionExtensions { + public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction = null) { ArgumentNullThrowHelper.ThrowIfNull(services); - ArgumentNullThrowHelper.ThrowIfNull(setupAction); services.AddOptions(); - services.Configure(setupAction); + if(setupAction != null) + { + services.Configure(setupAction); + } services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>()); return services; }or
namespace Microsoft.Extensions.DependencyInjection; public static class StackExchangeRedisCacheServiceCollectionExtensions { + public static IServiceCollection AddStackExchangeRedisCache(this IServiceCollection services, Action<RedisCacheOptions> setupAction = null) { ArgumentNullThrowHelper.ThrowIfNull(services); - ArgumentNullThrowHelper.ThrowIfNull(setupAction); services.AddOptions(); - services.Configure(setupAction); + services.Configure(setupAction ?? _ => {}); services.Add(ServiceDescriptor.Singleton<IDistributedCache, RedisCacheImpl>()); return services; }Risks
The risk of bad setup/configuration is still owned by inner implementation such as
RedisCache/RedisCacheImpletc ...