I have a peculiar situation. In a legacy system no longer used we have base64 values stored that we now need to access.
By converting the base64 value to a string I can see that the base64 value contains my properties needed like this.
The problem is that I can't deserialize neither the byte array or the string to a anonymous type object
or dynamic
. This is because I don't have access to the binaries that this object is using. In this example it is shown as ConsoleApp2
.
First try:
public static object FromByteArray(byte[] data)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
object obj = bf.Deserialize(ms);
return obj;
}
}
Source:
https://stackoverflow.com/a/33022788/3850405
System.Runtime.Serialization.SerializationException: 'Unable to find assembly 'ConsoleApp2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.'
Given that you normally can access properties from a plain Object Class I tried to set every assembly to System.Object
with a SerializationBinder
.
object o = new { A = "1", B = 2 };
public static object FromByteArray(byte[] data)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
bf.Binder = new PreMergeToMergedDeserializationBinder();
object obj = bf.Deserialize(ms);
return obj;
}
}
}
sealed class PreMergeToMergedDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
var systemObjectAssembly = "System.Object, System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
return Type.GetType(systemObjectAssembly);
}
}
Source:
https://stackoverflow.com/a/9012089/3850405
This prevents any runtime errors but everything that shows up looks like an empty object:
If I try to list properties using the code below it is of course empty as well.
Type myType = myObject.GetType();
List<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
What can I do to deserialize this base64 string and access the properties? Preferably I would not like to create a complete class hierarchy since the original object is quite large.
Runnable example program:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
object o = new { A = "1", B = 2 };
var base64String = "AAEAAAD/////AQAAAAAAAAAMAgAAAEJDb25zb2xlQXBwMiwgVmVyc2lvbj0xLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABhDb25zb2xlQXBwMi5FeGFtcGxlTW9kZWwCAAAAHDxNeVByb3BlcnR5QT5rX19CYWNraW5nRmllbGQcPE15UHJvcGVydHlCPmtfX0JhY2tpbmdGaWVsZAEACAIAAAAGAwAAAAtNeVRlc3RWYWx1ZXsAAAAL";
byte[] byteArray = Convert.FromBase64String(base64String);
string objectInfo = System.Text.Encoding.UTF8.GetString(byteArray);
var myObject = FromByteArray(byteArray);
Type myType = myObject.GetType();
List<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
}
public static object FromByteArray(byte[] data)
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream(data))
{
bf.Binder = new PreMergeToMergedDeserializationBinder();
object obj = bf.Deserialize(ms);
return obj;
}
}
}
sealed class PreMergeToMergedDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
var systemObjectAssembly = "System.Object, System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
return Type.GetType(systemObjectAssembly);
}
}
}
Guess how the original object could have been stored in the first place:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp2
{
[Serializable]
public class ExampleModel
{
public string MyPropertyA { get; set; }
public int MyPropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
var t = new ExampleModel();
t.MyPropertyA = "MyTestValue";
t.MyPropertyB = 123;
var byteArray = ToByteArray<ExampleModel>(t);
var base64String = Convert.ToBase64String(byteArray);
}
public static byte[] ToByteArray<T>(T obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
}
}
Aucun commentaire:
Enregistrer un commentaire