2016-09-08 2 views
2

У меня есть группа объектов домена, которые я сериализую, отправляю в другие приложения и затем десериализую с помощью Json.Net. Эти объекты могут иметь свойства, которыеOmit type для динамического свойства без изменения класса?

  • Определяется как абстрактный базовый класс с несколькими производными классами
  • Динамические свойства

Я использовал TypeNameHandling.Auto, который добавляет $type свойство типов, которые отличаются друг от объявленный тип. Однако этот параметр имеет нежелательный побочный эффект на мои динамические свойства, а именно, что типы их также объявляются.

В приведенном ниже примере model является динамическим свойством, определяемым как public dynamic Model { get; set; } в моем коде на C#.

"model":{"$type":"<>f__AnonymousType0`3[[System.String, mscorlib],[System.String, mscorlib],[System.String, mscorlib]], ExampleAssembly","link":"http://www.google.com","name":"John"} 

При попытке десериализации этой строки в другой сборке, Json.Net не может (конечно) найти ExampleAssembly. Использование TypeNameHandling.None свойства дает следующей Сериализации имущества

"model": {"link":"http://www.google.com","name":"John"} 

который может быть успешно десериализованная к dynamic. Однако это разрушает десериализацию производных типов.

Любые идеи о том, как заставить это работать без реализации пользовательских IContractResolver и, возможно, другого настраиваемого кода?

Я не являюсь владельцем объектов домена, поэтому я не могу их украсить или их свойства с помощью атрибутов или позволить им реализовать интерфейсы и т. Д. То, что я ищу, - это какая-то настройка в сериализаторе, который опускает типы для dynamics.

IMHO это должно быть настроено через настройки, так или иначе, я просто не нашел его.

+0

[JsonIgnore] или условного сериализации (http://www.newtonsoft.com /json/help/html/conditionalproperties.htm) может быть полезно – Nair

+0

@Nair: Спасибо, но, к сожалению, нет.Я не владею объектом домена и не могу затем украсить атрибутами или методами. Кроме того, это не очень хорошо масштабируется, поскольку я должен это для ВСЕХ объектов. – pardahlman

+0

Добавление '[JsonProperty (TypeNameHandling = TypeNameHandling.None)]' к соответствующему свойству было бы самым простым способом, но в вашем комментарии вы говорите, что не можете этого сделать. Возможно, вы захотите [изменить] вопрос, чтобы уточнить это требование. – dbc

ответ

2

Json.Net не предоставляет определенные настройки для отключения обработки имен типов только для динамических типов. Если вы не можете (или не хотите) отмечать соответствующие динамические свойства с помощью [JsonProperty(TypeNameHandling = TypeNameHandling.None)], то ваш единственный другой вариант (помимо изменения исходного кода Json.Net) заключается в том, чтобы реализовать пользовательский разрешитель контрактов для программного применения поведения , Но не беспокойтесь, это не сложно сделать, если вы вывели свой резольвер из одного из резольверов, предоставленных Json.Net, таких как DefaultContractResolver или CamelCasePropertyNamesContractResolver.

Вот весь код, вам нужно будет:

using System; 
using System.Reflection; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization; 

public class OmitTypeNamesOnDynamicsResolver : DefaultContractResolver 
{ 
    public static readonly OmitTypeNamesOnDynamicsResolver Instance = new OmitTypeNamesOnDynamicsResolver(); 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty prop = base.CreateProperty(member, memberSerialization); 
     if (member.GetCustomAttribute<System.Runtime.CompilerServices.DynamicAttribute>() != null) 
     { 
      prop.TypeNameHandling = TypeNameHandling.None; 
     } 
     return prop; 
    } 
} 

Затем, просто добавьте распознаватель к JsonSerializerSettings и вы должны быть все готово.

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.Auto, 
    ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance 
}; 

string json = JsonConvert.SerializeObject(foo, settings); 

Вот туда-обратно демо доказать концепцию:

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     Foo foo = new Foo 
     { 
      Model = new { link = "http://www.google.com", name = "John" }, 
      Widget1 = new Doodad { Name = "Sprocket", Size = 10 }, 
      Widget2 = new Thingy { Name = "Coil", Strength = 5 } 
     }; 

     JsonSerializerSettings settings = new JsonSerializerSettings 
     { 
      TypeNameHandling = TypeNameHandling.Auto, 
      ContractResolver = OmitTypeNamesOnDynamicsResolver.Instance, 
      Formatting = Formatting.Indented 
     }; 

     string json = JsonConvert.SerializeObject(foo, settings); 
     Console.WriteLine(json); 
     Console.WriteLine(); 

     Foo foo2 = JsonConvert.DeserializeObject<Foo>(json, settings); 
     Console.WriteLine(foo2.Model.link); 
     Console.WriteLine(foo2.Model.name); 
     Console.WriteLine(foo2.Widget1.Name + " (" + foo2.Widget1.GetType().Name + ")"); 
     Console.WriteLine(foo2.Widget2.Name + " (" + foo2.Widget2.GetType().Name + ")"); 
    } 
} 

public class Foo 
{ 
    public dynamic Model { get; set; } 
    public AbstractWidget Widget1 { get; set; } 
    public AbstractWidget Widget2 { get; set; } 
} 

public class AbstractWidget 
{ 
    public string Name { get; set; } 
} 

public class Thingy : AbstractWidget 
{ 
    public int Strength { get; set; } 
} 

public class Doodad : AbstractWidget 
{ 
    public int Size { get; set; } 
} 

Выход:

{ 
    "Model": { 
    "link": "http://www.google.com", 
    "name": "John" 
    }, 
    "Widget1": { 
    "$type": "Doodad, JsonTest", 
    "Size": 10, 
    "Name": "Sprocket" 
    }, 
    "Widget2": { 
    "$type": "Thingy, JsonTest", 
    "Strength": 5, 
    "Name": "Coil" 
    } 
} 

http://www.google.com 
John 
Sprocket (Doodad) 
Coil (Thingy) 
+0

Beautiful! Как я уже сказал, я предпочел бы использовать некоторые из функций без специальных классов. Тем не менее, ваша реализация Contact Resolver была очень маленькой, и это приветствуется. Спасибо за хорошо написанный ответ! – pardahlman

+0

Нет проблем; Рад, что смог помочь. –

Смежные вопросы