Einführung in JavaScript Object Notation (JSON) in JavaScript und .NET

 

Atif Aziz, Scott Mitchell

Februar 2007

Gilt für:
JSON
Ajax

Zusammenfassung: In diesem Artikel wird JavaScript Object Notation (JSON) behandelt, ein offenes und textbasiertes Format für den Datenaustausch, das ein standardisiertes Datenaustauschformat verwendet, das besser für Ajax-Webanwendungen geeignet ist. (22 gedruckte Seiten)

Inhalt

Einführung
Erläuterung von literalen Notationen in JavaScript
Vergleich von JSON und XML
Erstellen und Analysieren von JSON-Nachrichten mit JavaScript
Arbeiten mit JSON in .NET Framework
Zusammenfassung
Verweise

Laden Sie den Quellcode für diesen Artikel herunter.

Einführung

Beim Entwerfen einer Anwendung, die mit einem Remotecomputer kommuniziert, müssen ein Datenformat und Austauschprotokoll ausgewählt werden. Es gibt eine Vielzahl offener, standardisierter Optionen, und eine ideale Auswahl hängt von den Anwendungsanforderungen und der bereits existierenden Funktionalität ab. So formatieren z. B. SOAP-basierte Webdienste die Daten in einer XML-Nutzlast, die in einen SOAP-Umschlag integriert ist.

Obwohl XML gut für viele Anwendungsszenarios geeignet ist, hat es doch einige Nachteile, durch die es keine ideale Lösung für andere Anwendungen darstellt. Dies ist z. B. der Fall bei Ajax-Webanwendungen, für die XML nicht ideal ist. Ajax ist ein Verfahren zum Erstellen interaktiver Webanwendungen mit einer forschen Benutzerfreundlichkeit durch die Verwendung von einfachen Out-of-Band-Aufrufen des Webservers statt von ganzseitigen Postbacks. Diese asynchronen Aufrufe werden auf dem Client mit JavaScript initiiert und beinhalten das Formatieren von Daten, Senden der Daten an einen Webserver und Analysieren und Arbeiten mit den zurückgesendeten Daten. Während die meisten Browser XML erstellen, senden und analysieren können, bietet JavaScript Object Notation (JSON) ein standardisiertes Datenaustauschformat, das besser für Ajax-Webanwendungen geeignet ist.

JSON ist ein offenes, textbasiertes Datenaustauschformat (siehe RFC 4627). Wie XML ist es für Menschen lesbar, plattformunabhängig und bietet zahlreiche Implementierungsmöglichkeiten. Daten, die nach dem JSON-Standard formatiert werden, sind einfach und können von JavaScript-Implementierungen leicht analysiert werden und stellen daher ein ideales Datenaustauschformat für Ajax-Webanwendungen dar. Da es sich bei JSON vorwiegend um ein Datenformat handelt, ist JSON nicht auf Ajax-Webanwendungen beschränkt, sondern kann in nahezu allen Situationen verwendet werden, in denen Anwendungen strukturierte Informationen als Text austauschen oder speichern müssen.

In diesem Artikel werden der JSON-Standard und seine Beziehung zu JavaScript untersucht und mit XML verglichen. Jayrock, eine Open-Source-JSON-Implementierung für.NET, wird beschrieben und Beispiele für die Erstellung und Analyse von JSON-Nachrichten werden in JavaScript und C# genannt.

Erläuterung von literalen Notationen in JavaScript

Literale werden in Programmiersprachen verwendet, um feste Werte literal auszudrücken, wie z. B. der konstante Ganzzahlwert von 4 oder die Zeichenfolge „Hallo Welt“. Literale können in den meisten Sprachen verwendet werden, die Ausdrücke zulassen, wie z. B. als Teil einer Bedingung in einer Steueranweisung, als Eingabeparameter beim Aufrufen einer Funktion, in variablen Zuweisungen, etc. So initiiert das folgende eispiel im Code C# und Visual Basic die Variable x mit dem konstanten Ganzzahlwert von 42.

int x = 42;  // C#
Dim x As Integer = 42  ' Visual Basic

Verschiedene Programmiersprachen lassen Literale unterschiedlicher Typen zu. Die meisten Programmiersprachen unterstützen mindestens Literale für Skalartypen wie Ganzzahlen, Gleitkommazahlen, Zeichenfolgen und boolesche Werte. Das Interessante an JavaScript ist, dass neben Skalartypen auch Literale für strukturierte Typen wie Arrays und Objekte unterstützt. Durch dieses Feature ist eine knappe Syntax für das Erstellen und Initialisieren von Arrays und Objekten nach Bedarf möglich.

Array-Literale in JavaScript sind aus mindestens null Ausdrücken zusammengesetzt, wobei jeder Ausdruck ein Element des Arrays darstellt. Die Arrayelemente werden in eckige Klammern ([]) gesetzt und durch Kommas getrennt. Das folgende Beispiel definiert ein Array literal mit sieben Zeichenfolgenelementen, die die Namen der sieben Kontinente enthalten:

