Недавно я присоединился к новой команде на работе, и у меня возникли проблемы с настройкой репозитория для одного из наших приложений, в частности, я получаю сообщение об ошибке при попытке выполнить операцию, и мы не смогли воспроизвести эту проблему ни для одного других членов команды.
В некотором дополнительном контексте приложение представляет собой приложение для Windows, которое работает на архитектуре x64 в качестве плагина для AutoCAD. Мы являемся магазином .NET, поэтому все приложение было написано на C# с использованием .NET framework, хотя управление версиями платформы не является единообразным во всем репозитории.
Проблема, с которой я столкнулся, заключается в том, что в приложении есть общая функция CloneJson. По какой-то причине этот метод выдает исключение при попытке десериализации одного из наших пользовательских объектов PortMap. Если вы не уловили это в заголовке, эта десериализация происходит с помощью пакета Newtonsoft.Json.
Вот полная ошибка: JsonSerializationException: 'Ошибка преобразования значения «CompanyName.ApplicationName.Common.Objects.Field.Reader, CompanyName.ApplicationName.Common.Objects, Version=1.0.8976.23506, Culture=neutral, PublicKeyToken=null» для типа ' Тип системы'.
Внутреннее исключение: ArgumentException: не удалось привести или преобразовать System.String в System.Type.
Ошибка возникает при вызове JsonConvert.Deserialize в методе ниже.
public static T CloneJson<T>(this T source)
{
if ((object)source == null)
return default(T);
var settings = new Newtonsoft.Json.JsonSerializerSettings()
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace,
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto
};
var serializedObj = Newtonsoft.Json.JsonConvert.SerializeObject((object)source, settings);
var deserializedOjb = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(serializedObj, settings);
return deserializedOjb;
}
И это объект PortMap. Я также могу предоставить PanelPortRepExpanded, но, поскольку это код компании, я стараюсь ограничить сумму, которой я делюсь, только тем, что абсолютно необходимо.
public class PortMap
{
public List<PanelPortRepExpanded> Ports { get; set; } = new List<PanelPortRepExpanded>();
public PortMap(List<PanelPortRepExpanded> ports)
{
Ports = ports;
}
public PortMap()
{
}
}
На этом этапе я пробовал довольно много вещей, включая замену версий пакетов, возиться с настройками сериализации. изменение/проверка зависимостей другими способами, но мне не повезло.
Я также попытался перезагрузить свой ноутбук, потому что у меня было установлено много случайных сред разработки, пакетов и т. д., которые, как я беспокоился, могли вызвать конфликт, но, похоже, это не дало никакого эффекта.
Некоторые другие важные детали:
Если вам нужна дополнительная информация о проблеме, пожалуйста, спрашивайте. На данный момент я готов попробовать что угодно, поэтому буду очень благодарен за любую помощь!
Редактировать:
Вот полный вывод исключения ToString() по запросу dbc:
Newtonsoft.Json.JsonSerializationException: Error converting value "CompanyName.ApplicationName.Common.Objects.Field.Reader, CompanyName.ApplicationName.Common.Objects, Version=1.0.8976.25178, Culture=neutral, PublicKeyToken=null" to type 'System.Type'. Path 'Ports[0].PermittedTypes[0]', line 1, position 174.
---> System.ArgumentException: Could not cast or convert from System.String to System.Type.
at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
--- End of inner exception stack trace ---
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyC onverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Seri alization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContain erContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at CompanyName.ApplicationName.Common.Objects.Helpers.Extensions.CloneJson[T](T source)
Вот сериализованный Json по запросу DavidG. Я взял на себя смелость усечь данные, потому что каждая запись в массиве по сути представляла собой идентичные данные:
{
"Ports": [
{
"PermittedTypes": [
"CompanyName.ApplicationName.Common.Objects.Field.Reader, CompanyName.ApplicationName.Common.Objects, Version=1.0.8977.16740, Culture=neutral, PublicKeyToken=null"
],
"PreferredTypes": [
"CompanyName.ApplicationName.Common.Objects.Field.Reader, CompanyName.ApplicationName.Common.Objects, Version=1.0.8977.16740, Culture=neutral, PublicKeyToken=null"
],
"AssociatedReaderSlot": 1,
"ReservedFor": [],
"PortName": "RDR 1",
"DeviceId": "00000000-0000-0000-0000-000000000000"
}
]
}
Если вы присоединились к новой команде, то, возможно, лучше всего вам в этом помогут новые люди?
Сказав это, возможно, вы пытаетесь вызвать этот метод CloneJson
с параметром общего типа Type
? Это предположение, поскольку нам просто не хватает контекста. Как вы называете этот метод? Как выглядит JSON? Какова полная иерархия типов PortMap
, PanelPortRepExpanded
и т. д.
@dbc Я только что добавил ToString() в качестве редактирования. Извините, это заняло минуту. Я не ожидал, что получу ответы так быстро.
@DavidG, к сожалению, я работал над этим со многими внутренними людьми и даже провел сеанс устранения неполадок с нашим техническим директором. Я решил, что обращусь сюда за некоторыми дополнительными перспективами. Это код, который вызывает CloneJson. Как видите, это метод расширения, поэтому тип определяется неявно на основе объекта, к которому он вызывается. var deserializedPortMap = Panel.PortMap.CloneJson();
@DavigG, я добавил структуру JSON. Базовая иерархия объектов заключается в том, что Panel является производным от интерфейса, у которого есть свойство PortMap. Затем PortMap содержит List<PanelPortRepExpanded>. PanelPortRepExpanded содержит несколько свойств List<System.Type>.
Я предполагаю, что когда он сериализовал объект, он превратил Тип в строку, теперь вам нужно сделать наоборот: для PermitedTypes и PreferredTypes содержащиеся значения необходимо преобразовать в Типы, используя что-то вроде Type.GetType( нить).
Проблема оказалась в том, что у AutoCAD есть собственная DLL для Newtonsoft.JSON, которая была той же версии, что и установленная в проекте через NuGet. Поскольку наше приложение представляет собой плагин для AutoCAD, Visual Studio загружала версию AutoCAD вместо пакета Newtonsoft.JSON, установленного в проекте.
У других коллег в программных файлах AutoCAD была более старая версия Newtonsoft DLL, поэтому я заменил версию в папке AutoCAD на эту, и это устранило проблему.
Спасибо всем, кто нашел время, чтобы попытаться помочь мне решить эту проблему.
Не могли бы вы отредактировать свой вопрос, чтобы поделиться полным
ToString()
выводом исключения, включая тип исключения, сообщение, полную обратную трассировку и внутренние исключения, если таковые имеются?