C# .net 5 knowntype не работает при сериализации классов из других библиотек
Есть базовый класс в основном ядре *.dll:
[KnownType("GetRealizations")]
[DataContract]
public abstract class AnimalBase
{
[DataMember]
public string Name { get; set; }
public AnimalBase()
{
}
public static List<Type> GetRealizations() => typeof(AnimalBase).GetRealizations();
}
Есть класс-наследник, реализованный в другом ядре *.dll:
[DataContract]
public class AnimalDog : AnimalBase
{
[DataMember]
public string Description { get; set; }
[DataMember]
public string HomeAdress { get; set; }
public AnimalDog()
{
}
}
Поиск типов (GetRealizations) организован следующим способом:
public static class AssemblyHelper
{
public static List<Type> GetRealizations(this Type type)
{
List<Type> res = new List<Type>();
Action<Assembly> getRealizationsFrom = e =>
{
IEnumerable<Type> assignable = e.GetTypesSafe().Where(t => !t.IsAbstract && type.IsAssignableFrom(t));
res.AddRange(assignable.ToList());
};
var files = new DirectoryInfo(Environment.CurrentDirectory).GetFiles("*.dll", SearchOption.TopDirectoryOnly).Select(x=>x.FullName).ToList();
foreach (var f in files)
try
{
getRealizationsFrom(Assembly.LoadFile(f));
}
catch (Exception)
{
continue;
}
return res;
}
private static Dictionary<string, Type[]> assebliesTypes = new Dictionary<string, Type[]>();
public static Type[] GetTypesSafe(this Assembly assembly)
{
if (assebliesTypes.ContainsKey(assembly.FullName))
return assebliesTypes[assembly.FullName];
Type[] tt = null;
try
{
tt = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
tt = ex.Types.Where(t => t != null).ToArray();
}
assebliesTypes.Add(assembly.FullName, tt);
return tt;
}
}
Сериализатор реализован следующим образом:
public static class Serializer
{
public static void Serialize<T>(this T obj, string path)
{
DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T));
try
{
using (FileStream fs = new FileStream(path, FileMode.Create))
js.WriteObject(fs, obj);
}
catch (Exception ex)
{
throw new Exception($"Ошибка при сериализации в файл {path} : {ex.Message}");
}
}
}
Пример использования в консольном приложении:
List<AnimalBase> animals = new List<AnimalBase>()
{
new AnimalDog() { Name = "Собачка1", Description = "Коричневая", HomeAdress = "Пушкина 2" },
new AnimalDog() { Name = "Собачка2", Description = "Белая", HomeAdress = "Маркса 4" }
};
Serializer.Serialize(animals, "D:\\11111.json");
В сериализаторе получаю ошибку: Type 'TinkSampleNet.AnimalDog' with data contract name 'AnimalDog:http://schemas.datacontract.org/2004/07/TinkSampleNet' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
В отладке вижу, что GetRealizations возвращает необходимые типы сериализватору.
ПРИ ЭТОМ в приложении .Net Framework все работает. Также работает, если в KnownType базового абстрактного класса указать конкретные типы, но это невозможно, т.к. они находятся в других библиотеках.
Помогите, всю голову поломал себе уже...
Ответы (1 шт):
Накидал вот такой класс, вроде работает, попозже проверю получше
public static class Serializer2
{
private static readonly JsonSerializerSettings settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented
};
public static void Serialize(object obj, string fName)
{
if (obj == null)
{
throw new NullReferenceException();
}
string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(obj, settings);
File.WriteAllText(fName, jsonString);
}
public static T Deserialize<T>(string fName)
{
string jsonString = File.ReadAllText(fName);
T obj = JsonConvert.DeserializeObject<T>(jsonString, settings);
return obj;
}
}