var continents = ["Europe", "Asia", "Australia", "Antarctica", "North
 America", "South America", "Africa"];
alert(continents[0] + " is one of the " + continents.length + "
 continents.");

Vergleichen Sie dies nun mit der Erstellung und Initialisierung eines Arrays in JavaScript ohne literale Notation:

var continents = new Array();
continents[0] = "Europe";
continents[1] = "Asia";
continents[2] = "Australia";
continents[3] = "Antarctica";
continents[4] = "North America";
continents[5] = "South America";
continents[6] = "Africa";

Ein Objektliteral definiert die Mitglieder eines Objekts und dessen Werte. Die Liste der Objektmitglieder und deren Werte werden in geschweifte Klammern ({}) gesetzt und die Mitglieder durch Kommas getrennt. Innerhalb eines Mitglieds werden der Name und der Wert durch einen Doppelpunkt (:) getrennt. Im folgenden Beispiel wird ein Objekt erstellt und mit drei Mitgliedern mit den Namen Address, City und PostalCode mit den entsprechenden Werten „123 Anywhere St.“, „Springfield“ und „99999“ initialisiert.

var mailingAddress = { 
     "Address"    :   "123 Anywhere St.", 
     "City"       :   "Springfield", 
     "PostalCode" :   99999
};
alert("The package will be shipped to postal code " +
 mailingAddress.PostalCode);

Die bisherigen Beispiele haben die Verwendung von Zeichenfolgen- und numerischen Literalen in Array- und Objektliteralen gezeigt. Sie können auch ein vollständiges Diagramm ausdrücken, indem die Notation rekursiv verwendet wird und Arrayelemente und Objektmitgliederwerte selbst Objekt- und Arrayliterale verwenden können. So zeigt der folgende Ausschnitt z. B. ein Objekt, das über ein Array als Mitglied (PhoneNumbers) verfügt, wobei das Array aus einer Liste an Objekten zusammengesetzt ist.

  
    var contact = {
     "Name": "John Doe",
     "PermissionToCall": true,
     "PhoneNumbers": [ 
       {
           "Location": "Home",
           "Number": "555-555-1234"
       },
       {
           "Location": "Work",
           "Number": "555-555-9999 Ext. 123"
       }
     ]
};
if (contact.PermissionToCall)
{
  alert("Call " + contact.Name + " at " + contact.PhoneNumbers[0].Number);
}
  

Hinweis   Eine ausführlichere Beschreibung der Unterstützung für Literale in JavaScript finden Sie im Core JavaScript 1.5-Handbuch im Abschnitt zu Literalen.

Von JavaScript-Literalen zu JSON

JSON ist ein Datenaustauschformat, das von einer Teilmenge der literalen Objektnotation in JavaScript erstellt wurde. Während die von JavaScript unterstützte Syntax für literale Werte sehr flexibel ist, muss beachtet werden, dass JSON wesentlich strengeren Regeln folgt. Entsprechend des JSON-Standards muss es sich z. B. bei dem Namen eines Objektmitglieds um eine gültige JSON-Zeichenfolge handeln. Eine Zeichenfolge in JSON muss in Anführungszeichen gesetzt werden. JavaScript lässt hingegen die Trennung von Objektmitgliedernamen durch Anführungszeichen oder Apostrophe oder das Weglassen von Trennzeichen zu, sofern der Mitgliedername nicht mit einem reservierten JavaScript-Schlüsselwort in Konflikt steht. Ebenso ist ein Arrayelement oder ein Objektmitgliedwert in JSON auf einen sehr begrenzten Satz limitiert. In JavaScript können Arrayelemente und Objektmitgliederwerte sich auf mehr oder weniger beliebige gültige JavaScript-Ausdrücke beziehen, einschließlich von Funktionsaufrufen und Definitionen!

Der Charme von JSON liegt in seiner Einfachheit. Eine Nachricht, die im JSON-Standard formatiert ist, besteht aus einem einzigen, Top-Level-Objekt oder Array. Bei Arrayelementen und Objektwerten kann es sich um Objekte, Arrays, Zeichenfolgen, Zahlen, boolesche Werte (wahr und falsch) oder Null handeln. Genau dies ist kurz gesagt der JSON-Standard! Es ist wirklich so einfach. Eine formale Beschreibung des JSON-Standards finden Sie unter www.json.org oder RFC 4627.

Einer der Nachteile von JSON ist das Fehlen eines Datum-/Zeitliterals. Viele Benutzer sind enttäuscht, wenn Sie herausfinden, dass JSON dies nicht bietet. Eine einfache Erklärung (tröstlich oder nicht) ist, dass JavaScript auch nicht über ein Datum-/Zeitliteral verfügt: Die Unterstützung von Datum- und Zeitwerten in JavaScript wird lediglich über das Objekt Datum erreicht. Die meisten Anwendungen, die JSON als Datenformat verwenden, nutzen in der Regel eine Zeichenkette oder eine Zahl, um Datum- und Zeitwerte auszudrücken. Wenn eine Zeichenfolge verwendet wird, befindet sich diese in der Regel im Format ISO 8601. Wenn eine Zahl verwendet wird, handelt es sich hierbei in der Regel um die Anzahl an Millisekunden in koordinierter Weltzeit (Universal Coordinated Time, UTC), deren Anfang auf 24.00 Uhr des 1. Januar 1970 (UTC) festgelegt wurde. Hierbei handelt es sich wiederum um eine reine Konvention und nicht Teil des JSON-Standards. Wenn Sie Daten mit einer anderen Anwendung austauschen, müssen Sie deren Dokumentation prüfen, um herauszufinden, wie Datum- und Zeitwerte innerhalb eines JSON-Literals codiert sind. So verwendet z. B. ASP.NET AJAX von Microsoft keine der beschriebenen Konventionen. Stattdessen werden .NET DateTime-Werte als JSON-Zeichenfolge codiert, wobei der Inhalt der Zeichenfolge /Date(ticks)\/ ist, wobei ticks die Millisekunden seit Anfang der koordinierten Weltzeit darstellt. Dementsprechend wird der 29. November 1989, 4:55:30 in UTC als „\/Date(628318530718)\/“ codiert.

ASP.NET AJAX: Innerhalb der JSON-Datum- und Zeitzeichenfolge

Die AJAX JSON-Serialisierung in ASP.NEXT codiert eine DateTime-Instanz als eine JSON-Zeichenfolge. In den Vorabversionen hat ASP.NET AJAX das Format „@ticks@“ verwendet, wobei ticks die Anzahl der Millisekunden sit dem 1. Januar 1970 in UTC darstellt. Ein Datum und eine Zeit in UTC, wie z. B. 29. November 1989, 4:55:30, würde folgendermaßen ausgeschrieben werden: „@62831853071@“. Obwohl es sich um ein einfaches Format handelt, kann es nicht zwischen einem serialisierten Datum- und Zeitwert und einer Zeichenfolge unterscheiden, die wie ein serialisiertes Datum aussieht, aber nicht als solches deserialisiert wird. Daher hat das ASP.NET AJAX-Team eine Änderung für die endgültige Version vorgenommen, um das Problem mithilfe des Formats „\/Date(ticks)\/“ zu beheben.

Das neue Format verlässt sich auf einen kleinen Trick, um die Möglichkeit der Fehlinterpretationen zu verringern. In JSON kann ein Schrägstrich(/) in einer Zeichenfolge durch einen umgekehrten Schrägstrich (\) mit Escapezeichen versehen werden, obwohl dies nicht unbedingt erforderlich ist. Das ASP.NET AJAX-Team hat sich dies zu Nutze gemacht und den JavaScriptSerializer so geändert, dass eine DateTime-Instanz als Zeichenfolge „\/Date(ticks)\/“ geschrieben wird. Das Ersetzen der Schrägstriche für ein Escapezeichen ist nur oberflächlich, für den JavaScriptSerializer aber entscheidend. Nach JSON-Regeln ist "\/Date(ticks)\/" ist technisch äquivalent zu "/Date(ticks)/", der JavaScriptSerializer deserialisiert den ersten Ausdruck jedoch als DateTime und den zweiten als String. Die Chancen einer Zweideutigkeit sind daher deutlich geringer im Vergleich zum Format „@ticks@“ der Vorabversionen.

Vergleich von JSON und XML

Sowohl JSON als auch XML können zur Darstellung systemeigener Objekte im Speicher in einem textbasierten, von Menschen lesbaren Datenaustauschformat verwendet werden. Darüber hinaus sind beide Datenaustauschformate isomorph – liegt ein Text in einem Format vor, kann ein äquivalenter Text im anderen Format erzeugt werden. So können Sie z. B. beim Aufrufen von öffentlichen Webdiensten von Yahoo! über einen Abfragezeichenfolgeparameter angeben, ob die Antwort in XML oder JSON formatiert werden soll. Daher kommt es bei der Wahl eines Datenaustauschformats nicht einfach darauf an, was einem besser gefällt, sondern welches Format die Merkmale aufweist, die für eine spezifische Anwendung am besten geeignet sind. So basiert XML z. B. auf der Markierung von Dokumententext und eignet sich hierfür hervorragend (als gutes Beispiel dient hier XHTML). JSON basiert hingegen auf Programmiersprachentypen und -strukturen und stellt daher eine natürliche und leicht einsetzbare Zuordnung für den Austausch strukturierter Daten bereit. Zusätzlich zu diesen beiden wichtigen Unterscheidungsmerkmalen finden Sie einen Vergleich weiterer Unterschiede zwischen XML und JSON in der folgenden Tabelle.

Wichtige Unterscheidungsmerkmale zwischen XML und JSON

Merkmal XML JSON
Datentypen Stellt keine Angabe für Datentypen bereit. Hierbei muss sich auf das XML-Schema zum Hinzufügen von Typinformationen verlassen werden. Stellt Skalardatentypen bereit und die Möglichkeit, strukturierte Daten über Arrays und Objekte darzustellen.
Unterstützung für Arrays Arrays müssen durch Konventionen ausgedrückt werden, zum Beispiel durch die Verwendung eines äußeren Platzhalterelements, das den Inhalt des Arrays als inneres Element modelliert. In der Regel verwendet das äußere Element die Pluralform des Namens, der für das innere Element verwendet wird. Systemeigene Arrayunterstützung.
Unterstützung für Objekte Objekte müssen durch Konventionen dargestellt erden, häufig durch eine Kombination aus Attributen und Elementen. Systemeigene Objektunterstützung.
Null-Unterstützung Erfordert die Verwendung von xsi:nil für Elemente eines XML-Instanzdokumente sowie den Import des entsprechenden Namespace. Erkennt den Wert null intern.
Kommentare Systemeigene Unterstützung und in der Regel über APIs verfübar. Nicht unterstützt.
Namespaces Unterstützt Namespaces, wodurch das Risiko von Namenskonflikten bei einem Kombinieren von Dokumenten vermieden wird. Namespaces ermöglichen eine sichere Erweiterung vorhandener XML-basierter Standards. Kein Konzept für Namespaces. Namenskonflikte werden in der Regel durch die Verschachtelung von Objekten oder der Verwendung eines Präfixes in einem Objektmitgliednamen vermieden (dies wird in der Praxis bevorzugt).
Formatierungsentscheidungen Komplex. Hierbei ist die Entscheidung der Zuordnung von Anwendungstypen zu XML-Elementen und -Attributen schwieriger. Dies kann zu Auseinandersetzungen führen, ob ein Element-zentraler oder Attribut-zentraler Ansatz besser ist. Problemlos. Stellt eine wesentlich direktere Zuordnung für Anwendungsdaten bereit. Die einzige Ausnahme ist das Fehlen eines Datum-/Zeitliterals.
Größe Dokumente neigen dazu, sehr lang zu werden, besonders wenn ein Element-zentrischer Ansatz für die Formatierung verwendet wird. Die Syntax ist sehr knapp und gibt formatierten Text aus, bei dem der Großteil des Platzes durch die repräsentierten Daten eingenommen wird (und das mit Recht).
Analyse in JavaScript Erfordert eine XML-DOM-Implementierung und zusätzlichen Anwendungscode, um Text wieder JavaScript-Objekten zuzuordnen. Für die Analyse des Texts ist kein zusätzlicher Anwendungscode erforderlich; hierfür die JavaScript-Funktion eval verwendet werden.
Lernkurve Neigt in der Regel dazu, mehrere Technologien zusammen zu verwenden: XPath, XML-Schema, XSLT, XML-Namespaces, DOM usw. Sehr einfacher Technologienstapel, der Entwicklern bereits bekannt ist, die über Kenntnisse in JavaScript oder einer anderen dynamischen Programmiersprache verfügen.

Bei JSON handelt es sich um ein relativ neues Datenaustauschformat, das noch nicht die jahrelange Unterstützung von Herstellern und Benutzern genießt, die XML heutzutage zuteil wird (obwohl JSON schnell aufholt). Die folgende Tabelle zeigt den aktuellen Vergleich zwischen XML und JSON.

Unterschiedliche Unterstützung für XML und JSON

Support XML JSON
Tools Kann einen vielfältigen Satz an Tools verwenden, die von zahlreichen Herstellern verfügbar sind. Gute Unterstützung für Tools wie Editoren und Formatierer wird jedoch nur selten geboten.
Microsoft .NET Framework Sehr gute und ausgereifte Unterstützung seit Version 1.0 von .NET Framework. XML-Unterstützung ist als Teil der Basisklassenbibliothek (BCL) verfügbar. Für nicht verwaltete Umgebungen steht MSXML bereit. Bisher keine, außer einer anfänglichen Implementierung als Teil von ASP.NET AJAX.
Plattform und Sprache Parser und Formatierer sind für zahlreiche Plattformen und Sprachen verfübar (handelsübliche und Open-Source-Implementierungen). Parser und Formatierer sind bereits für zahlreiche Plattformen und Sprachen verfügbar. Zahlreiche Referenzen finden Sie unter json.org. Bei den meisten aktuellen Implementierungen handelt es sich um Open-Source-Projekte.
Integrierte Sprache Hersteller experimentieren derzeit mit literaler Unterstützung innerhalb der Sprachen. Weitere Informationen erhalten Sie unter Microsoft-LINQ-Projekt. Lediglich interne Unterstützung in JavaScript/ECMAScript.

Hinweis   Keine der Tabellen dient als umfassende Vergleichsliste. Es gibt weitere Blickwinkel, aus denen die beiden Datenformate verglichen werden können, die hier genannten wichtigen Punkte eignen sich jedoch als Grundlage, um einen ersten Einblick zu gewinnen.

Erstellen und Analysieren von JSON-Nachrichten mit JavaScript

Beim Verwenden JSON als Datenaustauschformat werden zwei übliche Tasks verwendet, um die interne und im Speicher vorhandene Repräsentation in die JSON-Textrepräsentation umzuwandeln, und umgekehrt. Zum Zeitpunkt der Verfassung dieses Dokuments bietet JavaScript keine internen Funktionen zum Erstellen von JSON-Text von einem gegebenen Objekt oder Array. Diese Methoden werden voraussichtlich in der vierten Version des ECMAScript-Standards in 2007 implementiert. Solange diese JSON-Formatierungsfunktionen nicht offiziell in JavaScript integriert und für häufig verwendete Anwendungen verfügbar sind, kann das Referenzimplementierungsskript verwendet werden, das unter http://www.json.org/json.js heruntergeladen werden kann.

In seiner aktuellen Iteration zum Zeitpunkt der Verfassung dieses Dokuments fügt das Skript json. js unter www.json.org die Funktionen toJSONString() zu Arrays, Zeichenfolgen, booleschen Werten, Objekten und anderen JavaScript-Typen hinzu. Die toJSONString()-Funktionen für skalare Typen (wie Zahlen und boolesche Werte) sind ziemlich einfach, da sie lediglich eine Zeichenfolgendarstellung des Instanzwerts zurückgeben müssen. Die toJSONString()-Funktion für den Typ boolescher Wert gibt z. B. die Zeichenfolge „true“ zurück, wenn der Wert wahr ist, und „false“, wenn dies nicht der Fall ist. Die toJSONString()-Funktionenfür Array- und Objekttypen sind interessanter. Für Array-Instanzen wird die toJSONString()-Funktion für jedes enthaltene Element nacheinander aufgerufen, wobei die Ergebnisse durch Kommas verkettet werden, um diese voneinander zu trennen. Die endgültige Ausgabe wird in eckige Klammern eingefügt. Ebenso werden für Objektinstanz die einzelnen Mitglieder aufgezählt und deren toJSONString()-Funktion aufgerufen. Der Mitgliedname und die JSON-Repräsentation des Werts werden in der Mitte mit einem Doppelpunkt verkettet; die Paare aus Mitgliedernamen und Wert werden durch Kommas getrennt und der gesamte Ausdruck in geschweifte Klammern gesetzt.

Ergebnis der toJSONString ()-Funktionen ist, dass jeder beliebige Typ in das eigene JSON-Format mit einem einzigen Funktionsaufruf konvertiert werden kann. Das folgende JavaScript erstellt ein Arrayobjekt und fügt absichtlich sieben Zeichenfolgeelemente über die ausführliche und nicht-literale Methode zu Anschauungszwecken hinzu. Daraufhin wird die JSON-Repräsentation der Arrays angezeigt:

// josn.js must be included prior to this point

var continents = new Array();
continents.push("Europe");
continents.push("Asia");
continents.push("Australia");
continents.push("Antarctica");
continents.push("North America");
continents.push("South America");
continents.push("Africa");

alert("The JSON representation of the continents array is: " +
 continents.toJSONString());

Abbildung 1: Die toJSONString()-Funktion gibt das Array im JSON-Standard formatiert aus.

Die Analyse von JSON-Text ist noch einfacher. Da es sich bei JSON lediglich um eine Teilmenge von JavaScript-Literalen handelt, kann es in einer Speicherdarstellung über die Funktion eval(expr) analysiert werden, wobei der JSON-Quelltext als JavaScript-Quellcode behandelt wird. Die eval-Funktion akzeptiert als Eingabe eine Zeichenfolge gültigen JavaScript-Codes und bewertet den Ausdruck. Daher ist folgende Codezeile ausreichend, um JSON-Text in eine interne Darstellung umzuwandeln:

var value = eval( "(" + jsonText + ")" );

Hinweis   Die zusätzlichen Klammern werden eingefügt, damit die Funktion eval die Quelleingabe bedingungslos als Ausdruck behandelt. Dies ist besonders für Objekte wichtig. Wenn Sie versuchen, eval mit einer Zeichenfolge aufzurufen, die JSON-Text enthält, z. B. die Zeichenfolge „{}“ (d. h. ein leeres Objekt), wird als analysiertes Ergebnis „nicht definiert“ zurückgegeben. Durch die Klammern wird der JavaScript-Parser gezwungen, die geschweiften Klammern auf der obersten Ebene als literale Notation für eine Objektinstanz zu interpretieren, im Gegensatz zu geschweiften Klammern, die einen Anweisungsblock definieren. Dieses Problem tritt jedoch nicht auf, wenn es sich bei dem Element der obersten Ebene um ein Array handelt, wie bei eval("[1,2,3]"). Zur Einheitlichkeit sollte JSON-Text vor dem Aufrufen von eval immer in Klammern gesetzt werden, um Unklarheiten bei der Interpretation der Quelle auszuschließen.

Bei der Auswertung literaler Notationen wird eine Instanz zurückgegeben, die der literalen Syntax entspricht, und zu value zugewiesen. Beachten Sie folgendes Beispiel, das die Funktion eval verwendet, um die literale Notation für ein Array zu analysieren und das Ergebnisarray der Variablen Continents zuordnet.

var arrayAsJSONText = '["Europe", "Asia", "Australia", "Antarctica",
 "North America", "South America", "Africa"]';
var continents = eval( arrayAsJSONText );
alert(continents[0] + " is one of the " + continents.length + "
 continents.");

In der Praxis stammt der ausgewertete JSON-Text aus einer externen Quelle und ist kein fest programmierter Code wie in diesem Beispiel.

Die Funktion eval bewertet jeden Ausdruck, der an sie weitergegeben wird. Eine unzuverlässige Quelle könnte daher möglicherweise gefährliches JavaScript enthalten, das zusammen mit der literalen Notation übergeben wird oder sogar in die Notation integriert ist, aus der die JSON-Daten bestehen. Bei nicht vertrauenswürdigen Quellen wird daher unbedingt empfohlen, den JSON-Text über die Funktion parseJSON() zu analysieren (in json.js zu finden):

// Requires json.js
var continents = arrayAsJSONText.parseJSON();

Die Funktion parseJSON() verwendet auch eval, vorausgesetzt die in arrayAsJSONText enthaltene Zeichenfolge entspricht dem JSON-Textstandard. Dies wird über die Verwendung eines raffinierten Tests mit regulärem Ausdruck erreicht.

Arbeiten mit JSON in .NET Framework

JSON-Text kann leicht von JavaScript-Code erstellt und analysiert werden, was ihn sehr beliebt macht. Wenn JSON jedoch in einer ASP.NET-Webanwendung verwendet wird, bietet lediglich der Browser Unterstützung für JavaScript, da der serverseitige Code in der Regel in Visual Basic oder C# geschrieben ist.

Die meisten Ajax-Bibliotheken, die für ASP.NET entworfen werden, unterstützen das programmgesteuerte Erstellen und Analysieren von JSON-Text. Daher wird für das Arbeiten mit JSON in einer .NET-Anwendung die Verwendung einer der folgenden Bibliotheken empfohlen. Es gibt zahlreiche Open-Source- und Drittanbieteroptionen, und Microsoft verfügt über eine eigene Ajax-Bibliothek: ASP.NET AJAX.

In diesem Artikel werden Beispiele vorgestellt, die Jayrockverwenden, eine Open-Source-Implementierung von JSON für Microsoft .NET Framework, die vom Mitautor Atif Aziz entwickelt wurde. Wir haben die Verwendung von Jayrock statt ASP.NET AJAX aus drei Gründen gewählt:

  • Jayrock ist eine Open-Source-Implementierung und kann daher nach Bedarf erweitert oder angepasst werden.
  • Jayrock kann in ASP.NET 1.x, 2.0 und Mono-Anwendungen verwendet werden, während ASP.NET AJAX lediglich für ASP.NET Version 2.0 verwendet werden kann.
  • Jayrock ist auf JSON und JSON-RPC beschränkt und dieser Artikel konzentriert sich auf JSON. Während ASP.NET AJAX eine gewisse Unterstützung für das Erstellen und Analysieren von JSON-Text bietet, ist das primäre Ziel, eine vielseitige Plattform für das Erstellen von End-to-End-Ajax-Webanwendungen in ASP.NET anzubieten. Die zusätzlichen Merkmale können hierbei ablenken, besonders wenn Sie sich vorwiegend auf JSON konzentrieren.

Das Arbeiten mit JSON in .NET unter Verwendung von Jayrock ähnelt dem Arbeiten mit XML und den Klassen XmlWriter, XmlReader und XmlSerializer in .NET Framework. Die Klassen JsonWriter, JsonReader, JsonTextWriter und JsonTextReader in Jayrock imitieren die Semantik der .NET Framework-Klassen XmlWriter, XmlReader, XmlTextWriter und XmlTextReader. Diese Klassen eignen sich für die Schnittstelle mit JSON auf einer niedrigen, datenstromorientierten Ebene. Durch die Verwendung dieser Klassen kann JSON-Text fragmentarisch über eine Reihe an Methodenaufrufen erstellt oder analysiert werden. So wird z. B. durch die Verwendung der JsonWriter-Klassenmethode WriteNumber(number) die entsprechende Zeichenfolgenrepräsentation von number entsprechend des JSON-Standards geschrieben. Die Klasse JsonConvert bietet Export- und Import-Methoden für die Konvertierung von .NET-Typen und JSON. Diese Methoden stellen eine ähnliche Funktionalität wie die XmlSerializer-Klassenmethoden Serialize und Deserialize bereit.

Erstellen von JSON-Text

Folgender Code zeigt die Verwendung der JsonTextWriter-Klasse zum Erstellen von JSON-Text für ein Zeichenfolgenarray an Kontinenten. Der JSON-Text wird an eine TextWriter-Instanz gesendet, die an den Konstruktor übergeben wird, der gleichzeitig den Ausgangsdatenstrom der Konsole in diesem Beispiel darstellt (in ASP.NET können Sie stattdessen Response.Output verwenden):

using (JsonTextWriter writer = JsonTextWriter(Console.Out))
{
    writer.WriteStartArray();
    writer.WriteString("Europe");
    writer.WriteString("Asia");
    writer.WriteString("Australia");
    writer.WriteString("Antarctica");
    writer.WriteString("North America");
    writer.WriteString("South America");
    writer.WriteString("Africa");
    writer.WriteEndArray();
}

Zusätzlich zu den Methoden WriteStartArray, WriteString und WriteEndArray stellt die JsonWriter-Klasse Methoden zum Schreiben anderer JSON-Werttypen bereit, wie z. B. WriteNumber, WriteBoolean, WriteNull usw. Die Methoden WriteStartObject, WriteEndObject und WriteMember erstellen den JSON-Text für ein Objekt. Das folgende Beispiel illustriert die Erstellung von JSON-Text für das Kontaktobjekt, das im Abschnitt „Erläuterung von literalen Notationen in JavaScript“ untersucht wurde:

private static void WriteContact()
{
    using (JsonWriter writer = new JsonTextWriter(Console.Out))
    {
        writer.WriteStartObject();              //  {
        writer.WriteMember("Name");             //      "Name" : 
        writer.WriteString("John Doe");         //          "John Doe",
        writer.WriteMember("PermissionToCall"); //      "PermissionToCall"
 :
        writer.WriteBoolean(true);              //          true,
        writer.WriteMember("PhoneNumbers");     //      "PhoneNumbers" :
        writer.WriteStartArray();               //          [ 
        WritePhoneNumber(writer,                //            {
 "Location": "Home",
            "Home", "555-555-1234");            //              "Number":
 "555-555-1234" },
        WritePhoneNumber(writer,                //            {
 "Location": "Work",
            "Work", "555-555-9999 Ext. 123");   //              "Number":
 "555-555-9999 Ext. 123" }
        writer.WriteEndArray();                 //          ]
        writer.WriteEndObject();                //  }
    }
}

