Wprowadzenie do notacji obiektów JavaScript (JSON) w językach JavaScript i .NET

 

Wprowadzenie do notacji obiektów JavaScript (JSON) w językach JavaScript i .NET

Atif Aziz, Scott Mitchell

Luty 2007 r.

Dotyczy:
   JSON
   AJAX

Krótki opis: W tym artykule omówiono javaScript Object Notation (lub JSON), otwarty i tekstowy format wymiany danych, który zapewnia ustandaryzowany format wymiany danych lepiej odpowiedni dla aplikacji internetowych w stylu Ajax. (22 drukowane strony)

Zawartość

Wprowadzenie
Opis notacji literału w języku JavaScript
Porównywanie danych JSON z XML
Tworzenie i analizowanie komunikatów JSON za pomocą języka JavaScript
Praca z plikiem JSON w .NET Framework
Podsumowanie
Odwołania

Pobierz kod źródłowy tego artykułu.

Wprowadzenie

Podczas projektowania aplikacji, która będzie komunikować się z komputerem zdalnym, należy wybrać format danych i protokół wymiany. Istnieje wiele otwartych, ustandaryzowanych opcji, a idealny wybór zależy od wymagań aplikacji i wstępnie istniejących funkcji. Na przykład usługi internetowe oparte na protokole SOAP sformatuj dane w ładunku XML opakowanym w kopercie protokołu SOAP.

Chociaż kod XML działa dobrze w przypadku wielu scenariuszy aplikacji, ma pewne wady, które sprawiają, że jest mniej niż idealny dla innych. Jednym z takich miejsc, w których język XML jest często mniej niż idealny, jest użycie aplikacji internetowych w stylu Ajax. Ajax jest techniką służącą do tworzenia interaktywnych aplikacji internetowych, które zapewniają szybkie środowisko użytkownika dzięki użyciu out-of-band, lekkich wywołań do serwera internetowego zamiast ogłaszania zwrotnego na pełnej stronie. Te wywołania asynchroniczne są inicjowane na kliencie przy użyciu języka JavaScript i obejmują formatowanie danych, wysyłanie ich do serwera internetowego oraz analizowanie i pracę z zwracanymi danymi. Chociaż większość przeglądarek może tworzyć, wysyłać i analizować kod XML, javaScript Object Notation (lub JSON) zapewnia standardowy format wymiany danych, który jest lepiej dostosowany do aplikacji internetowych w stylu Ajax.

Format JSON to otwarty format wymiany danych oparty na tekście (zobacz RFC 4627). Podobnie jak kod XML, jest czytelny dla człowieka, niezależny od platformy i cieszy się szeroką dostępnością implementacji. Dane sformatowane zgodnie ze standardem JSON są lekkie i mogą być analizowane przez implementacje języka JavaScript z niesamowitą łatwością, dzięki czemu jest to idealny format wymiany danych dla aplikacji internetowych Ajax. Ponieważ jest to przede wszystkim format danych, format JSON nie jest ograniczony tylko do aplikacji internetowych Ajax i może być używany w praktycznie dowolnym scenariuszu, w którym aplikacje muszą wymieniać lub przechowywać informacje ustrukturyzowane jako tekst.

W tym artykule omówiono standard JSON, jego relację z językiem JavaScript oraz sposób porównywania z językiem XML. Firma Jayrock, implementacja JSON typu open source dla platformy .NET, została omówiona, a przykłady tworzenia i analizowania komunikatów JSON są dostępne w językach JavaScript i C#.

Opis notacji literału w języku JavaScript

Literały są używane w językach programowania do dosłownie wyrażania wartości stałych, takich jak stała wartość całkowita 4 lub ciąg "Hello, World". Literały mogą być używane w większości języków wszędzie tam, gdzie jest dozwolone wyrażenie, takie jak część warunku w instrukcji sterującej, parametr wejściowy podczas wywoływania funkcji, przypisania zmiennej itd. Na przykład poniższy kod w językach C# i Visual Basic inicjuje zmienną x ze stałą liczbą całkowitą 42.

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

Różne języki programowania umożliwiają obsługę literałów różnych typów. Większość języków programowania obsługuje co najmniej literały dla typów skalarnych, takich jak liczby całkowite, liczby zmiennoprzecinkowe, ciągi i wartość logiczna. Co ciekawe w języku JavaScript, oprócz typów skalarnych, obsługuje również literały dla typów strukturalnych, takich jak tablice i obiekty. Ta funkcja umożliwia tworzenie i inicjowanie tablic i obiektów przy użyciu terse składni na żądanie.

Literały tablicowe w języku JavaScript składają się z zera lub większej liczby wyrażeń, a każde wyrażenie reprezentuje element tablicy. Elementy tablicy są ujęte w nawiasy kwadratowe ([]) i rozdzielane przecinkami. W poniższym przykładzie zdefiniowano tablicę dosłownie z siedmioma elementami ciągu zawierającymi nazwy siedmiu kontynentów:

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

Porównaj to teraz, aby dowiedzieć się, jak utworzyć i zainicjować tablicę w języku JavaScript bez notacji literału:

  
    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";
  

