EasyCaching icon indicating copy to clipboard operation
EasyCaching copied to clipboard

AddEasyCaching access to IServiceProvider - Redis Services are resolved at runtime via another Service

Open Simonl9l opened this issue 4 years ago • 11 comments

Hi - We're trying to use the caching in an environment were the Redis endpoints are discoverable via a service registry (consul). It would be great if the AddEasyCaching configuration action had access to the service provider.

Do you have any recommendation to best active this with what is available today, given that the service (per RedisEndpoints) below is registered elsewhere, and it being not best practice to cal' BuildServiceProvider() directly.

The EF Core DBContext AddDBContext service extension for configuration as an example does provide access to the service provider,

It would be great if in future versions I could do something like the following:

 services.AddEasyCaching((serviceProvider, option) =>
{
    option.UseRedis(config =>
    {
        config.DBConfig.AllowAdmin = true;
        serviceProvider.GetRequiredService<RedisEndpoints>().ForEach(endpoint => config.DBConfig.Endpoints.Add(new ServerEndPoint(endpoint.Host, endpoint.Port)));
    }, providerName);
});
  • Provider : Redis (version 1.1.0)
  • Interceptor : Asp Net Core (version 3.1.400)
  • Serializer : not use
  • System : alpine

Simonl9l avatar Dec 20 '20 21:12 Simonl9l

An additional path here is that we're already using the StackExchangeRedis package ourselves elsewhere, (that we have the ConnectionMultiplexer encapsulated in another service).

Would there be a possible future alternate configuration approach where we can use a variation of the MyAddEasyCaching helper with with access to the IServiceProvider context sour that we can just retrieved the ConnectionMultiplexer and pass that straight in ?

Simonl9l avatar Dec 21 '20 21:12 Simonl9l

@Simonl9l Thanks for your interest in this project.

We will take a look ASAP.

catcherwong avatar Dec 22 '20 00:12 catcherwong

@catcherwong thanks! very impressed by what we see with this in conjunction with the EF Core Second Level Cache Interceptor so all help greatly appreciated!

Simonl9l avatar Dec 22 '20 02:12 Simonl9l

@catcherwong hi - any word on when this might be addressed?

Simonl9l avatar Jan 05 '21 16:01 Simonl9l

@Simonl9l I'm very sorry, I don't have enough time to deal with this issue right now.

catcherwong avatar Jan 07 '21 00:01 catcherwong

@catcherwong OK - do please let us know what you do have enough "ASAP" time to take a look...

Simonl9l avatar Jan 07 '21 01:01 Simonl9l

Redis endpoints are discoverable via a service registry (consul). It would be great if the AddEasyCaching configuration action had access to the service provider.

If your Redis endpoints are discoverable via a service registry, you can do something combine service registry and Microsoft.Extensions.Configuration, so that you can read the endpoints from the service registry.

catcherwong avatar Jan 31 '21 02:01 catcherwong

Would there be a possible future alternate configuration approach where we can use a variation of the MyAddEasyCaching helper with with access to the IServiceProvider context

I am not sure AddEasyCaching access IServiceProvider is a good idea or not. This one needs to hear if other people have other opinions.

catcherwong avatar Jan 31 '21 02:01 catcherwong

@catcherwong thanks for the followup - per my code above, the endpoints are not available from configuration but via another service call to a registry service implementation (that makes HTTP calls via an HttpClient to consul API, that also needs to be first registered in the service container that would not be available in the Hosts ConfigureAppConfiguration).

The challenge is with the startup service configuration code in that we have a chicken-egg problem, that until the services container is built and made accessible via an IServicerProvider, I can't access that service in the EasyCaching .UseRedis configuration.

The can't is more one should not by best practice call BuildServiceProvider multiple times (onc really should really leave to the HostBuilder), or with some implicit expectation of registration ordering.

By making the IServiceProvider available with the configuration options (as is by default otherwise available, and made accessible in the default service registration code - via a `Func<IServiceProvider., ...>, and many other extensions out there) it makes each service configuration/startup more a lazy loading concept, once the service is initially requested, eliminating this issue with service dependencies.

As I understand it, when the service provider is built and all the available services are registered, that when a given service is requested the first time, that services configuration function is executed. Any dependent services will be identified by the service container as they are also retrieved - or others DI'd - and as applicable their startup function will each be executed first.

Whist I have something that works it's not ideal. With out the IServiceProvider being available in the service extension, this is the code I need to use today that is not best practice (note the call to services.BuildServiceProvider():

services.AddEasyCaching(option =>
{
    var endpoints = services.BuildServiceProvider().GetRequiredService<RedisEndpoints>().Endpoints;
            
    option.UseRedis(config =>
    {
        config.DBConfig.AllowAdmin = true;
        endpoints.ForEach(endpoint => config.DBConfig.Endpoints.Add(new ServerEndPoint(endpoint.Host, endpoint.Port)));
    }, providerName);
});

where the services variable is that scoped inside the public void ConfigureServices(IServiceCollection services) as what ever point it is in that functions implementation.

Does this explain the needs better - just trying to use dotnet core service registration as designed...?

Simonl9l avatar Jan 31 '21 03:01 Simonl9l

chegoone iran,tehran https://chegoone.info/download-youtube-videos/ Download tutorial from YouTube

shamiz01 avatar May 06 '21 07:05 shamiz01

Just a bump on this thread, having a mechanism to access IServiceProvider (e.g. a new parameter Func<IServiceProvider , ...> as suggested by @Simonl9l would be immensely helpful, and as mentioned, better aligned with the intent of service registration by avoiding explicit use of services.BuildServiceProvider()

cmcjcharters avatar Jan 24 '22 00:01 cmcjcharters