private static void WritePhoneNumber(JsonWriter writer, string location,
 string number)
{
    writer.WriteStartObject();      //  {
    writer.WriteMember("Location"); //      "Location" : 
    writer.WriteString(location);   //          "...", 
    writer.WriteMember("Number");   //      "Number" :
    writer.WriteString(number);     //          "..."
    writer.WriteEndObject();        //  }
}

Die Methoden Exportieren und ExportToString in der JsonConvert-Klasse können verwendet werden, um einen angegebenen .NET-Typ in JSON-Text zu serialisieren. So kann z. B. statt der manuellen Erstellung von JSON-Text für das Array der sieben Kontinente mit der Klasse JsonTextWriter folgender Aufruf von JsonConvert.ExportToString verwendet werden, um die gleichen Ergebnisse zu erzielen:

string[] continents = {
      "Europe", "Asia", "Australia", "Antarctica", "North America", "South
 America", "Africa"
};
string jsonText = JsonConvert.ExportToString(continents);

Analyse von JSON-Text

Die Klasse JsonTextReader stellt verschiedene Methoden für die Analyse der Token von JSON-Text bereit, wobei die wichtigste Read ist. Jedes Mal, wenn die Methode Read aufgerufen wird, nutzt der Parser das nächste Token, wobei es sich um einen Zeichenfolgenwert, einen Zahlenwert, einen Objektmitgliednamen, den Start eines Arrays usw. handeln kann. Sofern erforderlich, kann der analysierte Text des aktuellen Tokens über die Eigenschaft Text aufgerufen werden. Wenn das Lesegerät z. B. boolesche Daten liest, gibt die Eigenschaft Text „true“ oder „false“ zurück, abhängig von dem eigentlichen analysierten Wert.

