Jak mogę przeanalizować JSON z C #?

455

Mam następujący kod:

var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);

Dane wejściowe responsecontentto JSON, ale nie są one poprawnie analizowane w obiekcie. Jak powinienem właściwie to zrobić z postaci szeregowej?

Ola Ström
źródło
7
Hej, możesz spróbować tego linku techblog.procurios.nl/k/n618/news/view/14605/14863/…
Vamsi
34
Jest Jsonw System.Web.Helpers, jest JsonQueryStringConverterw System.ServiceModel.Web, jest JavascriptSerializerw System.Web.Script.Serialization, DataContractJsonSerializerw System.Runtime.Serialization.Json, cholery MS nawet postanowiła włączyć osobę trzecią Json.NETw ASP.NET Web API. Jeśli myślałeś, że to nie wystarczy, MS wymyśliło, System.Jsonale obecnie nie nadaje się do spożycia. Way to go Microsoft way to go ... Wybieram według najlepiej wyglądającej przestrzeni nazw.
nawfal
4
@fusi reszta znajduje się w osobnych zespołach. Google przestrzeń nazw / nazwa klasy, znajdziesz ich zestaw w dokumentacji msdn. Po prostu dodaj odniesienie do tego zestawu.
nawfal
1
Aby zakończyć, istnieje również JsonValuew Windows.Data.Jsonktórym jest tylko dla systemu Windows 8 i nowszych. Uwielbiam to. MS jest na misji :)
nawfal
5
NewtonSoft ma stronę porównawczą na swojej stronie (może być stronnicza, ale wciąż interesująca): newtonsoft.com/json/help/html/jsonnetvsdotnetserializers.htm . Szczególnie podobał mi się wiersz serializacji słownika Nonsensical :)
Ohad Schneider,

Odpowiedzi:

365

Zakładam, że nie korzystasz z Json.NET (pakiet Newtonsoft.Json NuGet). W takim przypadku powinieneś spróbować.

Ma następujące funkcje:

  1. LINQ do JSON
  2. JsonSerializer do szybkiego konwertowania obiektów .NET na JSON iz powrotem
  3. Json.NET może opcjonalnie tworzyć dobrze sformatowane, wcięte JSON do debugowania lub wyświetlania
  4. Atrybuty takie jak JsonIgnore i JsonProperty można dodać do klasy, aby dostosować sposób serializacji klasy
  5. Możliwość konwersji JSON do iz XML
  6. Obsługuje wiele platform: .NET, Silverlight i Compact Framework

Spójrz na poniższy przykład . W tym przykładzie JsonConvertklasa służy do konwersji obiektu na i z JSON. Ma dwie metody statyczne w tym celu. Są SerializeObject(Object obj)i DeserializeObject<T>(String json):

Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string json = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "Expiry": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
MD Sayem Ahmed
źródło
18
Czy mogę deserializować do varzmiennej typu, w przypadku gdy nie znam pełnej struktury mojego celu? W szczególności konsumuję Historie użytkowników Rally i chcę je przekształcić w obiekty.
Pedro Dusso,
16
@VANDERWEYENJonathan - w nowoczesnej przeglądarce internetowej zarówno JSON.parse (ciąg), jak i JSON.stringify (obiekt) obsługują daty jako ciągi znaków ISO8601, co jest formatem przedstawionym w powyższej odpowiedzi. Możesz zaktualizować swój standard, zanim ludzie uznają, że jest on nieistotny. Ludzie potrzebują randek o wiele bardziej niż standardu.
Peter Wone
3
@PeterWone: Nie, JSON.parse('{"Expiry": "2008-12-28T00:00:00"}').Expiryzwraca ciąg "2008-12-28T00:00:00" , a nie datę. może być przekształconyDate poprzez new Date(str), ale JSON.parsenie wie nic o terminach. Będziesz musiał przekazać Reviver, który sprawdził każdą wartość ciągu względem wzorca.
TJ Crowder,
3
Ponieważ 3,703 sekundy to tyle samo, co 3s i 703ms, a separatorem jest przecinek dziesiętny, podaję wam, że jest to sekunda do trzech miejsc po przecinku.
Peter Wone
38
Dlaczego wszyscy mają taki problem z tym istotne require, include, importlub usingoświadczenia w swoich odpowiedziach. Czy ta jedna linia boli?
Tomáš Zato - Przywróć Monikę
285