Literał obiektu definiuje elementy członkowskie obiektu i ich wartości. Lista elementów członkowskich i wartości obiektu jest ujęta w nawiasy klamrowe ({}), a każdy element członkowski jest rozdzielany przecinkami. W obrębie każdego elementu członkowskiego nazwa i wartość są rozdzielane dwukropkiem (:). Poniższy przykład tworzy obiekt i inicjuje go z trzema elementami członkowskimi o nazwach Address, City i PostalCode z odpowiednimi wartościami "123 Anywhere St.", "Springfield" i "99999".

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

Przedstawione do tej pory przykłady ilustrują użycie literałów ciągów i liczbowych w literałach tablicy i obiektów. Można również wyrazić cały graf przy użyciu notacji rekursywnie, tak aby elementy tablicy i wartości składowych obiektu mogły się z kolei używać literałów obiektu i tablicy. Na przykład poniższy fragment kodu ilustruje obiekt, który ma tablicę jako element członkowski (PhoneNumbers), gdzie tablica składa się z listy obiektów.

  
    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);
}
  

Uwaga Bardziej szczegółowe omówienie obsługi literałów dla języka JavaScript można znaleźć w przewodniku Core JavaScript 1.5 w sekcji Literały.

Od literałów języka JavaScript do formatu JSON

JSON to format wymiany danych utworzony na podstawie podzestawu notacji obiektów literału w języku JavaScript. Chociaż składnia akceptowana przez język JavaScript dla wartości literałów jest bardzo elastyczna, należy pamiętać, że kod JSON ma znacznie bardziej rygorystyczne reguły. Zgodnie ze standardem JSON, na przykład nazwa elementu członkowskiego obiektu musi być prawidłowym ciągiem JSON. Ciąg w formacie JSON musi być ujęta w znaki cudzysłowu. Z drugiej strony język JavaScript umożliwia rozdzielanie nazw elementów członkowskich obiektów za pomocą cudzysłowów lub apostrofów albo pomijanie cudzysłowu, o ile nazwa elementu członkowskiego nie powoduje konfliktu z zastrzeżonym słowem kluczowym JavaScript. Podobnie wartość elementu tablicy lub elementu członkowskiego obiektu w formacie JSON jest ograniczona do bardzo ograniczonego zestawu. Jednak w języku JavaScript elementy tablicy i wartości elementów członkowskich obiektu mogą odwoływać się do prawie każdego prawidłowego wyrażenia Języka JavaScript, w tym wywołań funkcji i definicji.

Urok kodu JSON jest w swojej prostoty. Komunikat sformatowany zgodnie ze standardem JSON składa się z pojedynczego obiektu lub tablicy najwyższego poziomu. Elementy tablicy i wartości obiektów mogą być obiektami, tablicami, ciągami, liczbami, wartościami logicznymi (true i false) lub wartościami null. To, w skrócie, jest standardem JSON! To naprawdę takie proste. Aby uzyskać bardziej formalny opis standardu, zobacz www.json.org lub RFC 4627 .

Jednym z ponowień kodu JSON jest brak literału daty/godziny. Wiele osób jest zaskoczonych i rozczarowanych, aby dowiedzieć się tego, gdy po raz pierwszy napotkają kod JSON. Prostym wyjaśnieniem (pocieszającym lub nie) braku literału daty/godziny jest to, że język JavaScript nigdy nie miał jednego z następujących elementów: obsługa wartości daty i godziny w języku JavaScript jest całkowicie udostępniana za pośrednictwem obiektu Date . W związku z tym większość aplikacji używających formatu JSON jako formatu danych zwykle używa ciągu lub liczby do wyrażania wartości daty i godziny. Jeśli jest używany ciąg, ogólnie można oczekiwać, że będzie on w formacie ISO 8601. Jeśli jest używana liczba, zamiast tego wartość jest zwykle przyjmowana jako liczba milisekund w uniwersalnym czasie koordynowanym (UTC) od epoki, gdzie epoka jest zdefiniowana jako północ 1 stycznia 1970 (UTC). Ponownie jest to zwykła konwencja, a nie część standardu JSON. Jeśli wymieniasz dane z inną aplikacją, musisz sprawdzić jego dokumentację, aby zobaczyć, jak koduje wartości daty i godziny w literale JSON. Na przykład ASP.NET AJAX firmy Microsoft nie używa żadnej z opisanych konwencji. Zamiast tego koduje wartości daty /godziny platformy .NET jako ciąg JSON, gdzie zawartość ciągu to \/Date(ticks)\/ i gdzie znaczniki reprezentują milisekundy od epoki (UTC). Tak więc 29 listopada 1989, 4:55:30 w formacie UTC jest zakodowany jako "\/Date(628318530718)\/". Aby zapoznać się z pewnym uzasadnieniem tego raczej przemyślanego wyboru kodowania, zobacz "Inside ASP.NET AJAX's JSON date and time string" (Wewnątrz ciągu daty i godziny AJAX).

Porównywanie danych JSON z XML