Der folgende Beispielcode verwendet die Klasse JsonTextReader, um die JSON-Textrepräsentation eines Zeichenfolgenarrays zu analysieren, das die Namen der sieben Kontinente enthält. Jeder Kontinent, der mit dem Buchstaben „A“ beginnt, wird an die Konsole gesendet:

  
    string jsonText = @"[""Europe"", ""Asia"", ""Australia"", ""Antarctica"",
 ""North America"", ""South America"", ""Africa""]";

using (JsonTextReader reader = new JsonTextReader(new
 StringReader(jsonText)))
{
    while (reader.Read())
    {
        if (reader.TokenClass == JsonTokenClass.String &&
            reader.Text.StartsWith("A"))
        {
            Console.WriteLine(reader.Text);
        }
    }
}
  

Hinweis   Die Klasse JsonTextReader in Jayrock ist ein ziemlich liberaler JSON-Textparser. Der Parser lässt wesentlich mehr Syntax zu, als für gültigen JSON-Text entsprechend der Regeln in RFC 4627 zugelassen ist. So lässt z. B. die Klasse JsonTextReader einzeilige und mehrzeilige Kommentare innerhalb des JSON-Texts zu, wie in JavaScript möglich ist. Einzeilige Kommentare beginnen mit doppeltem Schrägstrich (//), und mehrzeilige Kommentare beginnen mit Schrägstrich-Stern (/*) und enden mit Stern-Schrägstrich (*/). Einzeilige Kommentare können auch mit dem Rautensymbol (#) beginnen, das häufig in Unix-Konfigurationsdateien verwendet wird. In allen Instanzen werden die Kommentare vollständig vom Parser übergangen und nicht über die API angezeigt. Wie in JavaScript lässt JsonTextReader eine JSON-Zeichenfolge zu, die durch ein Apostroph (') getrennt wird. Der Parser kann sogar ein zusätzliches Komma nach dem letzten Mitglied eines Objekts oder nach dem letzten Element eines Arrays akzeptieren.

Selbst mit all diesen Zusätzen ist JsonTextReader ein anpassungsfähiger Parser! JsonTextWriter produziert hingegen lediglich strikt dem Standard entsprechenden JSON-Text. Dies stimmt mit der Aussage überein, die häufig als Robustheitsprinzip bezeichnet wird: „Sei konservativ bei dem, was du tust, und liberal bei dem, was du von anderen akzeptierst“.

Um JSON-Text direkt in ein .NET-Objekt zu konvertieren, verwenden Sie die JsonConvert-Klassenimportmethode, die den Ausgabetyp und den JSON-Text festlegt. Das folgende Beispiel zeigt die Konvertierung eines JSON-Arrays von Zeichenfolgen in ein .NET-Zeichenfolgenarray:

  
    string jsonText = @"[""Europe"", ""Asia"", ""Australia"", ""Antarctica"",
 ""North America"", ""South America"", ""Africa""]";

string[] continents = (string[]) JsonConvert.Import(typeof(string[]),
 jsonText);
  

Im Folgenden finden Sie ein interessanteres Beispiel der Konvertierung, bei der ein RSS XML-Feed in einen .NET-Typ mit XmlSerializer serialisiert und das Objekt dann in JSON-Text mit JsonConvert konvertiert wird (wobei RSS effektiv in XML zu JSON-Text konvertiert wird):

  
    XmlSerializer serializer = new XmlSerializer(typeof(RichSiteSummary));
RichSiteSummary news;

// Get the MSDN RSS feed and deserialize it...

using (XmlReader reader = XmlReader.Create("https://msdn.microsoft.com/rss.xml"))
{
    news = (RichSiteSummary) serializer.Deserialize(reader);
}



  // Export the RichSiteSummary object as JSON text, emitting the output to
 Console.Out

using (JsonTextWriter writer = new JsonTextWriter(Console.Out))
{
    JsonConvert.Export(news, writer);
}

Hinweis   Die Definition von RichSiteSummary und die entsprechenden Typen finden Sie in den Beispielen, die diesem Artikel beigefügt sind.

Verwendung von JSON in ASP.NET

Nachdem das Arbeiten mit JSON in JavaScript und innerhalb von .NET Framework über Jayrock bereits erklärt wurde, finden Sie jetzt ein praktisches Beispiel, für das diese Kenntnisse angewendet werden. Bedenken Sie die Clientskriptrückruffunktion in ASP.NET 2.0, mit der der Vorgang von Out-of-Band-Aufrufen von ASP-NET-Seiten (oder von einem bestimmten Steuerelement auf der Seite) über den Webbrowser vereinfacht wird. Während eines typischen Rückrufszenarios sendet das clientbasierte Skript im Browserpaket Daten zurück an den Webserver zur Verarbeitung durch eine serverbasierte Methode. Nach dem Erhalt der Antwortendaten vom Server verwendet der Client diese dann, um die Browseranzeige zu aktualisieren.