Jak tu odpowiedziano - Deserializować JSON w obiekt dynamiczny C #?

Korzystanie z Json.NET jest dość proste:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

Lub używając Newtonsoft.Json.Linq:

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;
Dmitrij Pawłow
źródło
13
@MaxHodges, masz rację. Właśnie użyłem wbudowanych „magicznych ciągów” do pokazania, jak parsować wartości ciągów JSON. Nie chciałem, żeby wyglądało to skomplikowanie z unikaniem podwójnych cytatów. W prawdziwym kodzie zwykle mamy łańcuchy JSON uzyskane gdzieś jako zmienne lub przekazane jako parametry.
Dmitry Pavlov
4
Bez .net 4 nie masz słowa kluczowego „dynamicznego”. Możesz użyć „var stuff” do deklaracji, a zamiast „stuff.Name” i „stuff.Address.City” masz odpowiednio „stuff” [„Name”] ”i„ stuff ”„ Address ”] [„ City ”] .
Fil
1
@Fil To daje wartość typu objecti nie można używać indeksowania na object.
Alex
138

Oto kilka opcji bez korzystania z bibliotek stron trzecich:

// For that you will need to add reference to System.Runtime.Serialization
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }"), new System.Xml.XmlDictionaryReaderQuotas());

// For that you will need to add reference to System.Xml and System.Xml.Linq
var root = XElement.Load(jsonReader);
Console.WriteLine(root.XPathSelectElement("//Name").Value);
Console.WriteLine(root.XPathSelectElement("//Address/State").Value);

// For that you will need to add reference to System.Web.Helpers
dynamic json = System.Web.Helpers.Json.Decode(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }");
Console.WriteLine(json.Name);
Console.WriteLine(json.Address.State);

Zobacz link, aby uzyskać więcej informacji o System.Web.Helpers.Json .

Aktualizacja : w dzisiejszych czasach najłatwiejszym sposobem uzyskania dostępuWeb.Helpers jest użycie pakietu NuGet .


Jeśli nie zależy ci na wcześniejszych wersjach systemu Windows, możesz użyć klas Windows.Data.Jsonprzestrzeni nazw:

// minimum supported version: Win 8
JsonObject root = Windows.Data.Json.JsonValue.Parse(jsonString).GetObject();
Console.WriteLine(root["Name"].GetString());
Console.WriteLine(root["Address"].GetObject()["State"].GetString());
qqbenq
źródło
Dlaczego nie widzę System.Web.Helpers na mojej stronie ASP.NET (4.5)? XElement, XPathSelectElement nie są znane dla mojego VisualStudio. Jak to edukować?
Budda,
Cóż, musisz dodać odniesienia do odpowiednich bibliotek (jak napisano w komentarzach powyżej), zobacz ten artykuł aby uzyskać więcej informacji. Również to pytanie może być interesujące.
qqbenq,
2
Użyłem opisanej tutaj metody Web.Helpers, ale natknąłem się na problem, który został rozwiązany przez ten post: stackoverflow.com/questions/7066726/...
Alex
1
współpracuje z WPF.By przy użyciu następującej przestrzeni nazw przy użyciu System.Runtime.Serialization.Json; using System.Xml.XPath; using System.Xml.Linq;
Shahid Neermunda
3
Json.Net nie jest już komponentem strony trzeciej. Microsoft używa go teraz. Jest domyślnym serilizatorem w interfejsie API sieci Web.
Liam,
62

Jeśli .NET 4 jest dostępny, sprawdź: http://visitmix.com/writings/the-rise-of-json (archive.org)

Oto fragment tej witryny:

WebClient webClient = new WebClient();
dynamic result = JsonValue.Parse(webClient.DownloadString("https://api.foursquare.com/v2/users/self?oauth_token=XXXXXXX"));
Console.WriteLine(result.response.user.firstName);

