You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确反序列化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:09:59