Zarówno format JSON, jak i XML mogą służyć do reprezentowania natywnych obiektów w pamięci w formacie wymiany danych opartym na tekście i czytelnym dla człowieka. Ponadto dwa formaty wymiany danych są izomorficzne — biorąc pod uwagę tekst w jednym formacie, równoważny jest w drugim. Na przykład podczas wywoływania jednej z publicznie dostępnych usług sieci Web yahoo!, można wskazać za pomocą parametru querystring, czy odpowiedź powinna być sformatowana jako XML lub JSON. W związku z tym przy podejmowaniu decyzji o formacie wymiany danych nie jest to prosta kwestia wyboru jednej nad drugą jako srebra kula, ale format ma cechy , które sprawiają, że jest to najlepszy wybór dla określonej aplikacji. Na przykład kod XML ma swoje korzenie w tekście dokumentu oznaczania i ma tendencję do bardzo dobrego blasku w tym obszarze (co jest widoczne w przypadku języka XHTML). Z drugiej strony kod JSON ma swoje korzenie w typach i strukturach języka programowania, a zatem zapewnia bardziej naturalne i łatwo dostępne mapowanie na potrzeby wymiany danych strukturalnych. Poza tymi dwoma punktami wyjścia poniższa tabela pomoże Ci zrozumieć i porównać kluczowe cechy kodu XML i JSON.

Kluczowe różnice charakterystyki między xml i JSON

Charakterystyka XML JSON
Typy danych Nie zawiera żadnego pojęcia typów danych. Należy polegać na schemacie XML w celu dodawania informacji o typie. Zapewnia skalarne typy danych i możliwość wyrażania danych strukturalnych za pośrednictwem tablic i obiektów.
Obsługa tablic Tablice muszą być wyrażane przez konwencje, na przykład za pomocą zewnętrznego elementu zastępczego, który modeluje zawartość tablic jako elementy wewnętrzne. Zazwyczaj element zewnętrzny używa formy mnogiej nazwy używanej dla elementów wewnętrznych. Obsługa macierzy natywnej.
Obsługa obiektów Obiekty muszą być wyrażane przez konwencje, często poprzez mieszane użycie atrybutów i elementów. Obsługa obiektów natywnych.
Obsługa wartości null Wymaga użycia elementu xsi:nil dla elementów w dokumencie wystąpienia XML oraz importowania odpowiedniej przestrzeni nazw. Natywnie rozpoznaje wartość null .
Komentarze Natywna obsługa i zwykle dostępna za pośrednictwem interfejsów API. Nieobsługiwane.
Przestrzenie nazw Obsługuje przestrzenie nazw, co eliminuje ryzyko kolizji nazw podczas łączenia dokumentów. Przestrzenie nazw umożliwiają również bezpieczne rozszerzanie istniejących standardów opartych na formacie XML. Brak koncepcji przestrzeni nazw. Kolizje nazewnictwa są zwykle unikane przez zagnieżdżanie obiektów lub używanie prefiksu w nazwie elementu członkowskiego obiektu (poprzednie jest preferowane w praktyce).
Decyzje dotyczące formatowania Złożonych. Wymaga większego nakładu pracy, aby zdecydować, jak mapować typy aplikacji na elementy i atrybuty XML. Może tworzyć gorące debaty, czy podejście skoncentrowane na elementach lub atrybutów jest lepsze. Proste. Zapewnia znacznie bardziej bezpośrednie mapowanie danych aplikacji. Jedynym wyjątkiem może być brak literału daty/godziny.
Rozmiar Dokumenty zwykle mają długi rozmiar, zwłaszcza gdy używane jest podejście skoncentrowane na elementach do formatowania. Składnia jest bardzo terse i zwraca sformatowany tekst, w którym większość miejsca jest zużywana (słusznie) przez reprezentowane dane.
Analizowanie w języku JavaScript Wymaga implementacji MODELU DOM XML i dodatkowego kodu aplikacji do mapowania tekstu z powrotem na obiekty JavaScript. Nie jest wymagany dodatkowy kod aplikacji do analizowania tekstu; może używać funkcji eval języka JavaScript.
Krzywa uczenia Zwykle wymaga użycia kilku technologii w koncercie: XPath, XML Schema, XSLT, XML Namespaces, DOM itd. Bardzo prosty stos technologii, który jest już znany deweloperom z doświadczeniem w języku JavaScript lub w innych językach programowania dynamicznego.

Format JSON jest stosunkowo nowym formatem wymiany danych i nie ma lat wdrażania ani obsługi dostawcy, który obecnie cieszy się formatem XML (chociaż kod JSON szybko nadrabia zaległości). W poniższej tabeli przedstawiono bieżący stan spraw w przestrzeniach XML i JSON.

Obsługa różnic między xml i JSON

Pomoc techniczna XML JSON
narzędzia Cieszy się dojrzałym zestawem narzędzi szeroko dostępnych od wielu dostawców branżowych. Rozbudowana obsługa narzędzi, takich jak edytory i formatery, jest rzadka.
Microsoft .NET Framework Bardzo dobra i dojrzała obsługa od wersji 1.0 .NET Framework. Obsługa kodu XML jest dostępna w ramach biblioteki klas bazowych (BCL). W przypadku środowisk niezarządzanych istnieje program MSXML. Brak do tej pory, z wyjątkiem początkowej implementacji w ramach ASP.NET AJAX.
Platforma i język Analizatory i formatatory są szeroko dostępne na wielu platformach i językach (implementacje komercyjne i open source). Analizatory i formatatory są już dostępne na wielu platformach i w wielu językach. Zapoznaj się z json.org , aby uzyskać dobry zestaw odwołań. Większość implementacji na razie zwykle jest open source projektów.
Zintegrowany język Dostawcy branżowi obecnie eksperymentują z obsługą dosłownie w językach. Aby uzyskać więcej informacji, zobacz projekt LINQ firmy Microsoft . Jest natywnie obsługiwany tylko w języku JavaScript/ECMAScript.

