dotnetcore / EasyCaching

:boom: EasyCaching is an open source caching library that contains basic usages and some advanced usages of caching which can help us to handle caching more easier!
MIT License
1.95k stars 322 forks source link

Cannot initialize MemoryPack with UseDisk #476

Open czmirek opened 1 year ago

czmirek commented 1 year ago

Simple reproduction. Create new console project, add following nugets.

Copy & paste the following code and run.

// See https://aka.ms/new-console-template for more information

using EasyCaching.Core;
using EasyCaching.Disk;
using EasyCaching.Serialization.MemoryPack;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;

var sc = new ServiceCollection();
sc.AddEasyCaching(o =>
{
    o.UseDisk(config =>
    {
        config.SerializerName = "mempack";
        config.DBConfig = new DiskDbOptions { BasePath = Path.GetTempPath() };
    }).WithMemoryPack();
});

ServiceProvider sp = sc.BuildServiceProvider();
IEasyCachingProvider provider = sp.GetRequiredService<IEasyCachingProvider>();

provider.Set("CACHE_KEY", new Test(), TimeSpan.FromDays(1));

Console.ReadLine();

[MemoryPackable]
public partial class Test
{
    public string Name { get; set; } = "asdf";
}   

Expected behavior: No exception is thrown, Test class value is cached on disk with CACHE_KEY in MemoryPack format.

Actual behavior: System.MissingMethodException: 'Method not found: 'Void MemoryPack.MemoryPackSerializerOptions.set_StringEncoding(MemoryPack.StringEncoding)'.'

Call stack

   at EasyCaching.Serialization.Json.MemoryPackOptionsExtension.<AddServices>b__3_1(IServiceProvider x)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetServices[T](IServiceProvider provider)
   at EasyCaching.Disk.DiskOptionsExtension.<AddServices>b__3_0(IServiceProvider x)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Program.<Main>$(String[] args) in C:\Users\lesar\Source\Repos\Locura\src\ConsoleTest\Program.cs:line 20

Also, I was little surprised by the first line in the call stack

at EasyCaching.Serialization.Json.MemoryPackOptionsExtension.<AddServices>b__3_1(IServiceProvider x)

...because MemoryPack is binary serialization, not JSON.

So I looked here to see that indeed MemoryPackOptionsExtension is indeed in the EasyCaching.Serialization.Json namespace.

czmirek commented 1 year ago

So I tried copying the source code of MemoryPack serializer and another issue showed up, apparently UseDisk cannot really be used with WithMemoryPack because the serialized value is not the serialized class but EasyCaching.Disk.DiskCacheValue so I cannot add the [MemoryPackable] attribute to it.

MemoryPack uses source generators so you cannot specify the serialization in runtime. This means that UseDisk must either support MemoryPack explicitly by specifying a different DiskCacheValue type or the DiskCacheValue must be serialized/deserialized using a different serializer.