2014-11-07 5 views
10

तो, मुझे कक्षाओं का एक गुच्छा मिला है जिसे मुझे धारावाहिक/deserialize करने की आवश्यकता है जो डोमेन ऑब्जेक्ट्स (कम से कम कुछ ') होने के कारण होता है, इस प्रकार मैं उन्हें किसी विशेषताओं से मुक्त होना चाहता हूं या किसी निश्चित के आधार पर नहीं ढांचा।जेसन.NET के साथ फ्लुएंट कन्वर्टर्स/मैपर?

मैं कस्टम कन्वर्टर्स Json.NET में को देखा, लेकिन वे बहुत नहीं उपयोग के नियमों और क्या में मुझे करने के लिए 'प्राचीन' देखो, क्योंकि हम आजकल जेनरिक है और यह कि कठिन एक को लागू करने में नहीं है धाराप्रवाह इंटरफेस। तो इससे पहले कि मैं कमजोर टाइपिंग आदि की सड़क ..

... मैं (छद्म) के लिए क्या देख रहा हूँ नीचे जा रहा हूँ:

public class MyModel { 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public SomeObj SomeObj { get; set; } 
} 

public class MyModelConverter : JsonConverter<MyModel> { 

    public JsonConverter() { 
     RuleFor(x => x.Id).Name("Identifier"); 
     RuleFor(x => x.SomeObj).Name("Data") 
      .WithConverter(new SomeObjConverter()); 
     RuleFor(x => x.Name).Ignore(); 
    } 

} 

वहाँ कि Json.NET में ऐसा कुछ है? क्या मैं बस कुछ याद कर रहा हूँ? (वैसे मैं अपने गुणों के लिए अलग-अलग नामों का उपयोग नहीं कर सकता हूं क्योंकि मॉडल तीसरे पक्ष के विनिर्देश पर आधारित हैं)।

+2

हो सकता है कि 'AutoMapper' का उपयोग करें और वांछित वर्ग में डोमेन वस्तु डालना? इसमें एक वाक्यविन्यास * ver * है जो आप ढूंढ रहे हैं उसके करीब है। – code4life

+0

एक्सटेंशन विधियों और JSON.NET को छिपाने के लिए अपनी खुद की वृद्धि प्लगइन जारी करें! :-) – VulgarBinary

+0

आप बस एक नया अनाम प्रकार बना सकते हैं और उसके बाद उसे क्रमबद्ध कर सकते हैं। '... नया {पहचानकर्ता = x.Id, ...}' –

उत्तर

2

यहाँ वांछित एपीआई प्राप्त करने पर मेरी ले है:

के रूप में टिप्पणी प्रति संपादित

public abstract class Rule 
{ 
    private Dictionary<string, object> rule { get; } = new Dictionary<string, object>(); 

    protected void AddRule(string key, object value) 
    { 
     if (rule.ContainsKey(key)) 
     { 
      rule.Add(key, value); 
     } 
     else 
     { 
      rule[key] = value; 
     } 
    } 

    protected IEnumerable<KeyValuePair<string, object>> RegisteredRules 
    { 
     get 
     { 
      return rule.AsEnumerable(); 
     } 
    } 
} 

public abstract class PropertyRule : Rule 
{ 
    public MemberInfo PropertyInfo { get; protected set; } 

    public void Update(JsonProperty contract) 
    { 
     var props = typeof(JsonProperty).GetProperties(); 
     foreach (var rule in RegisteredRules) 
     { 
      var property = props.Where(x => x.Name == rule.Key).FirstOrDefault(); 
      if (property != null) 
      { 
       var value = rule.Value; 
       if (property.PropertyType == value.GetType()) 
       { 
        property.SetValue(contract, value); 
       } 
      } 
     } 
    } 
} 

public class PropertyRule<TClass, TProp> : PropertyRule 
{ 
    public const string CONVERTER_KEY = "Converter"; 
    public const string PROPERTY_NAME_KEY = "PropertyName"; 
    public const string IGNORED_KEY = "Ignored"; 

    public PropertyRule(Expression<Func<TClass, TProp>> prop) 
    { 
     PropertyInfo = (prop.Body as System.Linq.Expressions.MemberExpression).Member; 
    } 

    public PropertyRule<TClass, TProp> Converter(JsonConverter converter) 
    { 
     AddRule(CONVERTER_KEY, converter); 
     return this; 
    } 

    public PropertyRule<TClass, TProp> Name(string propertyName) 
    { 
     AddRule(PROPERTY_NAME_KEY, propertyName); 
     return this; 
    } 

    public PropertyRule<TClass, TProp> Ignore() 
    { 
     AddRule(IGNORED_KEY, true); 
     return this; 
    } 
} 

public interface SerializationSettings 
{ 
    IEnumerable<Rule> Rules { get; } 
} 

public class SerializationSettings<T> : SerializationSettings 
{ 
    private List<Rule> rules { get; } = new List<Rule>(); 

    public IEnumerable<Rule> Rules { get; private set; } 

    public SerializationSettings() 
    { 
     Rules = rules.AsEnumerable(); 
    } 