Uwaga Żadna tabela nie ma być kompleksową listą punktów porównania. Istnieją dalsze kąty, dla których można porównać oba formaty danych, ale uważamy, że te kluczowe punkty powinny wystarczyć do utworzenia początkowego wrażenia.

Tworzenie i analizowanie komunikatów JSON za pomocą języka JavaScript

W przypadku używania formatu JSON jako formatu wymiany danych dwa typowe zadania przekształcają reprezentację natywną i w pamięci w reprezentację tekstu w formacie JSON i na odwrót. Niestety w momencie pisania skrypt JavaScript nie udostępnia wbudowanych funkcji do tworzenia tekstu JSON na podstawie danego obiektu lub tablicy. Oczekuje się, że te metody zostaną uwzględnione w czwartej edycji standardu ECMAScript w 2007 roku. Dopóki te funkcje formatowania JSON nie zostaną formalnie dodane do języka JavaScript i są szeroko dostępne w wielu popularnych implementacjach, użyj skryptu implementacji referencyjnej dostępnego do pobrania na stronie http://www.json.org/json.js.

W najnowszej iteracji w momencie pisania tego tekstu skrypt json.js w www.json.org dodaje funkcje toJSONString() do tablicy, ciągu, wartości logicznej, obiektu i innych typów języka JavaScript. Funkcje toJSONString() dla typów skalarnych (takich jak Liczba i Wartość logiczna) są dość proste, ponieważ muszą zwracać tylko ciąg reprezentujący wartość wystąpienia. Funkcja toJSONString() dla typu logicznego , na przykład zwraca ciąg "true", jeśli wartość jest prawdziwa, a w przeciwnym razie wartość "false". Bardziej interesujące są funkcje toJSONString() dla typów Array i Object. W przypadku wystąpień tablicy funkcja toJSONString() dla każdego zawartego elementu jest wywoływana w sekwencji, a wyniki są łączone przecinkami, aby rozdzielić każdy wynik. Końcowe dane wyjściowe ujęte w nawiasy kwadratowe. Podobnie w przypadku wystąpień obiektów każdy element członkowski jest wyliczany i wywoływana jest jego funkcja toJSONString(). Nazwa elementu członkowskiego i reprezentacja jej wartości w formacie JSON są łączone dwukropkiem w środku; każda nazwa elementu członkowskiego i para wartości są rozdzielane przecinkami, a całe dane wyjściowe są ujęte w nawiasy klamrowe.

Wynikiem net funkcji toJSONString() jest to, że dowolny typ można przekonwertować na format JSON za pomocą pojedynczego wywołania funkcji. Poniższy kod JavaScript tworzy obiekt Array i dodaje siedem elementów String celowo przy użyciu metody pełnej i niesłownej do celów ilustracyjnych. Następnie zostanie wyświetlona reprezentacja JSON tablic:

  
    // 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());
  

Bb299886.intro_to_json01(en-us,MSDN.10).gifBb299886.intro_to_json01

Rysunek 1. Funkcja toJSONString() emituje tablicę sformatowaną zgodnie ze standardem JSON.

Analizowanie tekstu JSON jest jeszcze prostsze. Ponieważ kod JSON jest tylko podzbiorem literałów języka JavaScript, można go przeanalizować w reprezentacji w pamięci przy użyciu funkcji , eval(expr)traktując źródłowy tekst JSON jako kod źródłowy JavaScript. Funkcja eval przyjmuje jako dane wejściowe ciąg prawidłowego kodu JavaScript i ocenia wyrażenie. W związku z tym poniższy pojedynczy wiersz kodu jest potrzebny do przekształcenia tekstu JSON w natywną reprezentację:

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

Uwaga Dodatkowe nawiasy są używane sprawiają, że eval bezwarunkowo traktuj dane wejściowe źródła jak wyrażenie. Jest to szczególnie ważne w przypadku obiektów. Jeśli spróbujesz wywołać eval z ciągiem zawierającym tekst JSON, który definiuje obiekt, taki jak ciąg "{}" (czyli pusty obiekt), po prostu zwraca niezdefiniowany jako przeanalizowany wynik. Nawiasy wymuszają analizator języka JavaScript, aby zobaczyć nawiasy klamrowe najwyższego poziomu jako notację literału dla wystąpienia obiektu, a nie nawiasy klamrowe definiujące blok instrukcji. Nawiasem mówiąc, ten sam problem nie występuje, jeśli element najwyższego poziomu jest tablicą, jak w eval("[1,2,3]"). Ze względu na jednolitość należy jednak zawsze otaczać tekst JSON nawiasami przed wywołaniem eval , aby nie było wątpliwości co do sposobu interpretowania źródła.

Podczas obliczania notacji literału wystąpienie odpowiadające składni literału jest zwracane i przypisywane do wartości. Rozważmy poniższy przykład, który używa funkcji eval do analizowania notacji literału dla tablicy i przypisywania wynikowej tablicy do zmiennych kontynentów.

  
    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.");
  

