如何正确反序列化IDistributedCache中二进制格式的byte[]数据?
解决ASP.NET Core会话存储的分布式缓存数据反序列化问题
问题根源
ASP.NET Core的ISession默认采用自定义二进制序列化格式(由内部SessionSerializer类处理),既不是JSON,也不是标准BinaryFormatter格式。直接用UTF8转字符串或BinaryFormatter反序列化,自然会出现格式不匹配的错误。
正确反序列化方案
方法1:通过ISession直接读取(推荐)
如果代码能访问当前ISession实例,直接用官方扩展方法读取,它会自动处理序列化逻辑:
// 需先引用Microsoft.AspNetCore.Http.Extensions包 var sessionData = session.Get<Dictionary<string, object>>("YourSessionKey");
方法2:手动解析SessionSerializer二进制格式
若必须直接从IDistributedCache读取byte[],可手动实现SessionSerializer的解析逻辑(因它是内部类无法直接调用):
using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; public static class SessionDataDeserializer { public static Dictionary<string, object> DeserializeSessionData(byte[] data) { var sessionDict = new Dictionary<string, object>(); using var ms = new MemoryStream(data); using var reader = new BinaryReader(ms); // 读取版本号(默认固定为1) var version = reader.ReadInt32(); if (version != 1) throw new NotSupportedException("不支持的会话数据版本"); // 读取键值对总数 var pairCount = reader.ReadInt32(); for (int i = 0; i < pairCount; i++) { var key = reader.ReadString(); var typeFlag = reader.ReadByte(); object value = typeFlag switch { 0 => null, 1 => reader.ReadString(), 2 => reader.ReadInt32(), 3 => reader.ReadBoolean(), 4 => reader.ReadByte(), 5 => reader.ReadChar(), 6 => reader.ReadDecimal(), 7 => reader.ReadDouble(), 8 => reader.ReadInt64(), 9 => reader.ReadSByte(), 10 => reader.ReadSingle(), 11 => reader.ReadUInt32(), 12 => reader.ReadUInt64(), 13 => reader.ReadInt16(), 14 => reader.ReadUInt16(), 15 => ReadComplexObject(reader), _ => throw new NotSupportedException($"不支持的类型标识: {typeFlag}") }; sessionDict.Add(key, value); } return sessionDict; } private static object ReadComplexObject(BinaryReader reader) { var dataLength = reader.ReadInt32(); var objectBytes = reader.ReadBytes(dataLength); using var ms = new MemoryStream(objectBytes); var formatter = new BinaryFormatter(); return formatter.Deserialize(ms); } }
使用示例:
var cacheBytes = await distributedCache.GetAsync("your-session-key"); var sessionData = SessionDataDeserializer.DeserializeSessionData(cacheBytes);
注意:会话中存储的复杂对象需标记
[Serializable]特性,否则BinaryFormatter无法反序列化。
会话的序列化与压缩说明
- 序列化规则:基本类型直接编码,复杂类型通过
BinaryFormatter序列化后嵌入二进制流。 - 压缩处理:默认不开启压缩,若配置了压缩(如下),读取到的
byte[]是Gzip压缩后的内容,需先解压再反序列化:
// Program.cs/Startup.cs中开启会话压缩 builder.Services.AddSession(options => { options.Compress = true; // 其他会话配置... });
解压代码:
using System.IO.Compression; public static byte[] DecompressSessionData(byte[] compressedBytes) { using var compressedStream = new MemoryStream(compressedBytes); using var gzipStream = new GZipStream(compressedStream, CompressionMode.Decompress); using var resultStream = new MemoryStream(); gzipStream.CopyTo(resultStream); return resultStream.ToArray(); }
调用流程:
var compressedData = await distributedCache.GetAsync("your-session-key"); var decompressedData = DecompressSessionData(compressedData); var sessionData = SessionDataDeserializer.DeserializeSessionData(decompressedData);
内容的提问来源于stack exchange,提问作者Vayne Main
相关产品推荐
相关产品推荐

