If anyone gets curious about how you can do this, here is a way. Its a rough little experiment I put together. Its not robust, just a breadcrumb. I'm not sharing this to say you should do this, since reflection is a cost. That's up to you and your requirements to decide. I'm just sharing the how. This will successfully map the MS-NRBF back into a class model. Note the recursion.
NOTE: This only works with objects. If it was a string value that was transformed originally, the library will just pull the string value out directly, so you'll need to cast it into (string) instead of (BinaryObject). You can read this to learn more about the MS-NRBF headers if you want to deeper dive into what the lib is doing: https://localcoder.org/how-to-analyse-contents-of-binary-serialization-stream
I used this lib to digest the format: https://github.com/bbowyersmyth/BinaryFormatDataStructure
private T TransformMSNRBFToObject<T>(byte[] data) where T : new()
{
T response = new T();
using (var stream = new MemoryStream(data))
{
var bObj = (BinaryObject)NRBFReader.ReadStream(stream);
GetObjectFromBinaryObject<T>(bObj, response);
}
return response;
}
private void GetObjectFromBinaryObject<T>(BinaryObject bObj, T result) where T : new()
{
foreach (var prop in result.GetType().GetProperties())
{
string key = $"<{prop.Name}>k__BackingField";
if (!bObj.ContainsKey(key))
{
throw new Exception($"Transform could not occur. Expected property {prop.Name} in data, but none was found.");
}
//If its a nested class, then the value will be another BinaryObject. Use recursion to get that next obj mapped.
if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string))
{
var type1 = prop.PropertyType;
var propValue = (BinaryObject)bObj[key];
try
{
var result2 = Activator.CreateInstance(type1);
GetObjectFromBinaryObject(propValue, result2);
prop.SetValue(result, result2);
}
catch (System.MissingMethodException mme) //This happens usually when you try to map a string or system object
{
throw new Exception($"Model you are trying to convert to is missing an empty contstructor. Class: {type1}");
}
}
else //its a IConvertible field or a string
{
prop.SetValue(result, bObj[key]);
}
}
}