Oczywiście, w praktyce oceniany tekst JSON będzie pochodzić z jakiegoś zewnętrznego źródła, a nie jest zakodowany w powyższym przypadku.

Funkcja eval w sposób ślepy ocenia dowolne wyrażenie, które jest przekazywane. Niezaufane źródło może zatem obejmować potencjalnie niebezpieczny kod JavaScript wraz z notacją literału lub mieszaną w notację literału, która składa się na dane JSON. W scenariuszach, w których źródło nie może być zaufane, zdecydowanie zaleca się analizowanie tekstu JSON przy użyciu funkcji parseJSON() (znajdującej się w json.js):

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

Funkcja parseJSON() używa również wartości eval, ale tylko wtedy, gdy ciąg zawarty w arrayAsJSONText jest zgodny ze standardem tekstu JSON. Robi to przy użyciu sprytnego testu wyrażeń regularnych.

Praca z plikiem JSON w .NET Framework

Tekst JSON można łatwo utworzyć i przeanalizować na podstawie kodu JavaScript, który jest częścią jego uroku. Jeśli jednak kod JSON jest używany w aplikacji internetowej ASP.NET, tylko przeglądarka korzysta z obsługi języka JavaScript, ponieważ kod po stronie serwera jest najprawdopodobniej napisany w języku Visual Basic lub C#.

Większość bibliotek Ajax przeznaczonych do ASP.NET zapewnia obsługę programowego tworzenia i analizowania tekstu JSON. W związku z tym, aby pracować z kodem JSON w aplikacji .NET, rozważ użycie jednej z tych bibliotek. Istnieje wiele opcji typu open source i innych firm, a firma Microsoft ma również własną bibliotekę Ajax o nazwie ASP.NET AJAX.

W tym artykule przyjrzymy się przykładom korzystającym z języka Jayrock, czyli implementacji kodu JSON typu open source dla .NET Framework firmy Microsoft utworzonej przez współautora Atif Aziz. Wybraliśmy opcję korzystania z Jayrock zamiast ASP.NET AJAX z trzech powodów:

  • Jayrock jest oprogramowaniem open source, co umożliwia rozszerzanie lub dostosowywanie w razie potrzeby.
  • Firma Jayrock może być używana w aplikacjach ASP.NET 1.x, 2.0 i Mono , natomiast ASP.NET AJAX jest przeznaczony tylko dla ASP.NET wersji 2.0.
  • Zakres Jayrocka jest ograniczony do formatu JSON i JSON-RPC, a pierwszy jest głównym celem tego artykułu. Chociaż ASP.NET AJAX obejmuje obsługę tworzenia i analizowania tekstu JSON, jej głównym celem jest oferowanie rozbudowanej platformy do tworzenia kompleksowej aplikacji internetowych w stylu Ajax w ASP.NET. Dodatkowe dzwony i gwizdki mogą rozpraszać, gdy głównym celem jest JSON.

Praca z formatem JSON na platformie .NET przy użyciu narzędzia Jayrock jest podobna do pracy z kodem XML za pomocą klas XmlWriter, XmlReader i XmlSerializer w .NET Framework. Klasy JsonWriter, JsonReader, JsonTextWriter i JsonTextReader znalezione w Jayrock naśladują semantyka klas .NET Framework XmlWriter, XmlReader, XmlTextWriter i XmlTextReader. Te klasy są przydatne do łączenia się z formatem JSON na poziomie niskim i zorientowanym na strumień. Przy użyciu tych klas tekst JSON można utworzyć lub przeanalizować fragmentarykę za pomocą serii wywołań metod. Na przykład użycie metody klasy JsonWriterWriteNumber(number) zapisuje odpowiednią reprezentację ciągu liczby zgodnie ze standardem JSON. Klasa JsonConvert oferuje metody eksportowania i importowania do konwertowania między typami platformy .NET i formatem JSON. Te metody zapewniają podobną funkcjonalność, jak znaleziono odpowiednio w metodach klasy XmlSerializerSerialize i Deserialize.

Tworzenie tekstu JSON

Poniższy kod ilustruje użycie klasy JsonTextWriter do utworzenia tekstu JSON dla tablicy ciągów kontynentów. Ten tekst JSON jest wysyłany do wystąpienia TextWriter przekazanego do konstruktora, który jest strumieniem wyjściowym z konsoli w tym przykładzie (w ASP.NET można użyć metody Response.Output ):

  
    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();
}
  

Oprócz metod WriteStartArray, WriteString i WriteEndArray klasa JsonWriter udostępnia metody pisania innych typów wartości JSON, takich jak WriteNumber, WriteBoolean, WriteNull itd. Metody WriteStartObject, WriteEndObject i WriteMember tworzą tekst JSON dla obiektu. Poniższy przykład ilustruje tworzenie tekstu JSON dla obiektu kontaktu badanego w sekcji "Opis notacji literału w języku JavaScript":

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();        //  }
}

Metody Export i ExportToString w klasie JsonConvert mogą służyć do serializacji określonego typu platformy .NET do tekstu JSON. Na przykład zamiast ręcznie tworzyć tekst JSON dla tablicy siedmiu kontynentów przy użyciu klasy JsonTextWriter , następujące wywołanie metody JsonConvert.ExportToString daje te same wyniki:

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

Analizowanie tekstu JSON