Ostatnia konsola WriteLine jest całkiem słodka ...

ElonU Webdev
źródło
Przepraszamy, wygląda na to, że wszystko się zmieniło, odkąd początkowo odpowiedziałem. Muszę się rozejrzeć i zobaczyć, która biblioteka jest poprawna ...
ElonU Webdev,
7
Czekamy na znalezienie tej biblioteki. Edycja: czy to ta: dynamicjson.codeplex.com ?
user989056,
1
Nie wiem, co miała tu na myśli klasa ElonU, ale w Windows.Data.Json jest „JsonValue” (która jest tylko dla Windows 8 i nowszych - dziwne), a także ten sam „JsonValue” w System.Json, który wciąż jest w wersji zapoznawczej i Tylko Bóg wie, czy to kiedykolwiek wyjdzie. Stwardnienie rozsiane myli mnie, jeśli chodzi o Jsona.
nawfal
35

Innym rodzimym rozwiązaniem tego problemu, które nie wymaga żadnych bibliotek stron trzecich, ale odniesieniem do System.Web.Extensions jest JavaScriptSerializer. To nie jest nowa, ale bardzo nieznana wbudowana funkcja tam od 3.5.

using System.Web.Script.Serialization;

..

JavaScriptSerializer serializer = new JavaScriptSerializer();
objectString = serializer.Serialize(new MyObject());

i z powrotem

MyObject o = serializer.Deserialize<MyObject>(objectString)
fr34kyn01535
źródło
2
Jest to bardzo miłe, ale wymaga komponentów internetowych, więc niestety nie działa w profilu klienta .NET 4.0, który jest ostatnią wersją .NET dla systemu Windows XP. Pełna instalacja .NET jest możliwa, ale wiele osób trzyma się tylko profilu klienta. Natomiast System.Runtime.Serialization.Json.DataContractJsonSerializer jest obsługiwany nawet w profilu klienta.
Al Kepp
3
@ fr34kyn01535: Windows XP ma drugi co do wielkości udział w rynku na komputery. To jest istotne.
DonkeyMaster
Kiedy użyłem JavaScriptSerializer do deseriarizowania mojego obiektu, zadziałało, ale niepoprawnie zserializowało moją datę. Powinien to być 19.04.2018 00:00, ale deserializować do 18.04.2018 08:00. NewtonSoft.Json.JsonConvert dokonał deserializacji zgodnie z oczekiwaniami.
Bogaty
21

Możesz także rzucić okiem na DataContractJsonSerializer

Pieter Germishuys
źródło
1
jest to lepsze, ponieważ jest kompatybilne z .NET 3.5
Mahmoud Fayez
jest również znacznie szybszy niż JavaScriptSerializer,
David
16

System.Json działa teraz ...

Zainstaluj nuget https://www.nuget.org/packages/System.Json

PM> Install-Package System.Json -Version 4.5.0

Próbka :

// PM>Install-Package System.Json -Version 4.5.0

using System;
using System.Json;

namespace NetCoreTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Note that JSON keys are case sensitive, a is not same as A.

            // JSON Sample
            string jsonString = "{\"a\": 1,\"b\": \"string value\",\"c\":[{\"Value\": 1}, {\"Value\": 2,\"SubObject\":[{\"SubValue\":3}]}]}";

            // You can use the following line in a beautifier/JSON formatted for better view
            // {"a": 1,"b": "string value","c":[{"Value": 1}, {"Value": 2,"SubObject":[{"SubValue":3}]}]}

            /* Formatted jsonString for viewing purposes:
            {
               "a":1,
               "b":"string value",
               "c":[
                  {
                     "Value":1
                  },
                  {
                     "Value":2,
                     "SubObject":[
                        {
                           "SubValue":3
                        }
                     ]
                  }
               ]
            }
            */

            // Verify your JSON if you get any errors here
            JsonValue json = JsonValue.Parse(jsonString);

            // int test
            if (json.ContainsKey("a"))
            {
                int a = json["a"]; // type already set to int
                Console.WriteLine("json[\"a\"]" + " = " + a);
            }

            // string test
            if (json.ContainsKey("b"))
            {
                string b = json["b"];  // type already set to string
                Console.WriteLine("json[\"b\"]" + " = " + b);
            }

            // object array test
            if (json.ContainsKey("c") && json["c"].JsonType == JsonType.Array)
            {
                // foreach loop test
                foreach (JsonValue j in json["c"])
                {
                    Console.WriteLine("j[\"Value\"]" + " = " + j["Value"].ToString());
                }

                // multi level key test
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][0]["Value"].ToString());
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][1]["Value"].ToString());
                Console.WriteLine("json[\"c\"][1][\"SubObject\"][0][\"SubValue\"]" + " = " + json["c"][1]["SubObject"][0]["SubValue"].ToString());
            }

            Console.WriteLine();
            Console.Write("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
Zunair
źródło
1
Przyniosłem mi tutaj próbę prawidłowego korzystania z nowoczesnego System.Json, po niezliczonych wynikach dla Json.NET/Newtonsoft.Json/"Newtson.Json "i starszych iteracjach System.Json dawno przestarzały. Dziękuję Ci za to.
monkey0506,
1
To pomogło mi w ogromnym stopniu. Dziękuję Ci bardzo.
MAK
10

Użyj tego narzędzia, aby wygenerować klasę opartą na twoim jsonie:

http://json2csharp.com/

A następnie skorzystaj z klasy, aby dokonać deserializacji swojego Jsona. Przykład:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}


string json = @"{
  'Email': '[email protected]',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);
// [email protected]

Odnośniki: https://forums.asp.net/t/1992996.aspx?Nested+Json+Deserialization+to+C+object+and+using+that+object https://www.newtonsoft.com/json/help /html/DeserializeObject.htm

Bruno Pereira
źródło
9

Wypróbuj następujący kod:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
JArray array = new JArray();
using (var twitpicResponse = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(twitpicResponse.GetResponseStream()))
{
    JavaScriptSerializer js = new JavaScriptSerializer();
    var objText = reader.ReadToEnd();

    JObject joResponse = JObject.Parse(objText);
    JObject result = (JObject)joResponse["result"];
    array = (JArray)result["Detail"];
    string statu = array[0]["dlrStat"].ToString();
}
Muhammad Awais
źródło
Dzięki, chciałem części [„wynik” + zmienna], ponieważ chciałem użyć tutaj zmiennych, których nie można łatwo zrobić w JSON.NET.
PHPGuru,
Czy ta linia coś robi ... JavaScriptSerializer js = new JavaScriptSerializer (); Z góry dziękuję.
Chris Catignani
9

System.Text.Json

.NET core 3.0 ma System.Text.Jsonwbudowane, co oznacza, że ​​możesz dokonać deserializacji / serializacji JSON bez korzystania z biblioteki innej firmy.

Aby serializować swoje klasy do ciągu JSON:

var json = JsonSerializer.Serialize(order);

Aby deserializować JSON w silnie typowaną klasę:

var order = JsonSerializer.Deserialize<Order>(json);

Więc jeśli masz klasę jak poniżej:

public class Order
{
    public int Id { get; set; }
    public string OrderNumber { get; set; }
    public decimal Balance { get; set; }
    public DateTime Opened { get; set; }
}

var json = JsonSerializer.Serialize(order);
// creates JSON ==>
{
    "id": 123456,
    "orderNumber": "ABC-123-456",
    "balance": 9876.54,
    "opened": "2019-10-21T23:47:16.85",
};

var order = JsonSerializer.Deserialize<Order>(json);
// ==> creates the above class

Należy zauważyć, że System.Text.Json nie używa automatycznie camelCasewłaściwości JSON podczas korzystania z własnego kodu (jednak dzieje się tak przy korzystaniu z żądań MVC / WebAPI i segregatora modeli).

Aby rozwiązać ten problem, musisz podać JsonSerializerOptionsjako parametr.

JsonSerializerOptions options = new JsonSerializerOptions
{        
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,  // set camelCase       
    WriteIndented = true                                // write pretty json
};

// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);

System.Text.Json jest również dostępny dla .Net Framework i .Net Standard jako pakiet Nu-get System.Text.Json

haldo
źródło
1
Co jeśli nie masz zajęć? Co zrobić, jeśli ledwo wiesz, co będzie zawierać dane JSON? A jeśli klucze w ogóle istnieją?
Cherona
Wykorzystanie @Cherona JsonDocument.Parse.
haldo
5

Poniższe informacje z witryny msdn powinny pomóc zapewnić natywną funkcjonalność tego, czego szukasz. Należy pamiętać, że jest on określony dla systemu Windows 8. Jeden taki przykład ze strony znajduje się poniżej.

JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");

Wykorzystuje przestrzeń nazw Windows.Data.JSON .

TargetofGravity
źródło
6
Fajny, ale „Minimalny obsługiwany klient: Windows 8”
watbywbarif,
myślę, że nie jest już obsługiwany, a teraz jest newtonoft json dll nie można znaleźć windows.data.json
virtouso
3
@virtouso, jak zauważył watbywbarif, jest to raczej nowa, jednak minimalna obsługa przez Microsoft działa tylko w systemie Windows 8.
TargetofGravity
3

Możesz użyć następujących rozszerzeń

public static class JsonExtensions
{
    public static T ToObject<T>(this string jsonText)
    {
        return JsonConvert.DeserializeObject<T>(jsonText);
    }

    public static string ToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    } 
}
Hidayet R. Colkusu
źródło
0

Myślę, że najlepszą odpowiedzią, jaką widziałem, jest @MD_Sayem_Ahmed.

Twoje pytanie brzmi: „Jak mogę parsować Jsona za pomocą C #”, ale wygląda na to, że chcesz zdekodować Jsona. Jeśli chcesz go zdekodować, odpowiedź Ahmeda jest dobra.

Jeśli próbujesz to osiągnąć w interfejsie ASP.NET Web Api, najprostszym sposobem jest utworzenie obiektu do przesyłania danych, który przechowuje dane, które chcesz przypisać:

public class MyDto{
    public string Name{get; set;}
    public string Value{get; set;}
}

Po prostu dodajesz nagłówek application / json do swojego żądania (jeśli na przykład używasz Fiddlera). Następnie użyłbyś tego w ASP.NET Web API w następujący sposób:

//controller method -- assuming you want to post and return data
public MyDto Post([FromBody] MyDto myDto){
   MyDto someDto = myDto;
   /*ASP.NET automatically converts the data for you into this object 
    if you post a json object as follows:
{
    "Name": "SomeName",
      "Value": "SomeValue"
}
*/
   //do some stuff
}

Bardzo mi to pomogło, gdy pracowałem w interfejsie internetowym i uczyniłem moje życie bardzo łatwym.

cr1pto
źródło
0
         string json = @"{
            'Name': 'Wide Web',
            'Url': 'www.wideweb.com.br'}";

        JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
        dynamic j = jsonSerializer.Deserialize<dynamic>(json);
        string name = j["Name"].ToString();
        string url = j["Url"].ToString();
Fernando Meneses Gomes
źródło
-1
var result = controller.ActioName(objParams);
IDictionary<string, object> data = (IDictionary<string, object>)new System.Web.Routing.RouteValueDictionary(result.Data);
Assert.AreEqual("Table already exists.", data["Message"]);
Jidheesh Rajan
źródło
2
Lepiej wytłumacz swoje rozwiązanie zamiast po prostu publikować jakiś wiersz kodu. Możesz przeczytać Jak napisać dobrą odpowiedź .
Massimiliano Kraus
Nie zapomnij dołączyć do System.Webreferencji projektu.
Ohad Cohen,
-3
 using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(user)))
 {
    // Deserialization from JSON  
    DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(UserListing))
    DataContractJsonSerializer(typeof(UserListing));
    UserListing response = (UserListing)deserializer.ReadObject(ms);

 }

 public class UserListing
 {
    public List<UserList> users { get; set; }      
 }

 public class UserList
 {
    public string FirstName { get; set; }       
    public string LastName { get; set; } 
 }
Kobie Williams
źródło