Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[.NET] JSON serialization tijdens runtime bepalen

Pagina: 1
Acties:

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
Ik heb een object met een aantal 'nested' sub-objecten welke ik graag naar JSON wil serializen met JSON.NET. Ik moet echter tijdens runtime kunnen bepalen welke members (van zowel het hoofd object als de sub-objecten) in de JSON moeten komen en welke niet. Daarvoor heb ik een lijstje met member names (strings).

Stel bijvoorbeeld dat ik een object RaceCarDriver heb met een naam, een Fastest Laptime en een Last laptime, beide van type Laptime:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class RaceCarDriver 
{
    public string Name {get; set;}
    public Laptime FastestLap {get; set;|
    public Laptime LastLap {get; set;}
}

public class Laptime 
{
    public TimeSpan Time {get; set;}
    public int MilliSeconds {get; set;}
    public int Lap {get; set;}
}


Nu wil ik een RaceCarDriver serializen, maar ik wil enkel de naam, en de 'MilliSeconds' property van de Laptime properties. Ik heb dus een lijstje met de volgende member names die ik wil serializen:
code:
1
2
3
Name
FastestLap.MilliSeconds
LastLap.MilliSeconds


Let op dat ik hier de NAAM van de property (FastestLap / LastLap) gebruik en niet het TYPE (Laptime), dat is belangrijk. Het zou namelijk kunnen zijn dat ik van de FastestLap de Milliseconds wil maar van de LastLap alleen de Lap:
code:
1
2
3
Name
FastestLap.MilliSeconds
LastLap.Lap

Er moet dus onderscheid gemaakt worden op property naam en niet op type (Laptime) anders is het niet duidelijk voor welke property van dat type de member name geldt (indien er meerdere van hetzelfde type zijn zoals hier).

Dit lijstje met member names wordt tijdens runtime aangemaakt.


Hoe kan ik nu een RaceCarDriver object serializeren rekening houdend met de properties die ik wil hebben?

Ik ben aan het kijken naar een custom ContractSerializer door een subclass van DefaultContractResolver te maken. Daar kan ik een aantal methods overriden die er nuttig uit zien, bijvoorbeeld CreateProperties, waar ik een lijstje JsonProperties krijg waar uit ik properties kan gooien die ik niet wil (omdat ze niet in de lijst voorkomen).


Het probleem wat ik overal tegenkom is echter steeds hetzelfde: als ik twee properties met hetzelfde type heb (zoals de Laptime properties in het voorbeeld) dan kan ik geen onderscheid maken. Ik heb in mijn lijstje de NAAM van de property (FastestLaptime) maar in elk van deze methods kan ik alleen het type vinden (Laptime) dus weet ik niet welke van de twee (of meer) properties ik op dit moment aan het serializen ben en dus welke ik moet toelaten en welke niet.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    public class DriverContractResolver : DefaultContractResolver
    {
        private readonly List<string> _members; 

        public DriverContractResolver(IEnumerable<string> members)
        {
            _members = new List<string>(members);
        }

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

            // Hier kan ik eventueel de property niet toelaten via:
            p.ShouldSerialize = x => false;
            
            return p;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = base.CreateProperties(type, memberSerialization);

            // Hier kan ik eventueel filteren bijv:
            properties = properties.Where(p => p.PropertyName == "A").ToList();
            
            return properties;
        }
    }


Ik kan wel bij de PropertyName van de huidige property (dat zou bijvoorbeeld "MilliSeconds" of "Lap" zijn), maar niet bij de PropertyName van de parent property (ofwel "FastestLapt" of "LastLap"), maar enkel het type van de parent ("Laptime") waar ik dus niks aan heb.

Hoe kom ik hier aan de NAAM van de parent property (ipv het type) zodat ik kan bepalen of die property mee moet komen of niet?

Dit zou toch wel mogelijk moeten zijn, want JSON.NET kan dit object prima serializen naar JSON waarbij het sub-object gewoon 'FastestLap' heet en niet 'Laptime'. Ik kan echter niet vinden hoe ik aan die informatie kom. Als ik het JsonProperty object inspecteer zie ik nergens de naam van de parent property terug komen, enkel het type...

[ Voor 4% gewijzigd door NickThissen op 24-01-2015 13:05 ]

Mijn iRacing profiel


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
Waarom weet je niet @compile time wat je moet serializen eigenlijk? Op basis van wat wordt dit bepaald? Ik zou zelf n.l. gewoon een class maken met de te serializen properties ....

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 19-11 18:15

Sebazzz

3dp