Klasa JsonTextReader udostępnia różne metody analizowania tokenów tekstu JSON z rdzeniem, który jest odczytywany. Za każdym razem, gdy metoda Read jest wywoływana, analizator używa następnego tokenu, który może być wartością ciągu, wartością liczbową, nazwą elementu członkowskiego obiektu, początkiem tablicy itd. Jeśli ma to zastosowanie, można uzyskać dostęp do przeanalizowanego tekstu bieżącego tokenu za pośrednictwem właściwości Text . Jeśli na przykład czytelnik znajduje się w danych logicznych, właściwość Text zwróci wartość "true" lub "false" w zależności od rzeczywistej wartości analizy.

Poniższy przykładowy kod używa klasy JsonTextReader do analizowania za pośrednictwem tekstowej reprezentacji JSON tablicy ciągów zawierającej nazwy siedmiu kontynentów. Każdy kontynent rozpoczynający się literą "A" jest wysyłany do konsoli:

  
    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);
        }
    }
}
  

Uwaga Klasa JsonTextReader w Jayrock jest dość liberalnym analizatorem tekstu JSON. W rzeczywistości dopuszcza o wiele więcej składni niż jest uważany za prawidłowy tekst JSON zgodnie z zasadami określonymi w RFC 4627. Na przykład klasa JsonTextReader umożliwia wyświetlenie komentarzy jednowierszowych i wielowierszowych w tekście JSON zgodnie z oczekiwaniami w języku JavaScript. Komentarze jednowierszowe zaczynają się od ukośnika (//) i komentarzy wielowierszowych z ukośnikami star (/*) i kończy się star ukośnikiem (*/). Komentarze jednowierszowe mogą nawet zaczynać się od znaku skrótu/funta (#), który jest często spotykany w plikach konfiguracji w stylu systemu Unix. We wszystkich wystąpieniach komentarze są całkowicie pomijane przez analizator i nigdy nie są udostępniane za pośrednictwem interfejsu API. Podobnie jak w języku JavaScript, element JsonTextReader zezwala na rozdzielenie ciągu JSON przez apostrof ('). Analizator może nawet tolerować dodatkowy przecinek po ostatnim elemencie obiektu lub elementu tablicy.

Nawet w przypadku wszystkich tych dodatków , JsonTextReader jest zgodny analizator! Z drugiej strony JsonTextWriter tworzy tylko rygorystyczny, zgodny ze standardami tekst JSON. Wynika to z tego, co jest często ukuwane jako podmiot zabezpieczeń, który stwierdza: "Bądź konserwatywny w tym, co robisz; bądź liberalny w tym, co akceptujesz od innych.

Aby przekonwertować tekst JSON bezpośrednio na obiekt .NET, użyj metody importowania klasy JsonConvert , określając typ danych wyjściowych i tekst JSON. W poniższym przykładzie pokazano konwersję tablicy ciągów JSON na tablicę ciągów platformy .NET:

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

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

Oto bardziej interesujący przykład konwersji, która przyjmuje źródło danych XML RSS, deserializuje go do typu .NET przy użyciu xmlSerializer, a następnie konwertuje obiekt na tekst JSON przy użyciu formatu JsonConvert (efektywnie konwertując rss w kodzie XML na tekst JSON):

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);

Uwaga Definicję richSiteSummary i jej powiązanych typów można znaleźć w przykładach towarzyszących temu artykułowi.

Używanie kodu JSON w ASP.NET

Po zapoznaniu się ze sposobami pracy z kodem JSON w języku JavaScript i z poziomu .NET Framework przy użyciu narzędzia Jayrock nadszedł czas, aby zwrócić się do praktycznego przykładu tego, gdzie i jak można zastosować całą tę wiedzę. Rozważ funkcję wywołania zwrotnego skryptu klienta w ASP.NET 2.0, która upraszcza proces wykonywania wywołań poza pasmem z przeglądarki internetowej do strony ASP.NET (lub do określonej kontrolki na stronie). Podczas typowego scenariusza wywołania zwrotnego skrypt po stronie klienta w pakietach przeglądarki i wysyła dane z powrotem do serwera internetowego w celu przetworzenia przez metodę po stronie serwera. Po otrzymaniu danych odpowiedzi z serwera klient użyje go do zaktualizowania ekranu przeglądarki.

Uwaga Więcej informacji można znaleźć w artykule MsdN Magazine Script Callbacks in ASP.NET 2.0 (Wywołania zwrotne skryptów w witrynie MSDN Magazine w ASP.NET 2.0).

Wyzwaniem w scenariuszu wywołania zwrotnego klienta jest to, że klient i serwer mogą dostarczać tylko ciąg tam iz powrotem. W związku z tym informacje do wymiany muszą zostać przekonwertowane z natywnej reprezentacji w pamięci na ciąg przed wysłaniem, a następnie przeanalizowane z ciągu z powrotem do jego natywnej reprezentacji w pamięci po odebraniu. Funkcja wywołania zwrotnego skryptu klienta w ASP.NET 2.0 nie wymaga określonego formatu ciągu dla wymienianych danych ani nie udostępnia żadnych wbudowanych funkcji konwersji między natywną reprezentacją w pamięci i ciągami; Deweloper musi zaimplementować logikę konwersji na podstawie wybranego formatu wymiany danych.

