Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Simonl9l opened this issue Dec 20, 2020 · 11 comments

Comments

@Simonl9l
Copy link

Simonl9l commented Dec 20, 2020

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
Copy link
Author

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 ?

@catcherwong
Copy link
Member

@Simonl9l Thanks for your interest in this project.

We will take a look ASAP.

@Simonl9l
Copy link
Author

@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
Copy link
Author

Simonl9l commented Jan 5, 2021

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

@catcherwong
Copy link
Member

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

@Simonl9l
Copy link
Author

Simonl9l commented Jan 7, 2021

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

@catcherwong
Copy link
Member

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
Copy link
Member

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.

@Simonl9l
Copy link
Author

Simonl9l commented Jan 31, 2021

@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...?

@shamiz01

This comment has been minimized.

@cmcjcharters
Copy link

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()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants