VahidN / EFSecondLevelCache.Core

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

It dosen't work in my application #4

Closed fishen closed 7 years ago

fishen commented 7 years ago

I used redis as cache provider but it dosen't work, i can't find any key in redis db, so I switched to another model(WithMicrosoftMemoryCacheHandle), It does not seem to work too. I wrote two action for compare cache and nocache, but the time-consuming seems almost. I need your help @VahidN .

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfigurationRoot>(provider => { return Configuration; });
            services.AddDbContext<SinoautoContext>(ServiceLifetime.Scoped);
            // Add framework services.
            var redisConnStr = Configuration.GetConnectionString("RedisConnetionString");
            var redisConn = ConnectionMultiplexer.Connect(redisConnStr);

            services.AddEFSecondLevelCache();
            services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
            services.AddSingleton(typeof(ICacheManagerConfiguration),
                new CacheManager.Core.ConfigurationBuilder()
                    .WithJsonSerializer()
                    //.WithRedisConfiguration("Redis", redisConn)
                    //.WithRedisCacheHandle("Redis")
                    .WithMicrosoftMemoryCacheHandle()
                    .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromSeconds(10))
                    .Build()
            );
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            app.UseEFSecondLevelCache();
            app.UseMvc();
        }
        [HttpGet]
        public IActionResult Get()
        {
            var list = db.HttpLogs.Take(1000).ToList();
            return Json(list);
        }

        [HttpGet("cache")]
        public IActionResult GetByCache()
        {
            var list = db.HttpLogs.Take(1000).Cacheable().ToList();
            return Json(list);
        }
VahidN commented 7 years ago

How do you know it doesn't work? How did you test it? To test it, you should log the produced SQL or you can provide an additional parameter here

var debugInfo = new EFCacheDebugInfo();
var list = db.HttpLogs.Take(1000).Cacheable(debugInfo).ToList();

And then check the value of debugInfo.IsCacheHit. It should be false for the fist call and true for the second call. Also it will be false after the cache invalidation.

fishen commented 7 years ago

thanks @VahidN

attiqeurrehman commented 6 years ago

@VahidN I am having the same trouble. I have checked with the debugInfo.IsCacheHit and it returns false even after numerous times.

Following is my configuration:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
       // Other code is stripped for clarity
      // Add Redis cache service provider
      services.AddEFSecondLevelCache();
      AddRedisCacheServiceProvider(services);
}

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

            const string redisConfigurationKey = "redis";
            services.AddSingleton(typeof(ICacheManagerConfiguration),
                new CacheManager.Core.ConfigurationBuilder()
                    .WithJsonSerializer(jss, jss)
                    .WithUpdateMode(CacheUpdateMode.Up)
                    .WithRedisConfiguration(redisConfigurationKey, config =>
                    {
                        config.WithAllowAdmin()
                            .WithDatabase(0)
                            .WithEndpoint("localhost", 6379);
                    })
                    .WithMaxRetries(100)
                    .WithRetryTimeout(50)
                    .WithRedisCacheHandle(redisConfigurationKey)
                    .WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
                    .Build());
            services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
        }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseEFSecondLevelCache();
            //other code is stripped for clarity 
        }

Following code is to get the the list of objects:

protected override async Task<object> OnHandleAsync(RestGetListRequest<TEntity, TGetModel> message,
            CancellationToken cancellationToken)
        {
            var results = UnitOfWork.GetRepository<TEntity>().GetAll();
 var debugInfo = new EFCacheDebugInfo();
            var mapped = await results.Cacheable(debugInfo).ProjectTo<TGetModel>(Mapper.ConfigurationProvider)
                    .ToListAsync(cancellationToken);
            return mapped;
        }

DbContext is overriding the following:

public override int SaveChanges()
        {
            ChangeTracker.DetectChanges();
            var changedEntityNames = this.GetChangedEntityNames();

            ChangeTracker.AutoDetectChangesEnabled = false; // for performance reasons, to avoid calling DetectChanges() again.
            var result = base.SaveChanges();
            ChangeTracker.AutoDetectChangesEnabled = true;

            this.GetService<IEFCacheServiceProvider>().InvalidateCacheDependencies(changedEntityNames);

            return result;
        }

        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
        {
            ChangeTracker.DetectChanges();
            var changedEntityNames = this.GetChangedEntityNames();

            ChangeTracker.AutoDetectChangesEnabled = false; // for performance reasons, to avoid calling DetectChanges() again.
            var result = base.SaveChangesAsync(cancellationToken);
            ChangeTracker.AutoDetectChangesEnabled = true;

            this.GetService<IEFCacheServiceProvider>().InvalidateCacheDependencies(changedEntityNames);

            return result;
        }

Base class library responsible for getting the results is using the following:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Autofac" Version="4.8.1" />
        <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.2" />
        <PackageReference Include="AutoMapper" Version="7.0.1" />
        <PackageReference Include="AutoMapper.Attributes" Version="6.0.1" />
        <PackageReference Include="EFSecondLevelCache.Core" Version="1.6.1" />
        <PackageReference Include="EntityFrameworkCore.Triggers" Version="1.1.1" />
        <PackageReference Include="FluentValidation" Version="7.6.104" />
        <PackageReference Include="MediatR" Version="5.0.1" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
        <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.1" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.UnitOfWork" Version="2.0.4" />
    </ItemGroup>
</Project>

and ASP.NET Core Web API is using the following:

<ItemGroup>
    <PackageReference Include="EFSecondLevelCache.Core" Version="1.6.0" />
    <PackageReference Include="CacheManager.Core" Version="1.1.2" />
    <PackageReference Include="CacheManager.Microsoft.Extensions.Caching.Memory" Version="1.1.2" />
    <PackageReference Include="CacheManager.StackExchange.Redis" Version="1.1.2" />
    <PackageReference Include="CacheManager.Serialization.Json" Version="1.1.2" />
  </ItemGroup>

Note: Upon further investigation, I found that if I remove ProjectTo<TGetModel>(Mapper.ConfigurationProvider) from the LINQ it works fine.

VahidN commented 6 years ago

It won't work with ProjectTo of auto-mapper. the Cacheable method needs to evaluate the expression tree to find dependencies and also its hash and it's not possible with the ProjectTo method.

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.