Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB.NET: JSON-datan lukeminen netistä

Sivun loppuun

Rox [02.05.2013 15:03:59]

#

Hei.. Mulla ois yks kyssäri. Louhin bitcoineja, ja poolillani on api. Kun menen api linkkiin, näen seuraavankaltaisen tekstin, (yhdellä rivillä!):

{"user":{"confirmed_rewards":0.0867721,"payouts":0,"hash_rate":"289.91","active_workers":1},"workers":{"1":{"worker_name":"TÄMÄ","hash_rate":"TÄMÄ","shares":244,"stales":2,"invalid":1,"checkpoint_shares":0,"checkpoint_stales":0,"checkpoint_invalid":0,"total_shares":TÄMÄ,"total_stales":266,"total_invalid":147,"last_share":1367495718,"blocks_found":0,"alive":true}}}

Miten luen tuon tekstin ohjelmassani? Haluaisin kohdat missä lukee "TÄMÄ", labeleihin, ihan vaan sen takia että voisin simppelisti avata aina ohjelman ja kurkata montako 'sharea' oon tehnyt jne. Jos joku viittis vähän helppiä :)

User137 [02.05.2013 15:16:57]

#

Etsit tekstipätkän "total_shares", ja luet mitä on sen jälkeisen kaksoispisteen ja pilkun välissä? Tuo nyt 1 simppeli tapa, ellet halua parsia koko höskää nimi:arvo tietueiks.

Metabolix [02.05.2013 15:22:21]

#