Hinweis   Weitere Informationen finden Sie im MSDN Magazin im Artikel Skriptrückrufe in ASP.NET 2.0.

Die Herausforderung bei einem Clientrückruf ist, dass der Client und der Server eine Zeichenfolge nur hin- und herschicken können. Daher müssen die auszutauschenden Informationen von einer internen Repräsentation im Speicher in eine Zeichenfolge konvertiert werden, bevor diese gesendet werden, und dann von einer Zeichenfolge zurück in die interne Repräsentation im Speicher analysiert werden, wenn diese empfangen werden. Die Clientskriptrückruffunktion in ASP.NET 2.0 erfordert kein besonderes Zeichenfolgenformat für die ausgetauschten Daten und bietet keine integrierte Funktionalität für die Konvertierung der internen Repräsentation im Speicher und den Zeichenfolgenrepräsentationen. Die Konvertierungslogik wird vom Entwickler implementiert und basiert auf einem vom Entwickler gewählten Datenaustauschformat.

Das folgende Beispiel illustriert die Verwendung von JSON als Datenaustauschformat bei einem Clientskriptrückruf. Das Beispiel besteht aus einer ASP.NET-Seite, die Daten aus der Northwind-Datenbank verwendet, die eine Liste an Kategorien in einer Dropdownliste bereitstellt; Produkte in der ausgewählten Kategorie werden in einer Liste im Aufzählungsformat angezeigt (siehe Abbildung 3). Wenn die Dropdownliste auf der Clientseite geändert wird, wird ein Rückruf über ein Array durchgeführt, das als einziges Element die ausgewählte CategoryID enthält.

