Ошибки сериализации в Json.NET Uri (de) - PullRequest
3 голосов
/ 17 октября 2011

Мне нужно сериализовать и десериализовать объект, который содержит свойство System.Uri, используя новейшую (4.0.3) Json.NET библиотеку.

Следующий код демонстрирует проблему:

string input = "http://test.com/%22foo+bar%22";
Uri uri = new Uri(input);
string json = JsonConvert.SerializeObject(uri);
Uri output = JsonConvert.DeserializeObject<Uri>(json);

Метод DeserializeObject создает исключение JsonReaderException. Это отлично работает с 4.0.2.

Я отправил проблему в codeplex с тестами и патчем, чтобы исправить эту проблему, но, кажется, автору требуется немного времени, чтобы выпустить исправленную версию.

Между тем, что я могу сделать (используя JsonSettings или что-то еще), чтобы последняя версия работала, как ожидалось?

Несколько вариантов, которые у меня есть:

  1. придерживайтесь 4.0.2 - новые пакеты nuget зависят от 4.0.3
  2. изменить URI на строку - я предпочитаю использовать опцию 1 и вручную управлять зависимостями pkg
  3. использовать пользовательскую сборку с примененным патчем - это то, чем я сейчас занимаюсь, но я ненавижу идею переопределения сборок пакета nuget.

1 Ответ

5 голосов
/ 11 ноября 2011

Вы можете написать вспомогательный класс, который обходит обычную обработку System.Uri и обрабатывает ее исключительно как строку, используя свойство Uri.OriginalString.

Вот пример кода, который делает именно это с классом конвертера, полученным из JsonConverter.

Json.Net.

Свойство OriginalString (System.Uri) @ MSDN

Одно предостережение: вы должны обновить все места, где вы используете JsonConvert, чтобы включить вспомогательный класс в качестве одного из дополнительных JsonConverter параметров.

Я также добавил пример использования Uri в качестве переменной-члена в классе, чтобы продемонстрировать, что не обязательно переопределять атрибуты класса, хотя это может быть более удобным для вас. Если это так, вы можете использовать [JsonConverter(UriConverter)] в качестве атрибута для членов, которые в нем нуждаются.

using Newtonsoft.Json;

namespace JsonUriSerializeTest
{
    class Program
    {
        public class UriConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return objectType.Equals(typeof(Uri));
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                if (reader.TokenType == JsonToken.String)
                {
                    return new Uri((string)reader.Value);
                }

                if (reader.TokenType == JsonToken.Null)
                {
                    return null;
                }

                throw new InvalidOperationException("Unhandled case for UriConverter. Check to see if this converter has been applied to the wrong serialization type.");
            }

            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                if (null == value)
                {
                    writer.WriteNull();
                    return;
                }

                if (value is Uri)
                {
                    writer.WriteValue(((Uri)value).OriginalString);
                    return;
                }

                throw new InvalidOperationException("Unhandled case for UriConverter. Check to see if this converter has been applied to the wrong serialization type.");
            }
        }

        public class UriPair
        {
            public string label { get; set; }
            public Uri first { get; set; }
            public Uri second { get; set; }

            public void Display()
            {
                Console.WriteLine(string.Format("label:  {0}", label));
                Console.WriteLine(string.Format("first:  {0}", first));
                Console.WriteLine(string.Format("second: {0}", second));
            }
        }

        static void Main(string[] args)
        {
            string input = "http://test.com/%22foo+bar%22";
            Uri uri = new Uri(input);
            string json = JsonConvert.SerializeObject(uri, new UriConverter());
            Uri output = JsonConvert.DeserializeObject<Uri>(json, new UriConverter());

            Console.WriteLine(input);
            Console.WriteLine(output.ToString());
            Console.WriteLine();

            UriPair pair = new UriPair();
            pair.label = input;
            pair.first = null;
            pair.second = new Uri(input);
            string jsonPair = JsonConvert.SerializeObject(pair, new UriConverter());
            UriPair outputPair = JsonConvert.DeserializeObject<UriPair>(jsonPair, new UriConverter());

            outputPair.Display();
            Console.WriteLine();

            Console.ReadKey();
        }
    }
}
...