Viisainta olisi käyttää jotain JSON-datan lukemiseen tarkoitettua kirjastoa (googleta; esim. http://json.codeplex.com/), jotta saat tekstin järkeväksi oliorakenteeksi, josta saat helposti poimittua oikeat kohdat. Toinen vaihtoehto on yrittää tunnistaa oikea kohta ympäröivien tekstien perusteella, kuten User137 ehdotti; siihen riittävät tavalliset String-luokan metodit kuten IndexOf, Substring ja Split.

Rox [02.05.2013 15:25:18]

#

Okei, miten poimin oikeat kohdat tuosta tekstistä?

Metabolix [02.05.2013 15:28:02]

#

Mainitsin oikeiden kohtien poimimisen vasta sivulauseen sivulauseessa. Luitko edellisiä lauseita ollenkaan, etkö ymmärtänyt niistä mitään, vai mistä kiikastaa?

Jos et osaa ollenkaan ohjelmoida, voit ihan suoraan sanoa sen ja kertoa, mikä tämän keskustelun tarkoitus on: tulitko esimerkiksi pyytämään valmista koodia, ja onko jokin syy tehdä se juuri VB.NETillä, jos et edes osaa sitä.

qeijo [03.05.2013 14:43:57]

#

DataContractJsonSerializerilla onnistuu suhteellisen helposti, C# esimerkkikoodi löytyy tarvittaessa.

http://msdn.microsoft.com/en-us/library/system.­run­ti­me.­se­ri­a­li­za­ti­on.j­son.­da­ta­cont­ractj­son­se­ri­a­li­zer.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

Siinäpä simppeli C# esimerkki josta see ehkä ideaa:

public class Workers
{
     public string worker_name, hash_rate;
     public int total_shares;
}

String json = "{\"worker_name\":\"Einari\",\"hash_rate\":21, \"total_shares\":1236}"; //hae verkon kautta..

MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
DataContractJsonSerializer jsonser = new DataContractJsonSerializer(typeof(Workers));

Workers worker = jsonser.ReadObject(ms) as Workers;

//worker.worker_name;
//worker.hash_rate;
//worker.total_shares;

groovyb [06.05.2013 11:46:38]

#

mahtaakohtan tuo toimia ilman että luokkaan on määritetty datacontract ja datamemberit (kyseessä on kuitenkin DataContractiin perustuva serialisointi).

How to: Serialize and Deserialize JSON Data

as in:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Xml;

namespace Test
{
    [DataContract]
    public class Worker
    {
        private string workerName;
        [DataMember]
        public string WorkerName
        {
            get { return workerName; }
            set { workerName = value; }
        }

		private string hashRate;
        [DataMember]
        public string HashRate
        {
            get { return hashRate; }
            set { hashRate = value; }
        }

		private int totalShares;
        [DataMember]
        public int TotalShares
        {
            get { return totalShares; }
            set { totalShares = value; }
        }
    }
}

Grez [06.05.2013 12:06:22]

#

groovyb kirjoitti:

mahtaakohtan tuo toimia ilman että luokkaan on määritetty datacontract ja datamemberit (kyseessä on kuitenkin DataContractiin perustuva serialisointi).

Mahtaa toimia ilmankin. Qeijon laittamaa esimerkkiä kokeilemallahan se olisi selvinnyt.

groovyb [06.05.2013 12:12:48]

#

Mihin tuo serialisointi silloin perustuu, kun luokkaan ei xml serialisoinnin attribuutteja ole asetettu? Pitääkö luokka silloin periyttää ISerializable tai IXmlSerializable interfaceista jotta luokka ylipäätään voidaan serialisoida (http://msdn.microsoft.com/en-us/library/vstudio/system.runtime.serialization.iserializable.aspx)?

esimerkin serialisointiin (DataContractJsonSerializer) lyödään luokan tyyppi, ja msdn sanoo Typestä näin:

'Declaration
<SerializableAttribute> _
<ClassInterfaceAttribute(ClassInterfaceType.None)> _
<ComVisibleAttribute(True)> _
Public MustInherit Class Type _
Inherits MemberInfo _
Implements _Type, IReflect


TypeOf itsessään palauttaa luokasta memberit ja muut härpäkkeet, mutta ne tulee objektimuodossa, eikä suinkaan DataContractina kuten DataContractJsonSerializer antaisi ymmärtää. (MSDN:n dokkarissakin on datacontract käytössä: http://msdn.microsoft.com/en-us/library/system.­run­ti­me.­se­ri­a­li­za­ti­on.j­son.­da­ta­cont­ractj­son­se­ri­a­lizer(v=VS.95).aspx)

tämän mukaan ainakin joku serialisointiattribuutti pitäisi olla mukana jos serialisoidaan ja nyt kiinnostaisi tosiaan se, että miten serialisointi tapahtuu käytännössä, jos mitään xml schemaa ei ole lyöty kiinni millään attribuutilla luokkaan. (eli kun TypeOf palauttaa luokan tyypin, ja luokassa ei ole mitään serialisointiin määritettävää attribuuttia)

qeijo [06.05.2013 12:44:24]

#

Mitäs outoa tuossa on? Ilman erillistä DataContract:ia kaikki jäsenmuuttujat joutuvat serialisoinnin kohteeksi.

groovyb [06.05.2013 12:59:32]

#

Tuohan se asia onkin mikä hämää, koska jos pätkä serialisoidaan datacontractin mukaan, tulisi luokankin edellyttää datacontractia.

XmlSerializer toimii siten, että se serialisoi automaattisesti kaiken, DataContractSerializer taas ei tee niin, vaan serialisoi vain ne jotka on määritetty (ja että ylipäätään contract on olemassa).

Tässä kiinnostaakin lähinnä se, että miten tuo voi toimia. Missään ei ole mainintaa että luokasta generoidaan datacontract automaattisesti kaikilla membereillä. jos toimintaperiaate tosiaan on noin, ei periaatteessa datacontracteja tarvitsi enää edes luoda jos kaikki serialisoituisi automaattisesti suoraan datacontractiksi, ilman määrittävää attribuuttia ja täten esim. WCF viestintä muuttuisi melkoisen oleellisesti. Eihän luokasta ole edes datacontractin xml:ää ilman attribuuttia.

Msdn:

Preparing Classes for Serialization or Deserialization

The DataContractSerializer is used in combination with the DataContractAttribute and DataMemberAttribute classes. To prepare a class for serialization, apply the DataContractAttribute to the class. For each member of the class that returns data that you want to serialize, apply the DataMemberAttribute.

En siis epäile etteikö toimi, vaan syvästi hämmästelen että miten se voi toimia datacontractin ajattelumallilla. Veikkaan että luokasta väännetään automaattisesti esim. [Serializable], jonka mukaan se luo XmlSerializer:lla scheman kaikilla attribuuteilla (POCO pohjalta). Molemmat schemat kuitenkin serialisoituu saman pohjan kautta ([ClassName] xmlns="http://schemas.datacontract.org/2004/07/SerializationSp1"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

qeijo [06.05.2013 13:18:22]

#

groovyb kirjoitti:

XmlSerializer toimii siten, että se serialisoi automaattisesti kaiken, DataContractSerializer taas ei tee niin, vaan serialisoi vain ne jotka on määritetty (ja että ylipäätään contract on olemassa).

.NET 3.5 SP1 lähtien jos DataContractSerializer:ille ei anneta DataContract:tia se toimii samalla periaatteella kuten XmlSerializer, miksi tämä on niin uskomatonta?

Toki tämä on hieman monimutkaisimmissa mappauksissa hieman kyseenalainen menettelytapa.

groovyb [06.05.2013 13:23:48]

#

Uskomatonta se on siten, että DataContractin ajattelumalliin (eikä muidenkaan serialisointiContractien maailmaan) ei kuulu kaikkien membereiden automaattista serialisointia. Eikä myöskään serialisointia ilman contractia. siten pidän sitä vähän erikoisena. toimiiko automaattinen kääntö contractiksi myös operation ja MessageContractien kanssa?

ja kuten sanoin, jos kerran toimii niin hyvä niin. En vain ymmärrä tätä logiikkaa kaikkien membereiden automaattisesta serialisoinnista ilman contractia, koska ei olisi esim. tarvittavaa xml schemaa saatavilla wcf kommunikaatioon (siellä ei kyllä tarvitsekkaan mitään erillisiä DataContractSerializereita käytellä).

Grez [06.05.2013 13:25:55]

#

qeijo kirjoitti:

Toki tämä on hieman monimutkaisimmissa mappauksissa hieman kyseenalainen menettelytapa.

Koodari päättää tarvitaanko DataContractia vai riittääkö jossain tapauksessa "kevyempi" lähestysmistapa.

qeijo [06.05.2013 13:26:31]

#

groovyb kirjoitti:

Uskomatonta se on siten, että DataContractin ajattelumalliin (eikä muidenkaan serialisointiContractien maailmaan) ei kuulu kaikkien membereiden automaattista serialisointia. Eikä myöskään serialisointia ilman contractia. siten pidän sitä vähän erikoisena.

Sehän on kontrakti. Kontrakti jossa serialisoidaan kaikki jäsenmuuttujat.

Grez kirjoitti:

qeijo kirjoitti:

Toki tämä on hieman monimutkaisimmissa mappauksissa hieman kyseenalainen menettelytapa.

Koodari päättää tarvitaanko DataContractia vai riittääkö jossain tapauksessa "kevyempi" lähestysmistapa.

Aivan.

groovyb [06.05.2013 13:39:18]

#

Niin ja kuten sanoin, se ei vaan kuulu Contractien malliin. Yhtä hyvin voisi käyttää XmlSerializeria niissä tapauksissa, joissa ei varsinaista Contractin tarvetta ole. Tässä on vaan taas mahdollistettu sellaista, mikä sotii alkuperäisen contract -ajattelumallin kanssa.

Grez [06.05.2013 13:42:43]

#

groovyb kirjoitti:

Yhtä hyvin voisi käyttää XmlSerializeria niissä tapauksissa, joissa ei varsinaista Contractin tarvetta ole.

Laitatko jonkun "yhtä hyvin" esimerkin Jsonin (de)serialisoimisesta käyttäen XmlSerializeria?

Olet oikeassa että sinänsä hieman turhaa nykyisin olla kaksi erillistä. Toisaalta olisi ikävää muuttaa vanhoja koodeja jos toinen poistettaisiin kokonaan.

groovyb [06.05.2013 13:54:54]

#

En ole tehnyt koskaan jsonin serialisointia XmlSerialisoinnin kautta, enkä yleisestikään windows applikaatiota jossa olisi tarvinnut jsonia edes stringistä Serialisoida luokaksi. Pointti oli lähinnä siinä että DataContractin serialisointia suoritetaan kuten XMLSerialisointia. Yhtä hyvin tuo luokka olisi voinut olla XmlJSONSerializer tjsp. Ehkä olen vaan jo vähän kalkkeutunut tästä kasvavasta geneerisyydestä ja automaatiosta, mutta mielestäni tässä on vain kaksi eroavaa asiaa nivottu yhteen huonolla tavalla.

pointti tässä on yleisestikin tuo DataContractSerializer, joka mahdollisti POCO luokkien serialisoinnin automaattisesti xml:ksi ilman erillistä contractia, jota tuo DataContractJSONSerializer:kin käyttää. Ja siinä mentiin mielestäni harhaan, koska POCO -luokkien serialisointi olisi mielestäni pitänyt suorittaa XmlSerializerilla, sen sijaan että siitä pystytään nyt luomaan DataContract kaikilla membereillä automaattisesti jälkikäteen ilman vaadittavia attribuutteja, ja näin sotkettu kaksi eroavaa asiaa yhteen.

*Edit*

Niin, ja ylipäätään veikkaan että tuo DataContractJSONSerializer luokka toimii
yksinkertaisesti siten, että JSON string splitataan palasiksi, ja verrataan membereitä serialisoidun luokan membereihin. mikäli homma bueno, asetetaan jsonin membereiden arvot luokan arvoihin, ja palautetaan luokka takaisin.

ja tämän olisi voinut yhtä hyvin suorittaa vaikka ottamalla tyyppi kohdeluokasta ja tarkistaa jsonin memberien vastaavuus saadun tyypin Type.GetMembers():llä. ilman että olisi tarvinnut serialisoida alkuunkaan DataContractin kautta. Tämän jälkeen jos memberit on ok, luodaan instanssi kohdeluokasta johon Jsonista saadut arvot lyödään oikeisiin membereihin, ja palautetaan luokka (jos kyseinen serialisoija palauttaa esim <T>:n, tai objektina joka koodissa sitten castataan itse takaisin haluttuun kohdeluokkaan.

qeijo [06.05.2013 14:27:53]

#

groovyb: Toteutustapoja on moneen lähtöön. Olen samaa mieltä kanssasi että DataContractJsonSerializerin käyttö ilman varsinaista kontraktia on hieman hölmöä, ja myös se että se on ylipäätään mahdollista käyttää ilman kontraktia on myös hölmöä.

Tässä nyt kuitenkin oli vain tarkoitus tuoda tällainen luokka esille, esimerkkini oli, ehkä näin jälkeenpäin ajateltuna huono. Olisin pitänyt olla tarkempi, en ajatellut asiaa, pyydän anteeksi.

Grez [06.05.2013 14:47:06]

#

Minusta se luokka joka sille annetaan on kuitenkin yksinkertainen sopimus (contract), joten mielestäni se ei ole lainkaan hölmöä.

Siis täysin sopimukseton deserializerhan pullauttaisi ulos dynaamisen objektin.

Nyt vaan on mahdollista tehdä yksinkertainen sopimus vähemmällä määrällä koodia.

Tokihan oltaisiin voitu tehdä myös systeemi että luokka täytyisi määritellä datacontracticsi ja sille määriteltäisiin joku [EveryMemberDataMember] parametri, mutta mielestäni nyt tarjolla oleva vaihtoehto on enemmän KISS.

groovyb [06.05.2013 16:10:51]

#

http://stackoverflow.com/questions/4836683/wcf-datacontract:

Since a lot of programmers were overwhelmed with the [DataContract] and [DataMember] attributes, with .NET 3.5 SP1, Microsoft made the data contract serializer handle all classes - even without any of those attributes - much like the old XML serializer.

So as of .NET 3.5 SP1, you don't have to add data contract or data member attributes anymore - if you don't then the data contract serializer will serialize all public properties on your class, just like the XML serializer would.

HOWEVER: not adding those attributes, you loose a lot of capabilities: – –

eli kyseessä ei ole edes täysiverinen datacontract, vaan jotain sinneppäin. Tämä on vielä huonompi ja tähän kun lisätään vielä se, että luokan syntaksista ei erotu että käytetäänkö sitä DataContractina vai ei.

Grez [06.05.2013 16:38:27]

#

Itse en pidä valinnanvapautta huonona asiana enkä myöskään sitä ettei väkisin ole tehty kahta erillistä luokkaa käytännössä hyvin saman asian tekemiseen.

En ihan ymmärrä tuota ongelmaa "ettei näy syntaksista". Onko yhteenlaskussakin ongelma kun ei näy syntaksista onko siinä nyt kokonaisluvut vai liukuluvut menossa?

Jos se nyt noin kovasti ärsyttää, niin voithan aina periyttää siitä erilliset luokat joista toinen hyväksyy vain täyden datacontractin ja toinen paljaan luokan. Tai käyttää vanhempaa .NETiä niin ei tarvitse kärsiä muistakaan uusien versioiden ominaisuuksista, joiden voisin kuvitella ärsyttävän ihan vastaavasti, kuten Dynamic.

groovyb [06.05.2013 17:13:37]

#

ärsyttää lähinnä se että DataContracteja sotketaan normaaleihin POCO -luokkiin.
Kun koodia selaa, niin näkee heti luokat joita on tarkoitus DataContracteina käyttää, koska koodia selaamalla silmään sattuu nuo kyseiset attribuutit. eipä tartte arvailla eikä vastaanottavasta päästä käydä tutkimassa mitkä luokat on tarkoitettu contracteiksi.

tässä pikainen WinForms esimerkki json parsimisesta ilman yllämainittua datacontract -serialisointia (kun kerran tuossa ylempänä aloin selittelemään että miten voitaisiin tehdä):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace jsonserializer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string JSON = "{\"worker_name\":\"Einari\",\"hash_rate\":21, \"total_shares\":1236}";
            Worker worker = new Worker();
            try
            {
               worker = JSONToClass<Worker>(JSON, worker);
            }
            catch(ArgumentException ex)
            {
               MessageBox.Show(ex.ToString());
            }
            MessageBox.Show("Done");
        }
        private T JSONToClass<T>(string json, object obj) where T: class
        {
            string[] JSONValues = json.Split(new string[] { "{","}",","}, StringSplitOptions.RemoveEmptyEntries);
            Type objType = obj.GetType();
            System.Reflection.PropertyInfo[] props = objType.GetProperties();
            bool AllOk = true;
            for (int i = 0; i < JSONValues.Length; i++)
            {
                bool Found = false;
                string[] JsonMemberInfo = JSONValues[i].Split(new string[] { " ", ":","\"" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (System.Reflection.PropertyInfo PI in props)
                {

                    if (JsonMemberInfo[0] == PI.Name)
                        Found = true;
                }

                if(!Found)
                    AllOk = false;
            }
            if (!AllOk)
                throw new ArgumentException("Cannot parse to class");
            else
            {
                var NewItem = (T)obj;
                foreach(System.Reflection.PropertyInfo p in props)
                {
                    foreach (string s in JSONValues)
                    {
                        string[] jsonproperty = s.Split(new string[] { " ", ":", "\"" }, StringSplitOptions.RemoveEmptyEntries);
                        if(p.Name == jsonproperty[0])
                        {
                            p.SetValue(NewItem,jsonproperty[1],null);
                        }
                    }

                }
                return (T)NewItem;

            }

        }
    }

    public class Worker
    {
        public string worker_name{ get;set;}
        public string hash_rate { get; set; }
        public string total_shares { get; set; }
    }
}

Grez [06.05.2013 17:23:21]

#

Musta näyttäis nopeasti katsoen että toi kosahtaa heti jos vaikka jossain merkkijonoarvossa on kaksoispiste. Enkä ymmärrä mikä pointti tossa on tehdä itse jos frameworkissa on valmis toiminnallisuus. Kyllähän lähes kaiken siellä olevan voi kirjoittaa itse jos tykkää.

Sen havaitsinkin että ärsyttää, mutta vieläkään en ymmärrä että miksi se niin kovasti ärsyttää. *

Siis voishan tuon tehdä niin, että vaikka ei tarvitsisi niitä datacontractin ominaisuuksia, joita ei POCO-luokkaa käyttämällä saa, niin olisi silti pakko lisätä ne datacontract -rimpsut. En vaan ymmärrä miksi sua ärsyttää että sellaista täysin turhaa työtä ei pakoteta tekemään.

* Edit: Näköjään muokkaist tuonne vähän perusteluita lisää.

Tietenkin joissain erikoistapauksissa joissa dokumentaatio on heikkoa niin voisi olla "kiva" että jostain näkee suoraan mitä käytetään. Tilannehan ei kuitenkaan muuttuisi mitenkään, vaikka käytettäisiin jotain muuta JSON (de)serialisointiluokkaa. Mielestäni oikea ratkaisu on se, että järjestelmien välinen rajapinta on asianmukaisesti dokumentoitu, jolloin ne käytetyt sopimukset näkee sieltä.

groovyb [06.05.2013 17:26:21]

#

koska ei ole turhaa työtä, eikä mitään väärää siinä, että pitäydytään tietyissä säännöissä. Saatika että tuo DataContract joka automaattisesti muodostetaan on vain osittain DataContract, eli siitä ei saada edes sitä kokonaishyötyä. Se on vain ja ainoastaan Dirty Hack, koska ihmiset eivät vaivautuneet oppimaan attribuuttien käyttöä.

tuon esimerkkini tarkoitus ei pitänytkään olla täysivoimainen parseri, vaan esimerkki toteutuksesta.

Grez [06.05.2013 17:32:48]

#

Mulla vaan hukkuu yhä vahvasti että mikä ko. esimerkin tarkoitus on.

Jos sen tarkoitus oli esittää että ilmankin valmista deserialisointikirjastoa on "helppo" hoitaa deserialisointi, niin mielestäni esimerkki epäonnistui, koska se ei selvästikään hoida asiaa kunnolla tai jos haluttaisiin että se hoidettaisiin kunnolla, niin se ei olisi noin helppo. Ja edelleen, vaikka toteutus olisikin noin helppo, niin näen helpommaksi käyttää valmista kirjastoa, jossa sudenkuopat on valmiiksi mietitty.

Lisäksi frameworkiin sisältyvän käyttö tarjoaa vähemmän ylläpidettävää koodia ja kaikkea muuta hyvää.

Jotenkin kaiken kaikkiaan tästä tulee sellainen kuva, että sun mielestä vaan on väärin että koodaajat joutuu kirjoittamaan vähemmän koodia uusissa versioissa. Kukaanhan ei toki kiellä edelleen kirjoittamasta yhtä paljon kuin ennenkin. Ja projektissa voidaan varmastikin sopia käytännöt.

Ymmärtäisin tosi hyvin närkästyksesi jos uudessa versiossa olisi kielletty käyttämästä Datacontracteja.

groovyb [06.05.2013 17:39:58]

#

ideana esimerkissä ei ollut se, että jokainen kirjoittakoon oman deserialisoijansa. Ideana oli se, että tässäkin tapauksessa koko serialisointi on tarpeeton (koska ei ole mikään pakko muuntaa JSON:ia ja luokkaa xml schemaksi ja verrata keskenään mätsääkö memberit tai propertyt). ja .NET:llä ei natiivina ole muuta tapaa muuntaa JSON:ia luokaksi kuin DataContractJSONSerializerin avulla.
Tietenkään itse parsiminen ei ole noin yksinkertainen, koska serialisoitava voi sisältää vaikka listojen sisällä olevia listoja jotka sisältää luokkia periytettynä muista luokista yms, mikä näyttääkin jo melkoiselta härpäkkeeltä JSON stringinä.

koko DataContractSerializer kaatuu siihen, että palautunut kilke ei ole edes DataContract, vaan jotain sinneppäin, jos attribuutit puuttuu.

Joko kilkkeen tulisi olla oikea DataContract, tai sitten ilman attribuutteja ei saisi DataContractia POCO:sta muodostaa. Se on vain Hack. ja niitä en tue.

Grez [06.05.2013 17:43:59]

#

Eli siis jos MS olisi tehnyt toiminnaltaan identtisen JSONSerializerin sinne ja tuo DataContract-alkuinen vaatisi edelleen (täydellisen) DataContractin, niin olisit iloinen ja tyytyväinen?

groovyb [06.05.2013 17:46:24]

#

Olisin tyytyväinen jos DataContractia ei voisi muodostaa luokasta josta attribuutit puuttuu. Tämä ei varsinaisesti JSONiin liity, vaan kyseisen JSONserialisointiluokan käyttämästä DataContractSerializerista, joka mahdollistaa nuo epämääräiset muka-Contractit.

Grez [06.05.2013 17:55:29]

#

No eikö tämä sitten täyttyisi jos olisi tehty kuten tuossa yllä ehdotin, että contractserializerit olisi erikseen ja contractlessserializerit erikseen?

Mitään kuvaamiasi "haittojahan" se ei toki poistaisi, mutta ei olisi "hack".

groovyb [06.05.2013 18:07:02]

#

Tottakai poistuisi, mutta näinhän asia ei nyt ole ehdotuksestasi huolimatta. Ei se närkästystä poista vaikka korvaavia ehdotuksia satelisikin.

Grez [06.05.2013 18:14:12]

#

Siis esimerkiksi luokkia katselemalla et siinäkään tapauksessa tietäisi mitkä niistä mahdollisesti serialisoidaan ja mitkä ei. En nyt muista olitko maininnut joitain muita konkreettisia haittoja.

groovyb [06.05.2013 18:33:57]

#

Katso tuosta yläpuolelta, stackoverflow:n lainauksesta. Ja tottakai näkisin luokasta jos olisi yksi attribuutti, vaikka [DataContractIncludeAll] tjsp.

Grez [06.05.2013 18:46:56]

#

No ei siellä stackoverflown viesteistä löytynyt mitään haittoja mainittuna. Ainoastaan kerrottiin mitä Datacontractin ominaisuuksia ei ole käytettävissä, jos päättää olla käyttämättä Datacontract määritteitä.

Et nyt ilmeisesti ymmärtänyt mitä kysyin. Sanoit, että että sinua ärsyttää että datacontractserializeria voi nykyään käyttää ilman datacontractia, koska se on "hack".

Kysyin, että olisitko sitten tyytyväinen jos datacontractserializer vaatisi edelleen datacontractin ja rinnalle olisi tehty "genericserializer" tms. Silloinhan kyseessä ei olisi hack.

Jos niin olisi tehty niin et edelleenkään pystyisi näkemään sieltä luokista että mitä mahdollisesti serialisoidaan ja mitä ei, kun joku voisi käyttää tuota genericserializeria.

Toki voisitte projektissa sopia, että genericserializeria ei käytetä, mutta nähdäkseni yhtä hyvin voi sopia että kaikille serialisoitaville luokille tehdään datacontract -määrittelyt.

groovyb [06.05.2013 21:03:34]

#

No onhan se nyt selvä haitta jos ominaisuuksia ei ole käytettävissä. Se on haitta kun kyseistä ominaisuutta tarvitsee.

MSDN:n blogit osasi myös kertoa muista rajoitteista, kuten siitä että constructor ei saa sisältää parametreja kun käytetään inferred datacontracts:ia (eli datacontract joka luodaan ilman attribuutteja). Ja näemmä WCF Standardi itsekin suosittelee pysyttelemään niistä erossa. En nyt käsitä miksi sitä pitää suosia, vaikka se onkin mahdollista. Mahdollista on myös moni muu huono tapa koodata, ja en käsitä miksi huonoja koodaustapoja ylipäätään pitää lähteä lobbaamaan vain siksi että ne ovat mahdollisia. Jo se pistää vähän ärsyttämään että inferred DataContracts:it ovat jääneet ilman mainintaa msdn:ssä. Se tietysti tarkoittaa että microsoft ei itse niiden käyttöä mainosta, mutta myös samalla sitä että on vaikea löytää tietoa niiden aiheuttamista rajoitteista ja muista mahdollisista käyttöongelmista.

Koodin vähenevän määrän otan mieluusti vastaan, kunhan sitä ei tehdä minkään toisen asian kustannuksella. Ja tuskinpa sinäkään huonoja tapoja lähdet mieluusti mainostamaan pelkästään sen vuoksi että se on mahdollista. Aina on tietysti tilanteita, joissa voi jonkun tilanteen pakottamana poikkeamaan hyvistä tavoista, mutta ei niitä ensisijaisesti varmaan ketään suosi pelkästään siksi että säästää pari riviä koodia.

GenericSerializer jo on Grez, se on XmlSerializer joka osaa ihan nätisti serialisoida ilman liitosta wcf:ään.

Grez [06.05.2013 22:28:41]

#

No siis nyt tarjottiin mahdollisuus tehdä joitain asioita helpommin niille, jotka ei tarvitse kaikkia niitä ominaisuuksia. Kukaan ei nähdäkseni ole kannustanut huonoon koodiin. Mielestäni juuri tässä ketjussa esitetty tapaus on sellainen, jossa Datacontract ei tuo sanottavaa lisäarvoa.

En nyt lähde syntyjä syviä selvittelemään, mutta jotenkin tuli sellainen käsitys että tuo Datacontract tehtiin vapaaehtoiseksi juuri noiden muiden kuin xml:n takia, jotka jakaa datacontractserialiserin. Eli näiden osalta ei välttämättä ole paljon iloa siitä XmlSerializerista.

Tavallaan olen samaa mieltä siitä, että on hienoa jos framework pystyy kannustamaan tekemään hyvää koodia jopa estämällä huonon koodin. Mutta olen myös realisti siinä suhteessa että joustavuuden ja valinnanvapauden mahdollistamiseksi kaikkea huonoa ei voi estää. On myös jossain määrin koodarin vastuulla tehdä järkeviä valintoja.

Rox [07.05.2013 17:50:38]

#

Unohdin salasanani, joten tein toisen tunnuksen.. (Mod. yhdisti tunnuksesi. Lisää profiiliin sähköpostiosoite, niin vältyt jatkossa ongelmilta.)

Vastauksia on tullut kiitettävästi mutta rehellisesti sanoen en ymmärtänyt noista datacontracteista yms yhtään mitään, joten jos joku viittis näyttää jonkun hyvän esimerkin tolle mitä kysyin ekassa postissa.. VB.netillä jos mahdollista. Mahdollisimman helppo esimerkki jos joku vain jaksaa kuluttaa aikaansa sen verran :)

Grez [07.05.2013 19:57:35]

#

Tuossa qeijon ekassa viestissä on hyvin yksinkertainen esimerkki.

C# syntaksin saa muutettua VB.Net sytanksiksi monellakin netistä löytyvällä konvertterilla, esim developerfusionin käännin tuotti tällaisen

Public Class Workers
	Public worker_name As String, hash_rate As String
	Public total_shares As Integer
End Class

Private json = "{""worker_name"":""Einari"",""hash_rate"":21, ""total_shares"":1236}" 'hae verkon kautta..
Private ms As New MemoryStream(Encoding.UTF8.GetBytes(json))
Private jsonser As New DataContractJsonSerializer(GetType(Workers))

Private worker As Workers = TryCast(jsonser.ReadObject(ms), Workers)

'worker.worker_name;
'worker.hash_rate;
'worker.total_shares;

Rox [14.05.2013 15:17:10]

#

Hmmmh..:\ Oisko liikaa pyydetty jos joku vois antaa valmiin koodin? Tiedän että seuraavalla koodilla saan ladattua koko höskän, mutta miten yhdistän sen tuohon ylläolevaan?

Imports System.Net
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim wc As WebClient = New WebClient
        Dim osote As String = "https://sivu.com/api/123"
        Label1.Text = wc.DownloadString(osote)
    End Sub
End Class

neau33 [14.05.2013 18:03:25]

#

Moi Rox!

tässä koko paska...

Imports System.Net
Imports System.Collections.Generic
Imports System.Web.Script.Serialization 'referenssi: System.Web.Extensions

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim url As String = "https://sivu.com/api/123"
        Dim json As String = String.Empty

        Using client As New WebClient
                Try
                        json = client.DownloadString(url)
                Catch ex As Exception
                        MsgBox(ex.Message)
                        Exit Sub
                End Try
        End Using

        Dim pos As Integer
        pos = json.IndexOf(Chr(34) + "worker_name" + Chr(34))
        json = json.Substring(pos -1 ,Len(json) - pos)
        pos = json.IndexOf("}")
        json = "{" + json.Substring(0, pos + 1)

        Dim jss As New JavaScriptSerializer
        Dim dict As Dictionary(Of String, String) = _
        jss.Deserialize(Of Dictionary(Of String, String))(json)

        For Each item As KeyValuePair(Of String, String) In dict
            Select Case item.Key
                Case "worker_name"
                    Label1.Text = item.Value
                Case "hash_rate"
                    Label2.Text = item.Value
                Case "total_shares"
                    Label3.Text = item.Value
            End Select
        Next

    End Sub

End Class

Rox [14.05.2013 19:59:16]

#

Kiitos! Mutta... Jostain syystä en löytänyt referenssiä tuolle System.Web.Extensionille. Koitin googletella mutten löytänyt mitään. Koitin .Net 2 ja 4 windows formilla. Koitan jatkaa etsiskelyä.. =>

neau33 [14.05.2013 20:22:39]

#

Moi taas Rox!

System.Web.Script.Serialization nimitilan luokka JavaScriptSerializer pitäisi löytyä ainakin .NET Framework 3.5 versiosta eteenpäin System.Web.Extensions.dll tiedostosta.

Rox [14.05.2013 20:35:14]

#

No vastauksessa ei kauaa mennyt! :) Mutta :\ Ennenkuin form1 aukesi, tuli tämmöinen virhe: http://i.imgur.com/YrecDgQ.png

Saako .Net 4.5 VS 2010:iin? Koitanpa googletella..=>

Grez [14.05.2013 20:38:25]

#

Jos Visual Studiota käytät, niin tarvitset version 2012:n käyttääksesi .Net 4.5

Rox [14.05.2013 20:45:11]

#

Grez kirjoitti:

Jos Visual Studiota käytät, niin tarvitset version 2012:n käyttääksesi .Net 4.5

Käytänpä hyvinkin.. Onko se kuinka paljon erilainen? / vaikeampikäyttöisempi? Täytyy harkita ostamista. Mistäköhän tämä virhe johtuu? http://i.imgur.com/YrecDgQ.png

neau33 [14.05.2013 23:34:19]

#

Moi taas Rox!

Mitä ilmeisimmin parsittava JSON data ei ole validia! Voit testata sivun datan esim. täällä

groovyb [14.05.2013 23:41:16]

#

Rox kirjoitti:

Mistäköhän tämä virhe johtuu? http://i.imgur.com/YrecDgQ.png

Siitä, että tuo JSONToClass demofunktio jonka tein, ei näemmä pysty JSON:iasi parsimaan. ilmeisesti tuo nean käännöksen delimiter """" ei toimi vastaavasti kuin "\"", joka alkuperäisestä esimerkistäni löytyy. Nean esimerkin pitäisi kyllä toimia ihan yhtä hyvin.

toinen vaihtoehto on että tuo esimerkkini funktio ei pysty jsoniasi purkamaan. Edellytys toimimiselle on, että Jsonin objektisi propertynimet tulee vastata luokkasi propertynimiä.

saatika, että alkuperäisessä json stringissäsi mm. hash_rate esiintyy kaksi kertaa. Tuo demoesimerkki ei ymmärrä erotella eri json "luokkia" toisistaan, ja esimerkiksi vertaa sitä kohdeluokan nimeen. ja niinpoispäin. Tässä tapauksessa hash_rate asettuu worker olioon oikein, koska se on json stringissä user -osion jälkeen. mutta se on ihan puhdas munkki että se sattuu sen kanssa toimimaan, koska en heittänyt breikkiä looppeihin jolla jsonin propertyä verrataan luokan propertynimeen ja täten viimeisen hash_raten arvo tallentuu worker -olioon.

neau33 [15.05.2013 00:50:40]

#

Moi taas Rox!

fuck the serialization...

Imports System.Net

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim url As String = "https://sivu.com/api/123"
        Dim json As String = String.Empty

        Using client As New WebClient
            Try
                json = client.DownloadString(url)
            Catch ex As Exception
                MsgBox(ex.Message)
                Exit Sub
            End Try
        End Using

        json = json.Replace(vbLf.ToCharArray,"")
        json = json.Replace(Chr(34),"")

        Dim pos As Integer = InStr(json,"worker_name")

        json = json.Substring(pos -1, Len(json)- pos)
        pos = json.IndexOf("}")
        json = json.Substring(0, pos)

        Dim jsonArray() As String =  json.Split(",".ToCharArray)
        Dim temp() As String

        For i As Integer = 0 To jsonArray.GetUpperBound(0)

            temp = jsonArray(i).Split(":".ToCharArray)

            If jsonArray(i).IndexOf("worker_name") > -1 Then
                Label1.Text =  temp(1).Trim
            ElseIf jsonArray(i).IndexOf("hash_rate") > -1 Then
                Label2.Text =  temp(1).Trim
            ElseIf jsonArray(i).IndexOf("total_shares") > -1 Then
                Label3.Text =  temp(1).Trim
            End If

            Erase temp

        Next

        Erase jsonArray

    End Sub

End Class

neau33 [15.05.2013 10:29:23]

#

Moi taas Rox!

mikäli kuitenkin päädyt käyttämään serialisointia niin qeijon esimerkkiin perustuen...

Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Runtime.Serialization.Json

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim url As String = "https://sivu.com/api/123"
        Dim json As String = String.Empty

        Using client As New WebClient
            Try
                json = client.DownloadString(url)
            Catch ex As Exception
                MsgBox(ex.Message)
                Exit Sub
            End Try
        End Using

        If json.Contains(Chr(34) + "worker_name" + Chr(34)) Then

            Dim pos As Integer

            pos = json.IndexOf(Chr(34) + "worker_name" + Chr(34))
            json = json.Substring(pos -1, json.Length  - pos)
            pos = json.IndexOf("}")
            json = "{" + json.Substring(0, pos + 1)

            Dim ms As New MemoryStream(Encoding.UTF8.GetBytes(json))
            Dim jsonser As New DataContractJsonSerializer(GetType(Workers))
            Dim worker As Workers = CType(jsonser.ReadObject(ms), Workers)

            label1.Text = worker.worker_name
            label2.Text = worker.hash_rate
            Label3.Text = worker.total_shares

        Else
            MsgBox("JSON data does not contain Key: worker_name")
        End If
    End Sub

End Class

Public Class Workers
    Public worker_name As String, _
    hash_rate As String, _
    total_shares As String
End Class

Rox [15.05.2013 16:08:39]

#

Testasin tätä ja toimii täydellisesti!

Eli voin lisäillä tonne vaikka esim:

ElseIf jsonArray(i).IndexOf("payouts") > -1 Then

Kiitos!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta