使用BinaryFormatter反序列化Web API字节数组时遇无效二进制格式异常
问题:二进制反序列化时提示“输入流不是有效的二进制格式”
我定义了实现ISerializable接口的可序列化类Class1:
[Serializable] public class Class1 : ISerializable { public int Id { get; set; } public string Name { get; set; } public Class1() { } Class1(SerializationInfo info, StreamingContext context) { Id = (int)info.GetValue(nameof(Id), typeof(int)); Name = (string)info.GetValue(nameof(Name), typeof(string)); } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue(nameof(Id), Id); info.AddValue(nameof(Name), Name); } public override string ToString() { return $"{Id}; {Name}"; } }
我的Web API将该类序列化后以字节数组形式返回:
public class DataController : ApiController { public byte[] Get() { Class1 class1 = new Class1() { Id = 100, Name = "Name" }; BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream()) { binaryFormatter.Serialize(memoryStream, class1); return memoryStream.ToArray(); } } }
在WinForms应用中,我尝试获取该序列化后的类并还原:
private async void Button1_Click(object sender, EventArgs e) { HttpClient httpClient = new HttpClient(); Uri uri = new Uri(textBox1.Text); var bytes = await httpClient.GetByteArrayAsync(uri); BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream(bytes)) { var class1 = binaryFormatter.Deserialize(memoryStream) as Class1; richTextBox1.Text = class1.ToString(); } }
但调用Deserialize方法时抛出异常,提示"The input stream is not a valid binary format.",请问哪里操作有误?
原因及解决办法
核心原因
Web API默认会将byte[]类型的返回值自动做Base64编码,以文本形式返回给客户端。你WinForms端用GetByteArrayAsync拿到的其实是这个Base64字符串的UTF-8字节数组,而非序列化后的原始二进制数据,所以直接反序列化会失败。
解决方法
方法1:修改Web API,返回原始二进制流
让API直接返回二进制内容,避免自动Base64编码:
public HttpResponseMessage Get() { Class1 class1 = new Class1() { Id = 100, Name = "Name" }; BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream()) { binaryFormatter.Serialize(memoryStream, class1); memoryStream.Position = 0; var response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StreamContent(memoryStream); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return response; } }
方法2:修改WinForms端,解码Base64字符串
如果不想改动API,客户端需要先将拿到的字节数组还原为Base64字符串,再解码成原始二进制数据:
private async void Button1_Click(object sender, EventArgs e) { HttpClient httpClient = new HttpClient(); Uri uri = new Uri(textBox1.Text); // 获取Base64格式的字符串 string base64Content = await httpClient.GetStringAsync(uri); // 解码为原始二进制数据 var rawBytes = Convert.FromBase64String(base64Content); BinaryFormatter binaryFormatter = new BinaryFormatter(); using (MemoryStream memoryStream = new MemoryStream(rawBytes)) { var class1 = binaryFormatter.Deserialize(memoryStream) as Class1; richTextBox1.Text = class1.ToString(); } }
额外注意事项
BinaryFormatter已被官方标记为过时,存在严重的安全漏洞(反序列化不可信数据可能导致代码执行),建议替换为System.Text.Json、Newtonsoft.Json或Protocol Buffers等更安全的序列化方案。- 确保WinForms项目中的
Class1类与Web API端的定义完全一致(包括命名空间、类名、属性、序列化构造函数和GetObjectData方法),否则即使二进制正确,也会反序列化失败。
内容的提问来源于stack exchange,提问作者DotNet Developer
相关产品推荐
相关产品推荐