W poniższym przykładzie pokazano, jak używać formatu JSON jako formatu wymiany danych w scenariuszu wywołania zwrotnego skryptu klienta. W szczególności przykład składa się z strony ASP.NET, która używa danych z bazy danych Northwind do udostępnienia listy kategorii na liście rozwijanej; produkty w wybranej kategorii są wyświetlane na liście punktowanej (zobacz Rysunek 3). Za każdym razem, gdy lista rozwijana zostanie zmieniona po stronie klienta, wywołanie zwrotne jest przesyłane do tablicy, której pojedynczy element jest wybranym identyfikatorem CategoryID.

Uwaga Przekazujemy tablicę zawierającą wybrany identyfikator CategoryID jako jedyny element (a nie tylko Identyfikator kategorii), ponieważ standard JSON wymaga, aby dowolny tekst JSON miał obiekt lub tablicę jako element główny. Oczywiście klient nie jest wymagany do przekazania tekstu JSON na serwer — w tym przykładzie można przekazać tylko wybrany identyfikator CategoryID jako ciąg. Chcieliśmy jednak zademonstrować wysyłanie tekstu JSON zarówno w komunikatach żądania, jak i odpowiedzi wywołania zwrotnego.

Poniższy kod w programie obsługi zdarzeń Page_Load konfiguruje kontrolkę Sieci Web Categories DropDownList , tak aby po jej zmianie funkcja GetProductsForCategory została wywołana i przekazana wybrana wartość list rozwijanych. Ta funkcja inicjuje wywołanie zwrotne skryptu klienta, jeśli przekazana wartość listy rozwijanej jest większa niż zero:

  
    // 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);
  

Metoda GetCallBackEventReference w klasie ClientScriptManager , która służy do generowania kodu JavaScript, który wywołuje wywołanie zwrotne, ma następujący podpis:

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

Parametr argumentu określa, jakie dane są wysyłane z klienta do serwera internetowego podczas wywołania zwrotnego, a parametr clientCallback określa nazwę funkcji po stronie klienta, która ma zostać wywołana po zakończeniu wywołania zwrotnego (showProducts). Wywołanie metody GetCallBackEventReference generuje następujący kod JavaScript i dodaje go do renderowanego znacznika:

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

"[" + categoryID + "]" to wartość przekazywana do serwera podczas wywołania zwrotnego (tablica z pojedynczym elementem, categoryID) i showProducts jest funkcją Języka JavaScript wykonywaną po powrocie wywołania zwrotnego.

Po stronie serwera metoda wykonywana w odpowiedzi na wywołanie zwrotne używa klasy JsonConvert z jayrock do analizowania przychodzącego tekstu JSON i formatowania wychodzącego tekstu JSON. W szczególności nazwy produktów skojarzonych z wybraną kategorią są pobierane i zwracane jako tablica ciągów.

  
    // 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);

Uwaga Klasa JsonConvert jest używana dwa razy — raz, aby przekonwertować tekst JSON w obiekcie eventArgument na tablicę liczb całkowitych, a następnie przekonwertować tablicę ciągów productNames na tekst JSON, aby powrócić do klienta. Alternatywnie w tym miejscu moglibyśmy użyć klas JsonReader i JsonWriter , ale JsonConvert wykonuje to samo zadanie dość dobrze, gdy zaangażowane dane są stosunkowo małe i łatwo mapowane na istniejące typy.

Po zwróceniu danych po stronie serwera wywoływana jest funkcja JavaScript określona z metody GetCallBackEventReference i przekazana wartość zwracana. Ta metoda JavaScript , showProducts, rozpoczyna się od odwołania do <elementu div>ProductOutput. Następnie analizuje odpowiedź JSON i dynamicznie dodaje nieuporządkowaną listę z elementem listy dla każdego elementu tablicy. Jeśli dla wybranej kategorii nie zostaną zwrócone żadne produkty, zostanie wyświetlony odpowiedni komunikat.

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);
    }
}

Rysunek 2 ilustruje sekwencję zdarzeń, podczas gdy rysunek 3 przedstawia ten przykład w akcji; Kompletny kod znajduje się w tym artykule do pobrania.

Bb299886.intro_to_json02(en-us,MSDN.10).gif

Rysunek 2. Klient wysyła wybrany identyfikator CategoryID jako pojedynczy element w tablicy, a serwer zwraca tablicę skojarzonych nazw produktów.

Bb299886.intro_to_json03(en-us,MSDN.10).gif

Rysunek 3. Produkty są wyświetlane na liście punktowanej w wybranej kategorii.

Podsumowanie

JSON to lekki format wymiany danych oparty na tekście oparty na podzestawie notacji literału z języka programowania JavaScript. Zapewnia zwięzłe kodowanie struktur danych aplikacji i jest zwykle używany w scenariuszach, w których implementacja języka JavaScript jest dostępna dla jednej lub obu aplikacji wymieniających dane, takich jak w aplikacjach internetowych w stylu Ajax. Urok kodu JSON leży w jego prostotzie, aby zrozumieć, wdrożyć i wdrożyć. Format JSON nie ma praktycznie żadnej krzywej uczenia się dla deweloperów, którzy znają język JavaScript lub inne języki programowania z podobną obsługą rozbudowanej notacji literału (na przykład Python i Ruby). Analizowanie tekstu JSON w kodzie JavaScript można wykonać, po prostu wywołując funkcję eval , a tworzenie tekstu JSON jest proste dzięki skryptowi json.js dostarczonemu pod adresem http://www.json.org/json.js.

