VahidN / EFSecondLevelCache.Core

Entity Framework Core Second Level Caching Library
Apache License 2.0
326 stars 50 forks source link

Help with DI and EFSecondLevelCache #7

Closed szavoda closed 7 years ago

szavoda commented 7 years ago

Hi -

I am trying to implement EFSecondLevelCache into my project which also uses SimpleInjector. My issue is when the DI container is verified, it cannot resolve the "IEFCacheServiceProvider cacheServiceProvider". I assume there is something simple I am missing, but if anyone has any insights, I appreciate it. My Startup looks like this:

public partial class Startup
    {
    private readonly Container _container = new Container();

    public IConfigurationRoot Configuration { get; }

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();

        Configuration = builder.Build();
    }

    // This method gets called by the runtime. Use this method to add services to the _container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("corsPolicy", policy =>
            {
                policy
                    .AllowAnyOrigin()
                    .AllowCredentials()
                    .AllowAnyHeader()
                    .AllowAnyMethod();
            });
        });

        var loggerFactory = new LoggerFactory();
        loggerFactory.AddNLog();
        loggerFactory.AddDebug(LogLevel.Debug);

        var builder = services.AddMvc();
        builder.AddMvcOptions(o => { o.Filters.Add(new CorsAuthorizationFilterFactory("corsPolicy")); });
        builder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter(loggerFactory)); });

        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
        services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));

        AddDbContextToService(services);

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IControllerActivator>(new SimpleInjectorControllerActivator(_container));
        services.AddSingleton<IViewComponentActivator>(new SimpleInjectorViewComponentActivator(_container));
        services.AddSingleton<IControllerActivator>(new SimpleInjectorControllerActivator(_container));
        services.AddSingleton<IViewComponentActivator>(new SimpleInjectorViewComponentActivator(_container));

        services.UseSimpleInjectorAspNetRequestScoping(_container);

        services.AddEFSecondLevelCache();
        AddRedisCacheServiceProvider(services);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseEFSecondLevelCache();
        app.UseCors("corsPolicy");
        app.UseDefaultFiles();
        app.UseStaticFiles(new StaticFileOptions
        {
            OnPrepareResponse = ctx =>
            {
                ctx.Context.Response.Headers["Access-Control-Allow-Origin"] = "*";
            }
        });

        loggerFactory.AddProvider(new DbLogging.SqlLoggerProvider());
        loggerFactory.AddNLog();
        env.ConfigureNLog("nlog.config");

        InitializeContainer(app);

        _container.Verify();

        //clear the cache
        var cacheManager = new Common.Caching.CacheManager(Configuration.GetConnectionString("RedisCache"));
        cacheManager.FlushServer();

        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
        {
            //Authority = "http://localhost:5000/",
            Authority = "http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            RequireHttpsMetadata = false,
            ApiName = "Jsa"
        });

        app.UseMvc();
    }

    private void InitializeContainer(IApplicationBuilder app)
    {
        _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

        _container.RegisterMvcControllers(app);
        _container.RegisterMvcViewComponents(app);
        _container.RegisterSingleton(app.ApplicationServices.GetService<ILoggerFactory>());
        _container.RegisterSingleton(app.ApplicationServices.GetService<IHostingEnvironment>());

        RegisterMediator();
        RegisterRepositories();
        RegisterJsaSpecificItems();
        RegisterAutomapper();
        RegisterDbContext();
    }

    private static void AddRedisCacheServiceProvider(IServiceCollection services)
    {
        var jss = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };

        const string redisConfigurationKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";
        services.AddSingleton(typeof(ICacheManagerConfiguration),
            new CacheManager.Core.ConfigurationBuilder()
                .WithJsonSerializer(serializationSettings: jss, deserializationSettings: jss)
                .WithUpdateMode(CacheUpdateMode.Up)
                .WithRedisConfiguration(redisConfigurationKey, config =>
                {
                    config.WithAllowAdmin()
                        .WithDatabase(0)
                        .WithEndpoint("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 6380);
                })
                .WithMaxRetries(100)
                .WithRetryTimeout(50)
                .WithRedisCacheHandle(redisConfigurationKey)
                .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
                .Build());
        services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
    }
}`
szavoda commented 7 years ago

I was able to figure this out after digging into the code a bit more. Adding these lines for container registration took care of the issue:

_container.RegisterSingleton(app.ApplicationServices.GetService<IEFCacheKeyHashProvider>()); _container.RegisterSingleton(app.ApplicationServices.GetService<IEFCacheKeyProvider>()); _container.RegisterSingleton(app.ApplicationServices.GetService<IEFCacheServiceProvider>());

VahidN commented 7 years ago

Probably you should move the services.UseSimpleInjectorAspNetRequestScoping method to the end of the ConfigureServices method to populate the registered services of the AddEFSecondLevelCache method (add it after the AddEFSecondLevelCache method).

szavoda commented 7 years ago

That sounded like a plausible solution, but unfortunately, it did not work that way.

VahidN commented 7 years ago

AddEFSecondLevelCache registers some initial services. Your DI should be able to retrieve them from the IServiceCollection.

szavoda commented 7 years ago

I will do some research on SimpleInjector and see what I can come up with and post back here if / when I find something...

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related problems.