Reputation: 1107
My error handling fixes the deserialization problem itself of JsonConvert.DeserializeObject
.
My question is now, how can i retry to deserialize the problematic object during process without breaking the whole deserialization procedure and trying again?
At first i set my error handling as follows JsonSerializerSettings.Error = HandleCouldNotLoadAssemblyError;
The serializer class looks like this:
public class Serializer
{
private JsonSerializerSettings Settings { get; set; }
public Serializer()
{
Settings = new JsonSerializerSettings(); // todo: add converters
Settings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full;
Settings.TypeNameHandling = TypeNameHandling.Objects;
Settings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
Settings.Error = HandleCouldNotLoadAssemblyError;
}
private void HandleCouldNotLoadAssemblyError(object sender, ErrorEventArgs args)
{
if (args != null && args.ErrorContext != null && args.ErrorContext.Error != null && args.ErrorContext.Error.GetType() == typeof(JsonSerializationException))
{
Logger.Error(args.ErrorContext.Error);
foreach (var repository in DeviceInformationManager.InformationSources.OfType<DeviceDriverRepository.DeviceDriverRepository>())
{
var result = repository.LoadType(args.CurrentObject.GetType().FullName);
if (result != null)
{
//args.CurrentObject = JsonConvert.DeserializeObject("SUBSTRING OF SERIALIZED DATA");
args.ErrorContext.Handled = true;
break;
}
}
}
}
public string Serialize(object obj)
{
// Serialize
return JsonConvert.SerializeObject(obj, Formatting.Indented, Settings);
}
public T Deserialize<T>(string serializedData)
{
// Deserialize
return JsonConvert.DeserializeObject<T>(serializedData, Settings);
}
The reason for the fail of json.net
is that my Assemblies are loaded dynamically during runtime. In the error handling I load missing assemblies.
At the moment deserialization only works by calling the Deserialize
twice.
Upvotes: 0
Views: 2529
Reputation: 1107
dbc led me on right track. So I coded a type binder to solve my problem:
/// <summary>
/// This binder looks for not found <see cref="Type"/>s in the unloaded assemblies of the repositories.
/// </summary>
public class RepositoryTypesBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type type = null;
try
{
type = base.BindToType(assemblyName, typeName);
if (type != null)
{
return type;
}
}
catch (JsonSerializationException)
{
// Type has not been found, so try to find type in some repositories
foreach (var repository in DeviceInformationManager.InformationSources.OfType<DeviceDriverRepository.DeviceDriverRepository>())
{
// Search for assembly paths and check their names
foreach (var driverUri in repository.GetDriverUris(null))
{
var targetAssemblyName = AssemblyName.GetAssemblyName(driverUri.LocalPath);
if (targetAssemblyName != null && targetAssemblyName.FullName.Equals(assemblyName))
{
// Load assembly into AppDomain
Assembly assembly = Assembly.Load(targetAssemblyName);
type = assembly.GetType(typeName, false);
if (type != null)
{
return type; // If type was found: finish
}
// else continue
}
}
}
// If not sufficient type has found until here: throw Error;
throw;
}
return null;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = serializedType.Assembly.FullName;
typeName = serializedType.FullName;
}
}
Use it like this:
var Settings = new JsonSerializerSettings();
Settings.Binder = new RepositoryTypesBinder();
JsonConvert.DeserializeObject<T>(serializedData, Settings);
Upvotes: 1