Het lijkt mij anders ook dat je niet echt wilt serializen via de standaard manier maar beter zelf je JSON graph kan samenstellen.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

https://blog.mariusschulz...d-properties-with-jsonnet

Uit interesse even gezocht. Denk dat dit is wat je zoekt.

Overigens weet ik niet waarom je @runtime zou willen bepalen wat je serialised. Ik weet niet waar je deserialized, maar het lijkt me prettig om te weten waar je aan toe bent, als ontvangende kant zijnde.

[ Voor 38% gewijzigd door EddoH op 24-01-2015 20:11 ]


  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
Ik wil dit tijdens runtime doen omdat de gebruiker van het programma het lijstje met member names tijdens runtime kan samenstellen.

De data is een lijst met RaceCarDrivers welke elke paar seconden naar een website gestuurd worden. De website slaat de json weer op en met wat javascript wordt een tabel gevuld met de data. De gebruiker moet kunnen kiezen welke eigenschappen hij van elke RaceCarDriver wil laten zien. In principe wil je zo weinig mogelijk versturen om de data zo klein mogelijk te houden zodat je sneller kan updaten zonder de server steeds een gigantische hoeveelheid data te sturen. Als men alle members mee zou willen sturen dan is dat een hele hoop en dat zou niet 'moeten', dus laat ik mensen zelf samenstellen wat ze willen laten zien en de rest stuur ik niet mee.

Naast de data zelf worden ook de members die de gebruiker kiest (het lijstje met namen dus) naar de website gestuurd. Aan de javascript kant weet de pagina dus ook precies welke kolommen er in de tabel moeten komen en dus ook precies welke members er in de data zitten, dus deserialization is geen probleem.


@EddoH:
Dat had ik al gezien, maar de JsonIgnore is natuurlijk geen optie voor runtime bepaling. ShouldSerialize heeft weer het probleem dat ik dat voor ELKE property toe moet gaan voegen en dan ook nog met reflection oid die properties allemaal true/false moet gaan zetten. Niet echt handig.


Uiteindelijk heb ik het iets anders aangepakt en gebruik ik toch reflection, zou het liever niet doen ivm snelheid maar het lijkt toch meer dan snel genoeg te gaan. In plaats van de serializer aanpassen heb ik gekozen om gewoon een nieuwe lijst met data te maken waar ik een Dictionary in gooi. De dictionary vul ik met key/values voor elke member die de gebruiker gekozen heeft (via reflection). Dat werkt ok.

Mijn iRacing profiel


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Hoe anders dan met Reflection kun je member names vergelijken met runtime strings? Op het moment dat je een compile-time naam wil gebruiken in een runtime omgeving is het per definitie al reflectie.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Je zou dynamisch dmv reflectie een anonymous object kunnen bouwen mbv een expando en deze laten serializen.

  • NickThissen
  • Registratie: November 2007
  • Laatst online: 18-11 13:07
MSalters schreef op maandag 26 januari 2015 @ 13:38:
Hoe anders dan met Reflection kun je member names vergelijken met runtime strings? Op het moment dat je een compile-time naam wil gebruiken in een runtime omgeving is het per definitie al reflectie.
Ik ga er van uit dat JSON.NET intern ook genoeg reflection gebruikt, maar ik wilde voorkomen om dat zelf nog eens te moeten doen en hoopte dat er binnen JSON.NET een mogelijkheid was om die namen (die de library al moet hebben) te vinden, bijvoorbeeld in een custom ContractResolver. Maar dat lijkt dus niet zo te zijn, of ik kan het in ieder geval niet vinden.
D-Raven schreef op maandag 26 januari 2015 @ 14:11:
Je zou dynamisch dmv reflectie een anonymous object kunnen bouwen mbv een expando en deze laten serializen.
Zoiets heb ik uiteindelijk ook gedaan (met een Dictionary<string,object> ipv een expando) en dat werkt ok.

Mijn iRacing profiel


  • SideShow
  • Registratie: Maart 2004
  • Laatst online: 30-10 17:25

SideShow

Administrator

new JObject();
Ook een mogelijkheid dacht ik. Maar dat heeft natuurlijk wel erg veel weg van een dynamic expando object.

  • ZaZ
  • Registratie: Oktober 2002
  • Laatst online: 20-11 12:36

ZaZ

Tweakers abonnee

Kan je niet zoiets doen met een JsonConverter? Die geef je mee als extra parameter aan je serialize/deserialize routine en daar kan je eventueel de hele boel mee customizen en properties weglaten/toevoegen etc.
Heb ik wel eens gebruikt volgens mij.

Lekker op de bank

Pagina: 1