-
Notifications
You must be signed in to change notification settings - Fork 328
缓存的序列化
对于分布式缓存,不可避免的要对缓存的内容进行序列化操作。
要如何对缓存的内容进行序列化?正常的情况将一个对象序列化成byte[]
会是第一选择。这也是EasyCaching的实现。
EasyCaching目前提供4种序列化可供选择,BinaryFormatter
、 Json
、 MessagePack
和 Protobuf
。
其中BinaryFormatter
是默认的,不用添加任何第三方序列化的包。
这里有一个 Breaking Change 还是要留意一下的。
在
< 0.6.0
的版本中,只能使用一种序列化方式,由于EasyCaching支持创建多个不同的Provider实例,对不同Provider有不同序列化方式的支持是必不可少的,所以在>= 0.6.0
的版本中,支持命名式序列化选择。
下面先来看看不同的用法。
services.AddEasyCaching(option =>
{
option.UseRedis(config =>
{
config.DBConfig.Database = 7;
config.DBConfig.Endpoints.Add(new ServerEndPoint("localhost", 6379));
});
});
在这个例子中,没有指定任何和序列化相关的配置!这个时候,EasyCaching给它分配的序列化器是BinaryFormatter
.
如果使用的时候有对一些复杂类型进行存取操作,并且没有给它们标识[Serializable]
,就会出现类似下面的错误:
Unhandled Exception: System.Runtime.Serialization.SerializationException: Type 'xxxx' is not marked as serializable.
针对< 0.6.0
的版本
dotnet add package EasyCaching.Serialization.MessagePack
services.AddEasyCaching(option =>
{
option.UseRedis(config =>
{
config.DBConfig.Database = 7;
config.DBConfig.Endpoints.Add(new ServerEndPoint("localhost", 6379));
})
.WithMessagePack()
;
});
在这个例子中,指定要使用MessagePack这种序列化!这个时候,EasyCaching给它分配的序列化器就是MessagePack
,替换默认的BinaryFormatter
这里需要注意的是,如果指定了多种序列化方式,则只会以最后添加到容器中的为准。
针对>= 0.6.0
的版本
services.AddEasyCaching(option =>
{
var serializerName = "s1";
option.UseRedis(config =>
{
config.DBConfig.Database = 7;
config.DBConfig.Endpoints.Add(new ServerEndPoint("localhost", 6379));
// 重要配置, 默认是provider的名字
config.SerializerName = serializerName;
}, "myredis");
option.WithMessagePack("s1")
.WithJson("myjson");
});
在这个例子中,名字为myredis
这个provider指定了它要用名字为s1
的序列化器。同时还添加了多种序列化器。
所以最后这个provider用的序列化器就是MessagePack
。
这里有个要注意的地方,如果没有指定SerializerName
,EasyCaching会去找有没有和Provider同名的序列化器,在上面的例子中就是myredis
,可以看到也没有,这个时候它要完成正常的功能,只能使用默认的BinaryFormatter
。
EasyCaching对序列化的操作提供了一个通用的接口 IEasyCachingSerializer
,要有相应的实现。
public interface IEasyCachingSerializer
{
string Name { get; }
byte[] Serialize<T>(T value);
T Deserialize<T>(byte[] bytes);
object Deserialize(byte[] bytes, Type type);
ArraySegment<byte> SerializeObject(object obj);
object DeserializeObject(ArraySegment<byte> value);
}
实现自己的序列化器后,还要实现IEasyCachingOptionsExtension
这个配置相关的接口。
public interface IEasyCachingOptionsExtension
{
void AddServices(IServiceCollection services);
}
如果我们在使用的过程中,有涉及到需要序列化时间的情况下,并且没有使用UTC时间,就会导致时区信息的丢失。
在 <= v0.8.0
的版本中,默认实现中使用了ContractlessStandardResolver
这个Resolver,选择这个是因为不需要给每个类和属性加特性,便于无缝融合。
在 v0.8.1
版本中,添加了一个EnableCustomResolver
的配置,当这个配置是true
的时候就表示启用自定义的Resolver,反之继续用默认的。
时间问题可以使用NativeDateTimeResolver+ContractlessStandardResolver
的组合来解决。下面是具体的例子。
public void ConfigureServices(IServiceCollection services)
{
CompositeResolver.RegisterAndSetAsDefault(
// This can solve DateTime time zone problem
NativeDateTimeResolver.Instance,
ContractlessStandardResolver.Instance
);
services.AddControllers();
services.AddEasyCaching(option =>
{
option.UseCSRedis(config =>
{
config.DBConfig = new EasyCaching.CSRedis.CSRedisDBOptions
{
ConnectionStrings = new List<string> { "127.0.0.1:6379,defaultDatabase=11,poolsize=10" }
};
config.SerializerName = "mymsgpack";
}, "redis1");
// use MessagePack
option.WithMessagePack( x =>
{
x.EnableCustomResolver = true;
},"mymsgpack");
});
}