Istnieje kwitnąca liczba bibliotek do pracy z formatem JSON na wszystkich głównych platformach i platformach. W tym artykule opatrzyliśmy jayrock, bibliotekę open source do tworzenia i analizowania tekstu JSON w aplikacjach platformy .NET. Firma Jayrock może być używana w aplikacjach ASP.NET 1.x, 2.0 i Mono. ASP.NET AJAX oferuje podobne funkcje JSON, ale tylko w przypadku aplikacji ASP.NET 2.0.

Szczęśliwe programowanie!

Odwołania

Ajax czy AJAX?

Termin Ajax został początkowo ukuty przez Jesse'a Jamesa Garretta w celu opisania stylu aplikacji internetowych i zestawu technologii związanych z tworzeniem wysoce interaktywnych aplikacji internetowych. Historycznie termin Ajax rozprzestrzenił się wokół internetu jako akronim AJAX, co oznacza asynchroniczny kod JavaScript i XML. Jednak z czasem ludzie zdali sobie sprawę, że "X" w AJAX nie był bardzo reprezentatywny dla bazowego formatu danych używanego do komunikowania się z serwerem internetowym w tle, ponieważ większość implementacji przełączała się na format JSON jako prostszą i wydajniejszą alternatywę. Więc zamiast wymyślać zastępczy akronim jak AJAJ, który jest trochę język-twister, akronim jest na ogół emerytowany na rzecz Ajax terminu, a nie AJAX akronim.

W momencie pisania tego tekstu spodziewaj się, że zobaczysz mieszane i szerokie zastosowanie "AJAX" i "Ajax", aby oznaczać jedno i to samo. W tym artykule utknęliśmy z terminem "Ajax". Produkty komercyjne, które zapewniają struktury umożliwiające aplikacje w stylu Ajax, mają jednak tendencję do używania formularza akronimu do odróżnienia od podobnie nazwanego produktu czyszczącego oraz uniknięcia potencjalnych sporów prawnych lub znaków towarowych.

ASP.NET AJAX: wewnątrz ciągu daty i godziny JSON

Serializator AJAX JSON w ASP.NET koduje wystąpienie DateTime jako ciąg JSON. Podczas cykli wstępnych ASP.NET AJAX użył formatu "@ticks@", gdzie znaczniki reprezentują liczbę milisekund od 1 stycznia 1970 r. w uniwersalnym czasie koordynowanym (UTC). Data i godzina w formacie UTC, takie jak 29 listopada 1989, 4:55:30, zostaną zapisane jako "@62831853071@". Chociaż prosty i prosty, ten format nie może odróżnić zserializowanej wartości daty i godziny oraz ciągu, który wygląda jak data serializowana, ale nie ma być deserializowany jako jeden. W związku z tym zespół ASP.NET AJAX dokonał zmiany w ostatnim wydaniu, aby rozwiązać ten problem, przyjmując format "\/Date(ticks)\/".

Nowy format opiera się na małej sztuczki, aby zmniejszyć prawdopodobieństwo błędnej interpretacji. W formacie JSON znak ukośnika do przodu (/) w ciągu można uciec z ukośnikiem odwrotnym (\), mimo że nie jest on ściśle wymagany. Korzystając z tego, zespół ASP.NET AJAX zmodyfikował javaScriptSerializer, aby napisać wystąpienie DateTime jako ciąg "\/Date(ticks)\/". Ucieczka dwóch ukośników do przodu jest powierzchowna, ale znacząca dla JavaScriptSerializer. Według reguł " JSON\/Date(ticks)\/" jest technicznie równoważne "/Date(ticks)/" ale javaScriptSerializer deserializuje byłą jako DateTime, a drugą jako ciąg. Szanse na niejednoznaczność są zatem znacznie mniejsze w porównaniu z prostszym formatem "@ticks@" z wersji wstępnej.

Specjalne podziękowania

Przed przesłaniem tego artykułu do MSDN mieliśmy wielu wolontariuszy, którzy pomogli w weryfikacji artykułu i przekazali opinię na temat zawartości, gramatyki i kierunku. Głównymi współautorami procesu przeglądu są Douglas Crockford, Eric Schönholzer i Milan Negovan.

Informacje o autorach

Atif Aziz jest głównym konsultantem w Skybow AG, gdzie jego głównym celem jest pomoc klientom w zrozumieniu i tworzeniu rozwiązań na platformie deweloperów .NET. Atif regularnie przyczynia się do społeczności deweloperów firmy Microsoft, przemawiając na konferencjach i pisząc artykuły dotyczące publikacji technicznych. Jest prelegentem INETA i prezesem największej szwajcarskiej grupy użytkowników platformy .NET. Można dotrzeć do niego pod adresem atif.aziz@skybow.com lub za pośrednictwem swojej witryny internetowej pod adresem http://www.raboof.com.

Scott Mitchell, autor sześciu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Można dotrzeć do niego pod adresem mitchell@4guysfromrolla.com lub za pośrednictwem swojego bloga: http://ScottOnWriting.net.