Hinweis   Der Rückruf wird über ein Array durchgeführt, dessen einziges Element die ausgewählte CategoryID ist (statt nur der CategoryID), da der JSON-Standard erfordert, dass JSON-Text ein Objekt oder Array als Stamm hat. Der Client muss natürlich keinen JSON-Text an Server senden, in unserem Beispiel reicht es, wenn die ausgewählte CategoryID als Zeichenfolge an den Server übertragen wird. Wir wollten jedoch das Senden von JSON-Text in sowohl der Anforderungs- als auch der Antwortnachricht des Rückrufs vorführen.

Der folgende Code im Ereignishandler Page_Load konfiguriert das Websteuerungselement Categories DropDownList, d. h. wenn dieses geändert wird, wird die Funktion GetProductsForCategory aufgerufen, und die ausgewählten Werte der Dropdownliste werden an sie übergeben. Diese Funktion initiiert den Clientskriptrückruf, wenn der übergebene Wert der Dropdownliste größer als Null ist:

  
    // Add client-side onchange event to drop-down list
Categories.Attributes["onchange"] = "Categories_onchange(this);";

// Generate the callback script
string callbackScript = ClientScript.GetCallbackEventReference(
    /* control        */ this, 
    /* argument       */ "'[' + categoryID + ']'", 
    /* clientCallback */ "showProducts", 
    /* context        */ "null");

