Einführung in die JavaScript-Objektnotation (JSON) in JavaScript und .NET
Einführung in die JavaScript-Objektnotation (JSON) in JavaScript und .NET
Atif Aziz, Scott Mitchell
Februar 2007
Gilt für:
JSON
Ajax
Zusammenfassung: In diesem Artikel wird javaScript Object Notation (oder JSON) erläutert, ein offenes und textbasiertes Datenaustauschformat, das ein standardisiertes Datenaustauschformat bietet, das sich besser für Webanwendungen im Ajax-Stil eignet. (22 gedruckte Seiten)
Inhalte
Einführung
Grundlegendes zur Literalnotation in JavaScript
Vergleichen von JSON mit XML
Erstellen und Analysieren von JSON-Nachrichten mit JavaScript
Arbeiten mit JSON im .NET Framework
Zusammenfassung
Referenzen
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 ein Austauschprotokoll ausgewählt werden. Es gibt eine Vielzahl von offenen, standardisierten Optionen, und die ideale Wahl hängt von den Anwendungsanforderungen und bereits vorhandenen Funktionen ab. Soap-basierte Webdienste formatieren die Daten beispielsweise in einer XML-Nutzlast, die in einen SOAP-Umschlag eingeschlossen ist.
WÄHREND XML für viele Anwendungsszenarien gut funktioniert, hat es einige Nachteile, die es für andere weniger als ideal machen. Ein solcher Bereich, in dem XML oft weniger als ideal ist, ist die Verwendung von Webanwendungen im Ajax-Stil. Ajax ist eine Technik zum Erstellen interaktiver Webanwendungen, die durch die Verwendung von Out-of-Band-, einfachen Aufrufen des Webservers anstelle von ganzseitigen Postbacks eine schnellere Benutzererfahrung bieten. Diese asynchronen Aufrufe werden auf dem Client mithilfe von JavaScript initiiert und umfassen das Formatieren von Daten, das Senden an einen Webserver sowie das Analysieren und Arbeiten mit den zurückgegebenen Daten. Während die meisten Browser XML erstellen, senden und analysieren können, bietet JavaScript Object Notation (oder JSON) ein standardisiertes Datenaustauschformat, das sich besser für Webanwendungen im Ajax-Stil eignet.
JSON ist ein offenes, textbasiertes Datenaustauschformat (siehe RFC 4627). Wie XML ist es von Menschen lesbar, plattformunabhängig und verfügt über eine breite Verfügbarkeit von Implementierungen. Daten, die nach dem JSON-Standard formatiert werden, sind einfach und können von JavaScript-Implementierungen mit unglaublicher Leichtigkeit analysiert werden, was sie zu einem idealen Datenaustauschformat für Ajax-Webanwendungen macht. Da es sich in erster Linie um ein Datenformat handelt, ist JSON nicht nur auf Ajax-Webanwendungen beschränkt und kann in praktisch jedem Szenario verwendet werden, in dem Anwendungen strukturierte Informationen als Text austauschen oder speichern müssen.
In diesem Artikel werden der JSON-Standard, seine Beziehung zu JavaScript und sein Vergleich mit XML untersucht. Jayrock, eine Open-Source-JSON-Implementierung für .NET, wird erläutert, und Beispiele für das Erstellen und Analysieren von JSON-Nachrichten werden in JavaScript und C# bereitgestellt.
Grundlegendes zur Literalnotation in JavaScript
Literale werden in Programmiersprachen verwendet, um feste Werte buchstäblich auszudrücken, z. B. den konstanten ganzzahligen Wert von 4 oder die Zeichenfolge "Hello, World". Literale können in den meisten Sprachen überall dort verwendet werden, wo ein Ausdruck zulässig ist, z. B. teil einer Bedingung in einer Steuerelementanweisung, ein Eingabeparameter beim Aufrufen einer Funktion, in der Variablenzuweisung usw. Der folgende C#- und Visual Basic-Code initialisiert beispielsweise die Variable x mit dem konstanten ganzzahligen Wert 42.
int x = 42; // C#
Dim x As Integer = 42 ' Visual Basic
Unterschiedliche Programmiersprachen ermöglichen Literale unterschiedlicher Typen. Die meisten Programmiersprachen unterstützen mindestens Literale für skalare Typen wie ganze Zahlen, Gleitkommazahlen, Zeichenfolgen und Boolean. Das Interessante an JavaScript ist, dass es neben skalaren Typen auch Literale für strukturierte Typen wie Arrays und Objekte unterstützt. Dieses Feature ermöglicht eine knappe Syntax für die bedarfsgesteuerte Erstellung und Initialisierung von Arrays und Objekten.
Arrayliterale in JavaScript bestehen aus null oder mehr Ausdrücken, wobei jeder Ausdruck ein Element des Arrays darstellt. Die Arrayelemente sind in eckige Klammern ([]) eingeschlossen und durch Kommas getrennt. Im folgenden Beispiel wird ein Array mit sieben Zeichenfolgenelementen definiert, 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 jetzt mit dem Erstellen und Initialisieren eines Arrays in JavaScript ohne die Literalnotation:
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 Member eines Objekts und deren Werte. Die Liste der Objektmember und -werte ist in geschweifte Klammern ({}) eingeschlossen, und jedes Element wird durch ein Komma getrennt. Innerhalb jedes Members werden Name und Wert durch einen Doppelpunkt (:) getrennt. Im folgenden Beispiel wird ein Objekt erstellt und mit drei Membern namens 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 bisher vorgestellten Beispiele veranschaulichen die Verwendung von Zeichenfolgen- und numerischen Literalen innerhalb von Array- und Objektliteralen. Sie können auch ein gesamtes Diagramm ausdrücken, indem Sie die Notation rekursiv verwenden, sodass Arrayelemente und Objektmemberwerte wiederum Objekt- und Arrayliterale verwenden können. Der folgende Codeausschnitt veranschaulicht beispielsweise ein Objekt, das über ein Array als Member (PhoneNumbers) verfügt, wobei das Array aus einer Liste von Objekten besteht.
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 Erläuterung der Literalunterstützung für JavaScript finden Sie im Core JavaScript 1.5-Leitfaden im Abschnitt Literale.
Von JavaScript-Literalen zu JSON
JSON ist ein Datenaustauschformat, das aus einer Teilmenge der Literalobjektnotation in JavaScript erstellt wurde. Während die von JavaScript für Literalwerte akzeptierte Syntax sehr flexibel ist, ist es wichtig zu beachten, dass JSON über viel strengere Regeln verfügt. Gemäß dem JSON-Standard muss beispielsweise der Name eines Objektelements eine gültige JSON-Zeichenfolge sein. Eine Zeichenfolge in JSON muss in Anführungszeichen eingeschlossen werden. JavaScript ermöglicht es hingegen, Objektmembernamen durch Anführungszeichen oder Apostrophe zu trennen oder Zitate ganz wegzulassen, solange der Membername nicht mit einem reservierten JavaScript-Schlüsselwort (keyword) in Konflikt steht. Ebenso ist ein Arrayelement oder ein Objektmemberwert in JSON auf einen sehr begrenzten Satz beschränkt. In JavaScript können Arrayelemente und Objektmemberwerte jedoch auf so ziemlich jeden gültigen JavaScript-Ausdruck verweisen, einschließlich Funktionsaufrufen und Definitionen!
Der Charme von JSON liegt in seiner Einfachheit. Eine nach dem JSON-Standard formatierte Nachricht besteht aus einem einzelnen Objekt oder Array der obersten Ebene. Die Arrayelemente und Objektwerte können Objekte, Arrays, Zeichenfolgen, Zahlen, boolesche Werte (true und false) oder NULL sein. Das ist kurz gesagt der JSON-Standard! Es ist wirklich so einfach. Eine formalere Beschreibung des Standards finden Sie unter www.json.org oder RFC 4627 .
Einer der wunden Punkte von JSON ist das Fehlen eines Datums-/Uhrzeitliterals. Viele Menschen sind überrascht und enttäuscht, dies zu erfahren, wenn sie zum ersten Mal auf JSON stoßen. Die einfache Erklärung (tröstlich oder nicht) für das Fehlen eines Datums-/Uhrzeitliterals besteht darin, dass JavaScript nie einen hatte: Die Unterstützung für Datums- und Uhrzeitwerte in JavaScript wird vollständig über das Date-Objekt bereitgestellt. Die meisten Anwendungen, die JSON als Datenformat verwenden, verwenden daher in der Regel entweder eine Zeichenfolge oder eine Zahl, um Datums- und Uhrzeitwerte auszudrücken. Wenn eine Zeichenfolge verwendet wird, können Sie im Allgemeinen davon ausgehen, dass sie im ISO 8601-Format vorliegt. Wenn stattdessen eine Zahl verwendet wird, wird der Wert in der Regel als Die Anzahl von Millisekunden in der koordinierten Weltzeit (UTC) seit der Epoche verwendet, wobei die Epoche als Mitternacht am 1. Januar 1970 (UTC) definiert ist. Auch dies ist eine reine Konvention und nicht Teil des JSON-Standards. Wenn Sie Daten mit einer anderen Anwendung austauschen, müssen Sie deren Dokumentation überprüfen, um zu sehen, wie Datums- und Uhrzeitwerte innerhalb eines JSON-Literals codiert werden. Microsofts ASP.NET AJAX verwendet beispielsweise keine der beschriebenen Konventionen. Stattdessen werden .NET DateTime-Werte als JSON-Zeichenfolge codiert, wobei der Inhalt der Zeichenfolge \/Date(ticks)\/ ist und bei der Ticks Millisekunden seit Epoche (UTC) darstellen. So ist der 29. November 1989, 4:55:30 Uhr in UTC als "\/Date(628318530718)\/" codiert. Einige Gründe für diese eher erfundene Wahl der Codierung finden Sie unter "Inside ASP.NET JSON-Datums- und Uhrzeitzeichenfolge von AJAX"
Vergleichen von JSON mit XML
Sowohl JSON als auch XML können verwendet werden, um native Objekte im Arbeitsspeicher in einem textbasierten, von Menschen lesbaren Datenaustauschformat darzustellen. Darüber hinaus sind die beiden Datenaustauschformate isomorph – wenn Text in einem Format angegeben wird, ist ein gleichwertiges Format im anderen denkbar. Wenn Sie beispielsweise einen der öffentlich zugänglichen Webdienste von Yahoo! aufrufen, können Sie über einen Abfragezeichenfolgenparameter angeben, ob die Antwort als XML oder JSON formatiert werden soll. Daher ist es bei der Entscheidung für ein Datenaustauschformat nicht einfach, eins gegenüber dem anderen als Wundermittel auszuwählen, sondern vielmehr, welches Format die Eigenschaften aufweist, die es zur besten Wahl für eine bestimmte Anwendung machen. Xml hat beispielsweise seine Wurzeln im Markieren von Dokumenttext und scheint in diesem Raum sehr gut zu glänzen (wie bei XHTML offensichtlich). JSON hingegen hat seine Wurzeln in Programmiersprachetypen und -strukturen und bietet daher eine natürlichere und leichter verfügbare Zuordnung zum Austausch strukturierter Daten. Über diese beiden Ausgangspunkte hinaus hilft Ihnen die folgende Tabelle, die wichtigsten Merkmale von XML und JSON zu verstehen und zu vergleichen.
Wichtige Merkmalsunterschiede zwischen XML und JSON
Merkmal | XML | JSON |
---|---|---|
Datentypen | Bietet keine Vorstellung von Datentypen. Für das Hinzufügen von Typinformationen muss das XML-Schema verwendet werden. | Bietet skalare Datentypen und die Möglichkeit, strukturierte Daten über Arrays und Objekte auszudrücken. |
Unterstützung für Arrays | Arrays müssen durch Konventionen ausgedrückt werden, z. B. durch die Verwendung eines äußeren Platzhalterelements, das die Arrayinhalte als innere Elemente modelliert. In der Regel verwendet das äußere Element die Pluralform des Namens, der für innere Elemente verwendet wird. | Native Arrayunterstützung. |
Unterstützung für Objekte | Objekte müssen durch Konventionen ausgedrückt werden, oft durch eine gemischte Verwendung von Attributen und Elementen. | Native Objektunterstützung. |
NULL-Unterstützung | Erfordert die Verwendung von xsi:nil für Elemente in einem XML-instance Dokument sowie einen Import des entsprechenden Namespaces. | Erkennt den NULL-Wert nativ. |
Kommentare | Native Unterstützung und in der Regel über APIs verfügbar. | Wird nicht unterstützt. |
Namespaces | Unterstützt Namespaces, wodurch das Risiko von Namenskonflikten beim Kombinieren von Dokumenten vermieden wird. Namespaces ermöglichen es auch, vorhandene XML-basierte Standards sicher zu erweitern. | Kein Konzept von Namespaces. Benennungskonflikte werden in der Regel vermieden, indem Objekte geschachtelt werden oder ein Präfix in einem Objektmembernamen verwendet wird (ersterer wird in der Praxis bevorzugt). |
Formatierungsentscheidungen | Komplex. Erfordert einen größeren Aufwand bei der Entscheidung, wie Anwendungstypen XML-Elementen und -Attributen zugeordnet werden sollen. Kann zu hitzigen Debatten führen, ob ein elementzentrierter oder attributzentrierter Ansatz besser ist. | Einfach. Bietet eine viel direktere Zuordnung für Anwendungsdaten. Die einzige Ausnahme kann das Fehlen von Datums-/Uhrzeitliteral sein. |
Size | Dokumente sind in der Regel langwierig, insbesondere wenn ein elementzentrierter Formatierungsansatz verwendet wird. | Die Syntax ist sehr knapp und ergibt formatierten Text, bei dem der größte Teil des Speicherplatzes (zu Recht) von den dargestellten Daten belegt wird. |
Analysieren in JavaScript | Erfordert eine XML-DOM-Implementierung und zusätzlichen Anwendungscode, um Text wieder JavaScript-Objekten zuzuordnen. | Es ist kein zusätzlicher Anwendungscode zum Analysieren von Text erforderlich. kann die eval-Funktion von JavaScript verwenden. |
Lernkurve | Im Allgemeinen ist die Gemeinsame Verwendung mehrerer Technologien erforderlich: XPath, XML-Schema, XSLT, XML-Namespaces, DOM usw. | Sehr einfacher Technologiestapel, der Entwicklern mit JavaScript- oder anderen dynamischen Programmiersprachen bereits vertraut ist. |
JSON ist ein relativ neues Datenaustauschformat und verfügt nicht über die jahrelange Einführung oder Anbieterunterstützung, die XML heute genießt (obwohl JSON schnell aufholt). In der folgenden Tabelle wird der aktuelle Stand der Dinge in den XML- und JSON-Leerzeichen hervorgehoben.
Unterstützung von Unterschieden zwischen XML und JSON
Support | XML | JSON |
---|---|---|
Tools | Verfügt über einen ausgereiften Satz von Tools, die von vielen Branchenanbietern weit verbreitet sind. | Umfangreiche Toolunterstützung – z. B. Editoren und Formatierer – ist knapp. |
Microsoft .NET Framework | Sehr gute und ausgereifte Unterstützung seit Version 1.0 des .NET Framework. XML-Unterstützung ist als Teil der Basisklassenbibliothek (Base Class Library, BCL) verfügbar. Für nicht verwaltete Umgebungen gibt es MSXML. | Bisher keine, außer einer anfänglichen Implementierung im Rahmen von ASP.NET AJAX. |
Plattform und Sprache | Parser und Formatierer sind auf vielen Plattformen und Sprachen (kommerzielle und Open Source Implementierungen) weit verbreitet. | Parser und Formatierer sind bereits auf vielen Plattformen und in vielen Sprachen verfügbar. Einen guten Satz von Verweisen finden Sie in json.org . Die meisten Implementierungen sind derzeit eher Open Source Projekte. |
Integrierte Sprache | Branchenanbieter experimentieren derzeit mit der Unterstützung buchstäblich innerhalb von Sprachen. Weitere Informationen finden Sie im LINQ-Projekt von Microsoft . | Wird nur in JavaScript/ECMAScript nativ unterstützt. |
Hinweis Keine der beiden Tabellen soll eine umfassende Liste von Vergleichspunkten sein. Es gibt weitere Winkel, auf denen beide Datenformate verglichen werden können, aber wir waren der Meinung, dass diese Schlüsselpunkte ausreichen sollten, um einen ersten Eindruck zu erzeugen.
Erstellen und Analysieren von JSON-Nachrichten mit JavaScript
Bei Verwendung von JSON als Datenaustauschformat sind zwei häufige Aufgaben die Umwandlung einer nativen und speicherinternen Darstellung in ihre JSON-Textdarstellung und umgekehrt. Leider bietet JavaScript zum Zeitpunkt des Schreibens keine integrierten Funktionen zum Erstellen von JSON-Text aus einem bestimmten Objekt oder Array. Diese Methoden werden voraussichtlich 2007 in der vierten Ausgabe des ECMAScript-Standards enthalten sein. Bis diese JSON-Formatierungsfunktionen formell zu JavaScript hinzugefügt und in gängigen Implementierungen allgemein verfügbar sind, verwenden Sie das Referenzimplementierungsskript, das unter http://www.json.org/json.jszum Download verfügbar ist.
In der neuesten Iteration zum Zeitpunkt dieses Schreibens fügt das json.js-Skript bei www.json.orgJSONString() -Funktionen zu Array-, Zeichenfolgen-, booleschen, Objekt- und anderen JavaScript-Typen hinzu. Die toJSONString()-Funktionen für Skalartypen (wie Number und Boolean) sind recht einfach, da sie nur eine Zeichenfolgendarstellung des instance Werts zurückgeben müssen. Die toJSONString()- Funktion für den booleschen Typ gibt beispielsweise die Zeichenfolge "true" zurück, wenn der Wert true ist, andernfalls "false". Die toJSONString()- Funktionen für Array- und Objekttypen sind interessanter. Bei Arrayinstanzen wird die toJSONString() -Funktion für jedes enthaltene Element nacheinander aufgerufen, wobei die Ergebnisse mit Kommas verkettet werden, um jedes Ergebnis zu trennen. Die letzte Ausgabe, die in eckige Klammern eingeschlossen ist. Ebenso wird für Objektinstanzen jedes Element aufgezählt und seine toJSONString() -Funktion aufgerufen. Der Membername und die JSON-Darstellung seines Werts werden mit einem Doppelpunkt in der Mitte verkettet. Jedes Elementname- und Wertpaar wird durch ein Komma getrennt, und die gesamte Ausgabe wird in geschweifte Klammern eingeschlossen.
Das Nettoergebnis der toJSONString() -Funktionen ist, dass jeder Typ mit einem einzelnen Funktionsaufruf in sein JSON-Format konvertiert werden kann. Das folgende JavaScript erstellt ein Array-Objekt und fügt sieben String-Elemente hinzu, die absichtlich die ausführliche und nicht literale Methode zu Veranschaulichungszwecken verwenden. Anschließend wird die JSON-Darstellung 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 aus, das gemäß dem JSON-Standard formatiert ist.
Das Analysieren von JSON-Text ist noch einfacher. Da JSON nur eine Teilmenge von JavaScript-Literalen ist, kann es mithilfe der eval(expr)-Funktion,
in eine In-Memory-Darstellung analysiert werden, die den JSON-Quelltext als JavaScript-Quellcode behandelt. Die eval-Funktion akzeptiert als Eingabe eine Zeichenfolge mit gültigem JavaScript-Code und wertet den Ausdruck aus. Folglich ist die folgende einzelne Codezeile alles, was erforderlich ist, um JSON-Text in eine native Darstellung zu verwandeln:
var value = eval( "(" + jsonText + ")" );
Hinweis Die zusätzlichen Klammern werden verwendet , um die Quelleingabe bedingungslos wie einen Ausdruck zu behandeln. Dies ist besonders wichtig für Objekte. Wenn Sie versuchen, eval mit einer Zeichenfolge aufzurufen, die JSON-Text enthält, der ein Objekt definiert, z. B. die Zeichenfolge "{}" (d. h. ein leeres Objekt), wird einfach undefined als analysiertes Ergebnis zurückgegeben. Die Klammern erzwingen, dass der JavaScript-Parser die geschweiften geschweiften Klammern der obersten Ebene als Literalnotation für ein Objekt instance anstelle von geschweiften Klammern, die einen Anweisungsblock definieren, angezeigt wird. Das gleiche Problem tritt übrigens nicht auf, wenn das Element der obersten Ebene ein Array ist, wie in eval("[1,2,3]"). Aus Gründen der Uniformität sollte JSON-Text jedoch vor dem Aufrufen von eval immer in Klammern eingeschlossen werden, sodass keine Unklarheit darüber besteht, wie die Quelle interpretiert werden soll.
Beim Auswerten der Literalnotation wird ein instance zurückgegeben, der der Literalsyntax entspricht, und dem Wert zugewiesen. Sehen Sie sich das folgende Beispiel an, das die eval-Funktion verwendet, um die Literalnotation für ein Array zu analysieren und das resultierende Array den Variablen kontinenten zuzuweisen.
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.");
Natürlich stammt der ausgewertete JSON-Text in der Praxis aus einer externen Quelle, anstatt wie im obigen Fall hartcodiert zu sein.
Die eval-Funktion wertet blind aus, welcher Ausdruck übergeben wird. Eine nicht vertrauenswürdige Quelle könnte daher potenziell gefährliches JavaScript zusammen mit der Literalnotation enthalten, aus der die JSON-Daten bestehen. In Szenarien, in denen die Quelle nicht vertrauenswürdig ist, wird dringend empfohlen, den JSON-Text mithilfe der ParseJSON() -Funktion zu analysieren (zu finden in json.js):
// Requires json.js
var continents = arrayAsJSONText.parseJSON();
Die parseJSON()- Funktion verwendet auch eval, aber nur, wenn die in arrayAsJSONText enthaltene Zeichenfolge dem JSON-Textstandard entspricht. Dazu wird ein cleverer Test für reguläre Ausdrücke verwendet.
Arbeiten mit JSON im .NET Framework
JSON-Text kann ganz einfach aus JavaScript-Code erstellt und analysiert werden, der Teil seiner Verzierung ist. Wenn JSON jedoch in einer ASP.NET Webanwendung verwendet wird, unterstützt nur der Browser JavaScript, da der serverseitige Code höchstwahrscheinlich in Visual Basic oder C# geschrieben ist.
Die meisten AJAX-Bibliotheken, die für ASP.NET entwickelt wurden, bieten Unterstützung für das programmgesteuerte Erstellen und Analysieren von JSON-Text. Um mit JSON in einer .NET-Anwendung zu arbeiten, sollten Sie daher eine dieser Bibliotheken verwenden. Es gibt viele Open Source- und Drittanbieteroptionen, und Microsoft verfügt auch über eine eigene Ajax-Bibliothek namens ASP.NET AJAX.
In diesem Artikel sehen wir uns Beispiele an, die Jayrock verwenden, eine Open-Source-Implementierung von JSON für die Microsoft-.NET Framework, die von Co-Autor Atif Aziz erstellt wurde. Wir haben uns aus drei Gründen für die Verwendung von Jayrock anstelle von ajax ASP.NET entschieden:
- Jayrock ist Open-Source, sodass es möglich ist, nach Bedarf zu erweitern oder anzupassen.
- Jayrock kann in ASP.NET 1.x-, 2.0- und Mono-Anwendungen verwendet werden, während ASP.NET AJAX nur für ASP.NET Version 2.0 gilt.
- Der Bereich von Jayrock ist auf JSON und JSON-RPC beschränkt, und ersterer ist der Standard Schwerpunkt dieses Artikels. Während ASP.NET AJAX einige Unterstützung für das Erstellen und Analysieren von JSON-Text enthält, besteht sein Hauptzweck darin, eine umfassende Plattform zum Erstellen von End-to-End-Ajax-Webanwendungen in ASP.NET zu bieten. Die zusätzlichen Schnickschnacks können ablenkend sein, wenn Ihr Standard Fokus JSON ist.
Das Arbeiten mit JSON in .NET mit Jayrock ähnelt der Arbeit mit XML über die XmlWriter-, XmlReader- und XmlSerializer-Klassen im .NET Framework. Die in Jayrock gefundenen Klassen JsonWriter, JsonReader, JsonTextWriter und JsonTextReader imitieren die Semantik der .NET Framework Klassen XmlWriter, XmlReader, XmlTextWriter und XmlTextReader. Diese Klassen sind nützlich für die Kopplung mit JSON auf niedriger und streamorientierter Ebene. Mit diesen Klassen kann JSON-Text über eine Reihe von Methodenaufrufen erstellt oder analysiert werden. Beispielsweise schreibt die JsonWriter-KlassenmethodeWriteNumber(number) die entsprechende Zeichenfolgendarstellung der Zahl gemäß dem JSON-Standard. Die JsonConvert-Klasse bietet Export- und Importmethoden für die Konvertierung zwischen .NET-Typen und JSON. Diese Methoden bieten eine ähnliche Funktionalität wie in den Methoden Serialize und Deserialize der XmlSerializer-Klasse.
Erstellen von JSON-Text
Der folgende Code veranschaulicht die Verwendung der JsonTextWriter-Klasse zum Erstellen des JSON-Texts für ein Zeichenfolgenarray von Kontinenten. Dieser JSON-Text wird an einen TextWriter-instance an den Konstruktor übergeben, bei dem es sich in diesem Beispiel um den Ausgabestream der Konsole handelt (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 wie WriteNumber, WriteBoolean, WriteNull usw. bereit. Die Methoden WriteStartObject, WriteEndObject und WriteMember erstellen den JSON-Text für ein Objekt. Das folgende Beispiel veranschaulicht das Erstellen des JSON-Texts für das Kontaktobjekt, das im Abschnitt "Grundlegendes zur Literalnotation in JavaScript" untersucht wird:
private static void WriteContact() { using (JsonWriter w = new JsonTextWriter(Console.Out)) { w.WriteStartObject(); // { w.WriteMember("Name"); // "Name" : w.WriteString("John Doe"); // "John Doe", w.WriteMember("PermissionToCall"); // "PermissionToCall" : w.WriteBoolean(true); // true, w.WriteMember("PhoneNumbers"); // "PhoneNumbers" : w.WriteStartArray(); // [ WritePhoneNumber(w, // { "Location": "Home", "Home" // "Number": "555-555-1234"); // "555-555-1234" }, WritePhoneNumber(w, // { "Location": "Work", "Work", // "Number": "555-555-9999"); // "555-555-9999" } w.WriteEndArray(); // ] w.WriteEndObject(); // } } } private static void WritePhoneNumber(JsonWriter w, string location, string number) { w.WriteStartObject(); // { w.WriteMember("Location"); // "Location" : w.WriteString(location); // "...", w.WriteMember("Number"); // "Number" : w.WriteString(number); // "..." w.WriteEndObject(); // } }
Export - und ExportToString-Methoden in der JsonConvert-Klasse können verwendet werden, um einen angegebenen .NET-Typ in JSON-Text zu serialisieren. Anstatt beispielsweise den JSON-Text für das Array der sieben Kontinente mithilfe der JsonTextWriter-Klasse manuell zu erstellen, führt der folgende Aufruf von JsonConvert.ExportToString zu den gleichen Ergebnissen:
string[] continents = { "Europe", "Asia", "Australia", "Antarctica", "North America", "South America", "Africa" }; string jsonText = JsonConvert.ExportToString(continents);
Analysieren von JSON-Text
Die JsonTextReader-Klasse stellt eine Vielzahl von Methoden bereit, um die Token von JSON-Text zu analysieren, wobei der Kern read ist. Jedes Mal, wenn die Read-Methode aufgerufen wird, nutzt der Parser das nächste Token, bei dem es sich um einen Zeichenfolgenwert, einen Zahlenwert, einen Objektmembernamen, den Start eines Arrays usw. handeln kann. Auf den analysierten Text des aktuellen Tokens kann ggf. über die Text-Eigenschaft zugegriffen werden. Wenn der Leser beispielsweise auf booleschen Daten sitzt, gibt die Text-Eigenschaft abhängig vom tatsächlichen Analysewert "true" oder "false" zurück.
Im folgenden Beispielcode wird die JsonTextReader-Klasse verwendet, um die JSON-Textdarstellung 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 JsonTextReader-Klasse in Jayrock ist ein recht liberaler JSON-Textparser. Es erlaubt tatsächlich viel mehr Syntax, als gemäß den Regeln in RFC 4627 als gültiger JSON-Text betrachtet wird. Mit der JsonTextReader-Klasse können beispielsweise einzeilige und mehrzeilige Kommentare im JSON-Text angezeigt werden, wie Sie es in JavaScript erwarten würden. Einzeilige Kommentare beginnen mit schrägstrichen (//) und mehrzeiligen Kommentaren mit slash-star (/*) und enden mit star-schrägstrich (*/). Einzeilige Kommentare können sogar mit dem Hash-/Pfundzeichen (#) beginnen, das bei Konfigurationsdateien im Unix-Stil üblich ist. In allen Instanzen werden die Kommentare vom Parser vollständig übersprungen und nie über die API verfügbar gemacht. Ebenso wie in JavaScript erlaubt JsonTextReader , dass eine JSON-Zeichenfolge durch einen Apostroph (') getrennt wird. Der Parser kann sogar ein zusätzliches Komma nach dem letzten Element eines Objekts oder Elements eines Arrays tolerieren.
Auch mit all diesen Ergänzungen ist JsonTextReader ein konformer Parser! JsonTextWriter hingegen erzeugt nur streng standardkonformen JSON-Text. Dies folgt dem, was oft als Robustitätsprinzip geprägt wird, das besagt: "Seien Sie bei dem, was Sie tun, konservativ; Seien Sie liberal in dem, was Sie von anderen akzeptieren."
Um JSON-Text direkt in ein .NET-Objekt zu konvertieren, verwenden Sie die Importmethode der JsonConvert-Klasse , indem Sie den Ausgabetyp und den JSON-Text angeben. 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);
Hier ist ein interessanteres Beispiel für die Konvertierung, die einen RSS-XML-Feed verwendet, ihn mithilfe von XmlSerializer in einen .NET-Typ deserialisiert und das Objekt dann mithilfe von JsonConvert in JSON-Text konvertiert (effektiv rss in XML in JSON-Text konvertiert):
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 den zugehörigen Typen finden Sie in den Beispielen zu diesem Artikel.
Verwenden von JSON in ASP.NET
Nachdem Sie sich mit Möglichkeiten zum Arbeiten mit JSON in JavaScript und innerhalb der .NET Framework mit Jayrock beschäftigt haben, ist es an der Zeit, sich einem praktischen Beispiel zu zuwenden, wo und wie all dieses Wissen angewendet werden kann. Betrachten Sie die Clientskriptrückruffunktion in ASP.NET 2.0, die den Prozess des Ausführens von Out-of-Band-Aufrufen vom Webbrowser an die ASP.NET-Seite (oder ein bestimmtes Steuerelement auf der Seite) vereinfacht. Während eines typischen Rückrufszenarios paketiert das clientseitige Skript im Browser und sendet Daten zur Verarbeitung durch eine serverseitige Methode zurück an den Webserver. Nach dem Empfang der Antwortdaten vom Server verwendet der Client diese, um die Browseranzeige zu aktualisieren.
Hinweis Weitere Informationen finden Sie im MSDN Magazine-Artikel Skriptrückrufe in ASP.NET 2.0.
Die Herausforderung in einem Clientrückrufszenario besteht darin, dass Client und Server nur eine Zeichenfolge hin und her versenden können. Daher müssen die auszutauschenden Informationen vor dem Senden von einer nativen Darstellung im Arbeitsspeicher in eine Zeichenfolge konvertiert und dann von einer Zeichenfolge zurück in die native, in-Memory-Darstellung analysiert werden, wenn sie empfangen wird. Das Clientskriptrückruffeature in ASP.NET 2.0 erfordert kein bestimmtes Zeichenfolgenformat für die ausgetauschten Daten und bietet auch keine integrierte Funktionalität für die Konvertierung zwischen den nativen In-Memory- und Zeichenfolgendarstellungen. es liegt am Entwickler, die Konvertierungslogik basierend auf einem von ihm gewählten Datenaustauschformat zu implementieren.
Im folgenden Beispiel wird veranschaulicht, wie JSON als Datenaustauschformat in einem Clientskriptrückrufszenario verwendet wird. Insbesondere besteht das Beispiel aus einer ASP.NET Seite, die Daten aus der Northwind-Datenbank verwendet, um eine Auflistung der Kategorien in einer Dropdownliste bereitzustellen. Produkte in der ausgewählten Kategorie werden in einer Aufzählung angezeigt (siehe Abbildung 3). Wenn die Dropdownliste auf der Clientseite geändert wird, wird ein Rückruf in einem Array übergeben, dessen einzelnes Element die ausgewählte CategoryID ist.
Hinweis Wir übergeben ein Array, das die ausgewählte CategoryID als einziges Element (und nicht nur die CategoryID) enthält, da der JSON-Standard erfordert, dass jeder JSON-Text ein Objekt oder ein Array als Stamm aufweisen muss. Natürlich muss der Client keinen JSON-Text an den Server übergeben. In diesem Beispiel hätte nur die ausgewählte CategoryID als Zeichenfolge übergeben werden können. Wir wollten jedoch das Senden von JSON-Text in den Anforderungs- und Antwortnachrichten des Rückrufs veranschaulichen.
Der folgende Code im Page_Load-Ereignishandler konfiguriert das DropDownList-Websteuerelement Kategorien so, dass die GetProductsForCategory-Funktion beim Ändern aufgerufen und den ausgewählten Dropdownlistenwert übergeben wird. Diese Funktion initiiert den Clientskriptrückruf, wenn der übergebene Dropdownlistenwert größer als 0 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 GetCallBackEventReference-Methode in der ClientScriptManager-Klasse , mit der der JavaScript-Code generiert wird, der den Rückruf aufruft, weist die folgende Signatur auf:
public string GetCallbackEventReference (
Control control,
string argument,
string clientCallback,
string context,
)
Der Argumentparameter gibt an, welche Daten während des Rückrufs vom Client an den Webserver gesendet werden, und der clientCallback-Parameter gibt den Namen der clientseitigen Funktion an, die nach Abschluss des Rückrufs (showProducts) aufgerufen werden soll. Der Aufruf der GetCallBackEventReference-Methode generiert den 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 des 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ückgibt.
Auf der Serverseite verwendet die Methode, die als Reaktion auf den Rückruf ausgeführt wird, die JsonConvert-Klasse von Jayrock, um den eingehenden JSON-Text zu analysieren und den ausgehenden JSON-Text zu formatieren. Insbesondere werden die Namen der Produkte, die der ausgewählten Kategorie 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 client
return JsonConvert.ExportToString(productNames);
Hinweis Die JsonConvert-Klasse wird zweimal verwendet– einmal, um den JSON-Text in eventArgument in ein Array von ganzen Zahlen zu konvertieren und dann das Zeichenfolgenarray productNames in JSON-Text zu konvertieren, um an den Client zurückzukehren. Alternativ hätten wir hier die JsonReader- und JsonWriter-Klassen verwenden können, aber JsonConvert erledigt die gleiche Aufgabe ziemlich gut, wenn die beteiligten Daten relativ klein sind und problemlos vorhandenen Typen zugeordnet werden können.
Wenn die Daten von der Serverseite zurückgegeben werden, wird die von der GetCallBackEventReference-Methode angegebene JavaScript-Funktion aufgerufen und der Rückgabewert übergeben. Diese JavaScript-Methode showProducts verweist zunächst auf das <div-Element>ProductOutput. Anschließend wird die JSON-Antwort analysiert und dynamisch eine ungeordnete Liste mit einem Listenelement für jedes Arrayelement hinzugefügt. Wenn für die ausgewählte Kategorie keine Produkte zurückgegeben werden, wird stattdessen eine entsprechende Meldung 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 veranschaulicht die Abfolge der Ereignisse, während Abbildung 3 dieses Beispiel in Aktion zeigt. Der vollständige Code ist in diesem Artikel-Download enthalten.
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 Aufzählungsliste innerhalb der ausgewählten Kategorie angezeigt.
Zusammenfassung
JSON ist ein einfaches, textbasiertes Datenaustauschformat, das auf einer Teilmenge der Literalnotation aus der Programmiersprache JavaScript basiert. Es bietet eine prägnante Codierung für Anwendungsdatenstrukturen und wird in der Regel in Szenarien verwendet, in denen eine JavaScript-Implementierung für eine oder beide Anwendungen verfügbar ist, die Daten austauschen, z. B. in Webanwendungen im Ajax-Stil. Der Reiz von JSON liegt in seiner Einfachheit zu verstehen, zu übernehmen und zu implementieren. JSON hat praktisch keine Lernkurve für Entwickler, die bereits mit JavaScript oder anderen Programmiersprachen mit ähnlicher Unterstützung für eine umfassende Literalnotation (wie Python und Ruby) vertraut sind. Das Analysieren von JSON-Text in JavaScript-Code kann einfach durch Aufrufen der eval-Funktion erreicht werden, und das Erstellen von JSON-Text ist ein Kinderspiel mit dem json.js Skripts, das unter http://www.json.org/json.jsbereitgestellt wird.
Es gibt eine blühende Anzahl von Bibliotheken für die Arbeit mit JSON auf allen wichtigen Plattformen und Frameworks. In diesem Artikel haben wir Uns mit Jayrock befasst, einer Open-Source-Bibliothek zum 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-Funktionen, jedoch nur für ASP.NET 2.0-Anwendungen.
Viel Spaß beim Programmieren!
Referenzen
- ASP.NET AJAX
- Clientseitige Webdienstaufrufe mit AJAX-Erweiterungen
- Core JavaScript 1.5-Leitfaden
- eval(expr)-Funktion
- Jayrock
- JSON.org
- Skriptrückrufe in ASP.NET
- RFC 4627
Ajax oder AJAX?
Der Begriff Ajax wurde ursprünglich von Jesse James Garrett geprägt, um den Stil von Webanwendungen und einer Reihe von Technologien zu beschreiben, die an der Erstellung von hochgradig interaktiven Webanwendungen beteiligt sind. In der Vergangenheit verbreitete sich der Begriff Ajax im Web als Das Akronym AJAX, was asynchrones JavaScript und XML bedeutet. Mit der Zeit erkannten die Menschen jedoch, dass das "X" in AJAX nicht sehr repräsentativ für das zugrunde liegende Datenformat war, das für die Kommunikation mit dem Webserver im Hintergrund verwendet wird, da die meisten Implementierungen zu JSON als einfachere und effizientere Alternative wechselten. Anstatt also ein Ersatz akronym wie AJAJ zu finden, das ein bisschen Zungenbrecher ist, wird das Akronym im Allgemeinen zugunsten von Ajax anstelle von AJAX das Akronym eingestellt.
Erwarten Sie zum Zeitpunkt dieses Schreibens, dass eine gemischte und breite Verwendung von "AJAX" und "Ajax" ein und dasselbe bedeutet. In diesem Artikel haben wir uns mit "Ajax the term" (Ajax, dem Begriff) befasst. Kommerzielle Produkte, die Frameworks bereitstellen, die Anwendungen im Ajax-Stil ermöglichen, verwenden jedoch in der Regel das Akronymformular, um sich von einem ähnlich benannten Reinigungsmittelprodukt zu unterscheiden und potenzielle Marken- oder Rechtsstreitigkeiten zu vermeiden.
ASP.NET AJAX: In JSON-Datums- und Uhrzeitzeichenfolge
Der AJAX JSON-Serialisierer in ASP.NET codiert eine DateTime-instance als JSON-Zeichenfolge. Während der Vorabveröffentlichungszyklen verwendete ASP.NET AJAX das Format "@ticks@", wobei Ticks die Anzahl von Millisekunden seit dem 1. Januar 1970 in der koordinierten Weltzeit (UTC) darstellt. Ein Datum und eine Uhrzeit in UTC wie der 29. November 1989, 4:55:30 Uhr, würde als "@62831853071@" geschrieben werden. Obwohl dieses Format einfach und einfach ist, kann dieses Format nicht zwischen einem serialisierten Datums- und Uhrzeitwert und einer Zeichenfolge unterscheiden, die wie ein serialisiertes Datum aussieht, aber nicht als deserialisiert werden soll. Daher hat das ASP.NET AJAX-Team eine Änderung für das endgültige Release vorgenommen, um dieses Problem zu beheben, indem das Format "\/Date(ticks)\/" übernommen wurde.
Das neue Format basiert auf einem kleinen Trick, um die Wahrscheinlichkeit von Fehlinterpretationen zu verringern. In JSON kann ein Schrägstrich (/)-Zeichen in einer Zeichenfolge mit einem umgekehrten Schrägstrich (\) mit Escapezeichen versehen werden, obwohl er nicht unbedingt erforderlich ist. Aus diesem Vorteil hat das ASP.NET AJAX-Team JavaScriptSerializer geändert, um stattdessen eine DateTime-instance als Zeichenfolge "\/Date(ticks)\/" zu schreiben. Die Entweichung der beiden Schrägstriche ist oberflächlich, aber für JavaScriptSerializer von Bedeutung. Nach JSON-Regeln
"
ist \/Date(ticks)\/"
technisch gleichwertig"
mit /Date(ticks)/,"
aber der JavaScriptSerializer deserialisiert erstere als DateTime und letzteres als Zeichenfolge. Die Chancen auf Mehrdeutigkeiten sind daher im Vergleich zum einfacheren "@ticks@"-Format aus den Vorabversionen deutlich geringer.
Herzlichen Dank
Bevor wir diesen Artikel an MSDN übermittelten, hatten wir eine Reihe von Freiwilligen, die beim Korrekturlesen des Artikels helfen und Feedback zu Inhalt, Grammatik und Richtung geben. Zu den Wichtigsten Mitwirkenden am Überprüfungsprozess gehören Douglas Crockford, Eric Schönholzer und Milan Negovan.
Über die Autoren
Atif Aziz ist Principal Consultant bei Skybow AG, wo sein Hauptaugenmerk darauf liegt, Kunden dabei zu helfen, Lösungen auf der .NET-Entwicklungsplattform zu verstehen und zu entwickeln. Atif trägt regelmäßig zur Microsoft-Entwicklercommunity bei, indem er auf Konferenzen spricht und Artikel für technische Publikationen schreibt. Er ist INETA-Referent und Präsident der grössten Schweizer .NET User Group. Er kann unter atif.aziz@skybow.com oder über seine Website unter http://www.raboof.comerreicht werden.
Scott Mitchell, Autor von sechs ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Er ist unter mitchell@4guysfromrolla.com oder über seinen Blog zu erreichen: http://ScottOnWriting.net.