    public PropertyRule<T, TProp> RuleFor<TProp>(Expression<Func<T, TProp>> prop) 
    { 
     var rule = new PropertyRule<T, TProp>(prop); 
     rules.Add(rule); 
     return rule; 
    } 
} 

public class FluentContractResolver : DefaultContractResolver 
{ 
    static List<SerializationSettings> settings; 

    public static void SearchAssemblies(params Assembly[] assemblies) 
    { 
     SearchAssemblies((IEnumerable<Assembly>)assemblies); 
    } 

    public static void SearchAssemblies(IEnumerable<Assembly> assemblies) 
    { 
     settings = assemblies.SelectMany(x => x.GetTypes()).Where(t => IsSubclassOfRawGeneric(t, typeof(SerializationSettings<>))).Select(t => (SerializationSettings)Activator.CreateInstance(t)).ToList(); 
    } 

    //http://stackoverflow.com/questions/457676/check-if-a-class-is-derived-from-a-generic-class 
    static bool IsSubclassOfRawGeneric(System.Type toCheck, System.Type generic) 
    { 
     if (toCheck != generic) 
     { 
      while (toCheck != null && toCheck != typeof(object)) 
      { 
       var cur = toCheck.GetTypeInfo().IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; 
       if (generic == cur) 
       { 
        return true; 
       } 
       toCheck = toCheck.GetTypeInfo().BaseType; 
      } 
     } 
     return false; 
    } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var contract = base.CreateProperty(member, memberSerialization); 

     var rule = settings.Where(x => x.GetType().GetTypeInfo().BaseType.GenericTypeArguments[0] == member.DeclaringType).SelectMany(x => x.Rules.Select(r => r as PropertyRule).Where(r => r != null && r.PropertyInfo.Name == member.Name)).FirstOrDefault(); 
     if (rule != null) 
     { 
      rule.Update(contract); 
     } 
     return contract; 
    } 
} 
अब कार्यक्रम में कहीं पर

शुरू हुआ:

FluentContractResolver.SearchAssemblies(typeof(MyModel).GetTypeInfo().Assembly); 

Newtonsoft.Json.JsonConvert.DefaultSettings =() => 
{ 
    return new Newtonsoft.Json.JsonSerializerSettings 
    { 
     Formatting = Newtonsoft.Json.Formatting.Indented, 
     ContractResolver = new FluentContractResolver() 
    }; 
}; 
इस के साथ

में अब आपको धाराप्रवाह सेटिंग्स के साथ कक्षाएं जोड़ने की आवश्यकता है:

public class MyModelSettings : SerializationSettings<MyModel> 
{ 

    public MyModelSettings() 
    { 
     RuleFor(x => x.Id).Name("Identifier"); 
     RuleFor(x => x.SomeObj).Name("Data").Converter(new SomeObjConverter()); 
     RuleFor(x => x.Name).Ignore(); 
    } 

} 
+0

1. PropertyRule.Update में पहली पंक्ति होना चाहिए: var props = typeof (JsonProperty) .GetProperties(); 2. .NET कोर के लिए टाइप गुण IsGenericType, असेंबली, और बेसटाइप GetTypeInfo() के माध्यम से सुलभ हैं। इससे सब कुछ ठीक है ठीक है। अच्छा समाधान –

+0

@AlexanderChristov मैंने आपकी टिप्पणी के अनुसार कोड संपादित किया है। धन्यवाद! – Nripendra

1

Fluent-Json.NET आपको ऑब्जेक्ट्स को मैप करने, टाइप करने वाले भेदभावियों का उपयोग करने की अनुमति देता है, सब कुछ आपके डेटा ऑब्जेक्ट्स में हस्तक्षेप किए बिना। कोई विशेषताओं की आवश्यकता नहीं है।

मानचित्रण कक्षाएं

public class AnimalMap : JsonMap<Animal> 
{ 
    public AnimalMap() 
    { 
     this.DiscriminateSubClassesOnField("class"); 
     this.Map(x => x.Speed, "speed"); 
    } 
} 

public class FelineMap : JsonSubclassMap<Feline> 
{ 
    public FelineMap() 
    { 
     this.Map(x => x.SightRange, "sight"); 
    } 
} 

public class LionMap : JsonSubclassMap<Lion> 
{ 
    public LionMap() 
    { 
     this.DiscriminatorValue("lion"); 
     this.Map(x => x.Strength, "strength"); 
    } 
} 

मॉडल वर्गों

public class Animal 
{ 
    public Animal(float speed) 
    { 
     this.Speed = speed; 
    } 

    public float Speed { get; set; } 
} 

public abstract class Feline : Animal 
{ 
    protected Feline(float speed, float sightRange) : base(speed) 
    { 
     this.SightRange = sightRange; 
    } 

    public float SightRange { get; set; } 
} 

public class Lion : Feline 
{ 
    public Lion(float speed, float sightRange, float strength) : base(speed, sightRange) 
    { 
     this.Strength = strength; 
    } 

    public float Strength { get; set; } 
} 
संबंधित मुद्दे