// Add the Categories_onchange function
ClientScript.RegisterClientScriptBlock(GetType(),
"Categories_onchange", @"
    function Categories_onchange(sender)
    {
        clearResults();

        var categoryID = sender.value;            
        if (categoryID > 0)
        {
            " + callbackScript + @"
        }
    }", true);
  

Die Methode GetCallBackEventReference in der Klasse ClientScriptManager, die zur Generierung des JavaScript-Codes verwendet wird, über den der Rückruf aufgerufen wird, verfügt über folgende Signatur:

  
    public string GetCallbackEventReference (
    Control control,
    string argument,
    string clientCallback,
    string context,
)
  

Der Argumentparameter legt fest, welche Daten während des Rückrufs vom Client an den Webserver gesendet werden, und der Parameter clientCallback legt den Namen der clientbasierten Funktion fest, die nach Abschluss des Rückrufs aufgerufen wird (showProducts). Der Methodenaufruf GetCallBackEventReference generiert folgenden JavaScript-Code und fügt ihn dem gerenderten Markup hinzu:

  
    WebForm_DoCallback('__Page','[' + categoryID + 
']',showProducts,null,null,false)
  

'[' + categoryID + ']' ist der Wert, der während eines Rückrufs an den Server übergeben wird (ein Array mit einem einzelnen Element, categoryID) und showProducts ist die JavaScript-Funktion, die ausgeführt wird, wenn der Rückruf zurückgegeben wird.

Auf Serverseite verwendet die Methode, die als Antwort auf den Rückruf ausgeführt wird, die Klasse JsonConvert von Jayrock zur Analyse des eingehenden JSON-Texts und zur Formatierung des ausgehenden JSON Texts. Insbesondere werden die Namen der Produkte, die den ausgewählten Kategorien zugeordnet sind, abgerufen und als Zeichenfolgenarray zurückgegeben.

// Deserialize the JSON text into an array of integers
int[] args = (int[]) JsonConvert.Import(typeof(int[]), eventArgument);

// Read the selected CategoryID from the array
int categoryID = args[0];

// Get products based on categoryID 
NorthwindDataSet.ProductsRow[] rows = Northwind.Categories.FindByCategoryID(categoryID).GetProductsRows();

// Load the names into a string array
string[] productNames = new string[rows.Length];
for (int i = 0; i < rows.Length; i++)
{
    productNames[i] = rows[i].ProductName;
}// Serialize the string array as JSON text and return it to the clientreturn JsonConvert.ExportToString(productNames);

Hinweis   Die Klasse JsonConvert wird zweimal verwendet, einmal für die Konvertierung von JSON-Text in eventArgument in ein Array an Ganzzahlen und dann zur Konvertierung des Zeichenfolgenarrays productNames in JSON-Text, der an den Client zurückgegeben wird. Alternativ hätten hier die Klassen JsonReader und JsonWriter verwendet werden können, doch JsonConvert führt die gleiche Aufgabe aus, sofern die involvierten Daten relativ klein sind und einfach vorhandenen Typen zugeordnet werden können.

Wenn die Daten vom Server zurückgegeben werden, wird die über die Methode GetCallBackEventReference angegebene JavaScript-Funktion aufgerufen, die den Rückgabewert übergibt. Die JavaScript-Methode, showProducts, beginnt mit dem Verweis auf das <div>-Element ProductOutput. Die JSON-Antwort wird dann analysiert und fügt eine nicht geordnete Liste dynamisch hinzu, die ein Listenelement für jedes Arrayelement enthält. Wenn keine Produkte für die ausgewählte Kategorie zurückgegeben werden, wird eine entsprechende Nachricht angezeigt.

function showProducts(arg, context)
{
    // Dump the JSON text response from the server.

    document.forms[0].JSONResponse.value = arg;
    
    // Parse JSON text returned from callback.

    var categoryProducts = eval("(" + arg + ")");

    // Get a reference to the <div> ProductOutput.
    
    var output = document.getElementById("ProductOutput");

    // If no products for category, show message.
    
    if (categoryProducts.length == 0)
    {
        output.appendChild(document.createTextNode("There are no products
 for this category..."));
    }
    else
    {
        // There are products, display them in an unordered list. 
        
        var ul = document.createElement("ul");
        
        for (var i = 0; i < categoryProducts.length; i++)
        {
            var product = categoryProducts[i];
            var li = document.createElement("li");
            li.appendChild(document.createTextNode(product));
            ul.appendChild(li);
        }
        
        output.appendChild(ul);
    }
}

Abbildung 2 illustriert die Abfolge der Ereignisse, während Abbildung 3 das Beispiel in Aktion zeigt; der vollständige Code befindet sich im Download für diesen Artikel.

Abbildung 2: Der Client sendet die ausgewählte CategoryID als einzelnes Element in einem Array, und der Server gibt ein Array zugeordneter Produktnamen zurück.

Abbildung 3: Die Produkte werden in einer Liste im Aufzählungsformat innerhalb der ausgewählten Kategorie angezeigt.

Schlussbemerkung

JSON ist ein einfaches, textbasiertes Datenaustauschformat, das auf einer Teilmenge der literalen Notation der Programmiersprache JavaScript basiert. Es stellt eine kurze Codierung für Anwendungsdatenstrukturen bereit und wird in der Regel in Situationen verwendet, in denen eine JavaScript-Implementierung für eine oder beide Anwendungen verfügbar ist, die Daten austauschen, z. B. Ajax-Webanwendungen. Die Vorteile von JSON liegen darin, dass das Format leicht zu verstehen, leicht anzupassen und leicht zu implementieren ist. JSON erfordert so gut wie keine Einarbeitungszeit für Entwickler, die bereits mit JavaScript oder anderen Programmiersprachen vertraut sind, die eine ähnliche Unterstützung für reichhaltige literale Notation bieten (wie Python und Ruby). Eine Analyse von JSON-Text in JavaScript-Code kann einfach über Aufrufen der Funktion eval erfolgen, und das Erstellen von JSON-Text kann einfach über das Skript json.js erreicht werden, das unter http://www.json.org/json.js bereitgestellt wird.

Es gibt stetig ansteigende Anzahl an Bibliotheken für die Arbeit mit JSON für alle wichtigen Plattformen und Frameworks. In diesem Artikel wurde Jayrock behandelt, eine Open-Source-Bibliothek für Erstellen und Analysieren von JSON-Text in .NET-Anwendungen. Jayrock kann in ASP.NET 1.x, 2.0 und Mono-Anwendungen verwendet werden. ASP.NET AJAX bietet ähnliche JSON-Funktionalität, jedoch nur für ASP.NET 2.0-Anwendungen.

Viel Spaß bei der Programmierung!

Ajax oder AJAX?

Der Begriff Ajax wurde anfänglich von Jesse James Garrett zur Beschreibung der Art von Webanwendungen und Technologiesätzen geprägt, die bei der Erstellung äußerst interaktiver Webanwendungen beteiligt sind. Der Begriff Ajax wurde in der Vergangenheit als Akronym AJAX über das Internet verbreitet, das für „Asynchronous JavaScript And XML“ steht. Mit der Zeit wurde jedoch erkannt, dass das „X“ in AJAX nicht sehr repräsentativ für das zugrunde liegende Datenformat ist, das zur Kommunikation mit dem Webserver im Hintergrund verwendet wird, da zahlreiche Implementierungen zu JSON gewechselt haben, das eine einfachere und effizientere Alternative darstellt. Statt ein neues Akronym zu verwenden, wie AJAJ (das eher ein Zungenbrecher ist), wurde dazu übergegangen, den Begriff Ajax anstelle des Akronyms AJAX zu verwenden.

Derzeit ist zu erwarten, dass „AJAX“ und „Ajax“ gemischt, weit verbreitet und mit identischer Bedeutung verwendet werden. In diesem Artikel haben wir den „Begriff Ajax“ verwendet. Handelsübliche Produkte, die Frameworks für Ajax-Anwendungen bereitstellen, verwenden häufig das Akronym, um das Produkt von dem bekannten Reinigungsprodukt zu unterscheiden und um potenzielle Probleme durch die Verwendung von Markennamen zu verhindern.

Referenzen

Danksagungen

Vor der Übergabe des Artikels an MSDN haben zahlreiche Freiwillige beim Korrekturlesen geholfen und ihr Feedback zu Inhalt, Grammatik und Anleitung bereitgestellt. Douglas Crockford, Eric Schönholzer und Milan Negovan haben einen Hauptteil der Arbeit geleistet.

Die Autoren

Atif Aziz ist einer der wichtigsten Berater der Skybow AG. Er konzentriert sich darauf, Kunden zu helfen, die .NET-Entwicklungsplattform zu verstehen und Lösungen hierfür zu erstellen. Er trägt regelmäßig zur Microsoft-Entwicklercommunity bei, indem er Vorträge bei Konferenzen hält und Artikel für technische Veröffentlichungen verfasst. Atif Aziz ist ein Sprecher bei INETA und Vorsitzender der größten Schweizer .NET-Benutzergruppe. Er kann unter atif.aziz@skybow.com oder über seine Website unter http://www.raboof.com erreicht werden.

Scott Mitchell, Autor von sechs Büchern zu ASP/ASP.NET und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Er ist als freier Berater, Trainer und Autor tätig. Er kann unter mitchell@4guysfromrolla.com oder über seinen Blog erreicht werden: http://ScottOnWriting.net.