My Application crashed after I upgraded EasyCashing from version 0.5.6 to version 1.9.2 ( when caching Proxied Entity (EntityFrameworkCore 8.x))

#572 · open · 3 comments

View on GitHub ↗

vithens

[TestEasyCache.zip](https://github.com/user-attachments/files/21155663/TestEasyCache.zip) EasyCaching.InMemory 1.9.2 EntityFrameworkCore 8.0.18 This issue does not happen for version 0.5.6 and version 0.6.1 Startup.cs `namespace EasyCaching.Demo.ResponseCaching { using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddEasyCaching(x => { x.UseInMemory("default"); }); //services.AddSqlite<MyDbContext>("Data Source=my_data.db"); services.AddDbContextPool<MyDbContext>(optionsBuilder => { // this configuration seems does not work with eazy cache? optionsBuilder.UseLazyLoadingProxies(); optionsBuilder.UseSqlite("Data Source=my_data.db"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //app.UseEasyCachingResponseCaching(); app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }` HomeController.cs `namespace EasyCaching.Demo.ResponseCaching.Controllers { using EasyCaching.Core; using EasyCaching.Demo.ResponseCaching.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System; using System.Threading.Tasks; public class HomeController : Controller { private readonly IEasyCachingProvider _provider; private readonly MyDbContext _myDbContext; public HomeController(IEasyCachingProviderFactory easyCachingProviderFactory, MyDbContext myDbContext) { _provider = easyCachingProviderFactory.GetCachingProvider("default"); _myDbContext = myDbContext; } [ResponseCache(Duration = 20)] public async Task<IActionResult> Index() { _myDbContext.Database.Migrate(); var test = await _provider.GetAsync<object>("k1", async () => { for (var i = 0; i < 100; i++) { var product = await _provider.GetAsync<Product>("product1", async () => { var p = await _myDbContext.Products.FirstOrDefaultAsync(); // the real type of p is Castle.Proxies.ProductProxy return p;// new Product() { Name = p.Name}; }, TimeSpan.FromSeconds(60)); } return new object(); }, TimeSpan.FromSeconds(60)); return Ok(test); } } }`

Comments

vithens

It could be caused by th feature added at version 0.8.0: Add deep clone for memory cache provider (https://github.com/dotnetcore/EasyCaching/issues/150 ). services.AddEasyCaching(x => { x.UseInMemory(opt => { opt.DBConfig.EnableReadDeepClone = false; opt.DBConfig.EnableWriteDeepClone = false; }, "default"); // this could not avoid from crashing x.UseMemoryLock(); //x.UseDistributedLock<DistributedLockFactory>(); }); Disable deep clone, and it works well with the proxied entities.

vithens

How about this? Let's skip clone proxy properties? DeepClonerExprGenerator.cs private static object GenerateProcessMethod(Type type, bool unboxStruct) ``` do { if (tp.Name == "ContextBoundObject") break; **if (type.FullName.StartsWith("Castle.Proxies.") && type.BaseType != null && type.FullName == $"Castle.Proxies.{type.BaseType.Name}Proxy") { tp = tp.BaseType; continue; }** fi.AddRange(tp.GetTypeInfo().DeclaredFields.Where(x => !x.IsStatic).ToArray()); tp = tp.BaseType; } while (tp != null); ```

vithens

I also found that, if we modify a property of the cached object the first time we get it, the value will be apllied to the cached object. This means the first time we get is not a copy of the cached object, but the object itself.