Comment analyser JSON avec C #?

455

J'ai le code suivant:

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

L'entrée dans responsecontentest JSON, mais elle n'est pas correctement analysée dans un objet. Comment dois-je le désérialiser correctement?

Ola Ström
la source
7
Hé, vous voudrez peut-être essayer ce lien techblog.procurios.nl/k/n618/news/view/14605/14863/…
Vamsi
34
Il y a Jsondans System.Web.Helpers, il y a JsonQueryStringConverterdans System.ServiceModel.Web, il y a JavascriptSerializerdans System.Web.Script.Serialization, DataContractJsonSerializerdans System.Runtime.Serialization.Json, Heck MS a même décidé d'inclure un tiers Json.NETdans son API Web ASP.NET. Si vous pensiez que cela ne suffisait pas, la SEP arrive, System.Jsonmais est actuellement impropre à la consommation. Way to go Microsoft way to go .... Je choisis par le plus bel espace de noms.
nawfal
4
@fusi les autres sont dans des assemblages séparés. Recherchez le nom de l'espace de noms / classe, vous trouverez l'assembly qu'ils sont dans la documentation msdn. Ajoutez simplement une référence à cet assemblage.
nawfal
1
Juste pour compléter, il y a aussi JsonValuedans ce Windows.Data.Jsonqui est uniquement pour Windows 8 et plus. J'adore ça. MS est en mission :)
nawfal
5
NewtonSoft a une page de comparaison sur leur site (peut être biaisée mais toujours intéressante): newtonsoft.com/json/help/html/jsonnetvsdotnetserializers.htm . J'ai particulièrement aimé la ligne de sérialisation du dictionnaire absurde :)
Ohad Schneider

Réponses:

365

Je suppose que vous n'utilisez pas Json.NET (package Newtonsoft.Json NuGet). Si tel est le cas, vous devriez l'essayer.

Il présente les caractéristiques suivantes:

  1. LINQ à JSON
  2. Le JsonSerializer pour convertir rapidement vos objets .NET en JSON et vice-versa
  3. Json.NET peut éventuellement produire un JSON bien formaté et en retrait pour le débogage ou l'affichage
  4. Des attributs tels que JsonIgnore et JsonProperty peuvent être ajoutés à une classe pour personnaliser la façon dont une classe est sérialisée
  5. Possibilité de convertir JSON vers et depuis XML
  6. Prend en charge plusieurs plates-formes: .NET, Silverlight et le Compact Framework

Regardez l' exemple ci-dessous. Dans cet exemple, la JsonConvertclasse est utilisée pour convertir un objet vers et depuis JSON. Il a deux méthodes statiques à cet effet. Ils sont SerializeObject(Object obj)et 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
la source
18
Puis-je désérialiser en une varvariable de type, dans le cas où je ne connais pas la structure complète de mon objectif? Plus précisément, je consomme des histoires d'utilisateurs de rallye et je souhaite les convertir en objets.
Pedro Dusso
16
@VANDERWEYENJonathan - dans un navigateur Web moderne, JSON.parse (chaîne) et JSON.stringify (objet) gèrent tous deux les dates sous forme de chaînes ISO8601, qui est le format décrit dans la réponse ci-dessus. Vous voudrez peut-être mettre à jour votre norme avant que les gens décident qu'elle n'est pas pertinente. Les gens ont besoin de dates beaucoup plus que de leurs standards.
Peter Wone
3
@PeterWone: Non, JSON.parse('{"Expiry": "2008-12-28T00:00:00"}').Expiryrenvoie la chaîne "2008-12-28T00:00:00" , pas une date. il peut être transformé en un Datevia new Date(str), mais JSON.parsene sait rien sur les dates. Vous devez passer un reviver qui vérifie chaque valeur de chaîne par rapport à un modèle.
TJ Crowder
3
Étant donné que 3,703 secondes sont les mêmes que 3 s et 703 ms et que le séparateur est une virgule décimale, je vous suggère qu'il s'agit de secondes à trois décimales.
Peter Wone
38
Pourquoi tout le monde a un tel problème avec pertinents , y compris require, include, importou des usingdéclarations dans leurs réponses. Est-ce que cette ligne ferait mal?
Tomáš Zato - Reinstate Monica
285

Comme il a été répondu ici - Désérialiser JSON en objet dynamique C #?

C'est assez simple en utilisant Json.NET:

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

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

Ou en utilisant 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;
Dmitry Pavlov
la source
13
@MaxHodges, vous avez raison. Je viens d'utiliser des "chaînes magiques" en ligne pour montrer comment analyser les valeurs de chaîne JSON. Je ne voulais pas que cela semble complexe avec des guillemets d'échappement. Dans le code réel, nous avons généralement des chaînes JSON obtenues quelque part en tant que variables ou passées en tant que paramètres.
Dmitry Pavlov
4
Sans .net 4, vous n'avez pas de mot-clé «dynamique». Vous pouvez utiliser 'var stuff' pour la déclaration et au lieu de 'stuff.Name' et 'stuff.Address.City' vous avez respectivement 'stuff ["Name"]' et 'stuff ["Address"] ["City"]' ' .
Fil
1
@Fil Cela vous donne une valeur de type object, et vous ne pouvez pas utiliser l'indexation sur un fichier object.
Alex
138

Voici quelques options sans utiliser de bibliothèques tierces:

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

Voir le lien pour plus d'informations sur System.Web.Helpers.Json .

Mise à jour : De nos jours, le moyen le plus simple d'obtenir le Web.Helpersest d'utiliser le package NuGet .


Si vous ne vous souciez pas des versions antérieures de Windows, vous pouvez utiliser les classes de l' Windows.Data.Jsonespace de noms:

// 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
la source
Pourquoi je ne vois pas System.Web.Helpers dans mon site Web ASP.NET (4.5)? XElement, XPathSelectElement ne sont pas connus pour mon VisualStudio. Comment l'éduquer?
Budda
Eh bien, vous devez ajouter des références pour les bibliothèques correspondantes (comme écrit dans les commentaires ci-dessus), consultez cet article pour plus d'informations. En outre, cette question pourrait être intéressante.
qqbenq
2
J'ai utilisé la méthode Web.Helpers décrite ici, mais j'ai rencontré un problème résolu par cet article: stackoverflow.com/questions/7066726/…
Alex
1
il fonctionne avec WPF.By en utilisant l'espace de noms suivant en utilisant System.Runtime.Serialization.Json; using System.Xml.XPath; using System.Xml.Linq;
Shahid Neermunda
62

Si .NET 4 est à votre disposition, consultez: http://visitmix.com/writings/the-rise-of-json (archive.org)

Voici un extrait de ce site:

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

Cette dernière Console.WriteLine est assez douce ...

ElonU Webdev
la source
Désolé, on dirait que les choses ont changé depuis que j'ai répondu initialement. Je vais devoir jeter un coup d'œil et voir quelle bibliothèque est la bonne ...
ElonU Webdev
7
Au plaisir de vous trouver cette bibliothèque. Edit: est-ce celui-ci: dynamicjson.codeplex.com ?
user989056
1
Je ne sais pas ce que la classe ElonU signifiait ici, mais il y a "JsonValue" dans Windows.Data.Json (qui est uniquement pour Windows 8 et supérieur - bizarre) et aussi le même "JsonValue" dans System.Json qui est toujours en préversion et Dieu seul sait si cela sortira jamais. MS me confond quand il s'agit de Json.
nawfal
35

Une autre solution native à cela, qui ne nécessite aucune bibliothèque tierce mais une référence à System.Web.Extensions est JavaScriptSerializer. Ce n'est pas une nouveauté mais une fonctionnalité intégrée très inconnue depuis la 3.5.

using System.Web.Script.Serialization;

..

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

et retour

MyObject o = serializer.Deserialize<MyObject>(objectString)
fr34kyn01535
la source
2
C'est très bien, mais il a besoin des composants Web, donc malheureusement cela ne fonctionne pas dans le profil client .NET 4.0, qui est la dernière version .NET pour Windows XP. L'installation complète de .NET est possible, mais de nombreuses personnes s'en tiennent uniquement au profil client. En revanche, System.Runtime.Serialization.Json.DataContractJsonSerializer est pris en charge même dans le profil client.
Al Kepp
3
@ fr34kyn01535: Windows XP a la deuxième plus grande part de marché sur le bureau. C'est pertinent.
DonkeyMaster
Lorsque j'ai utilisé JavaScriptSerializer pour désérialiser mon objet, cela a fonctionné mais il a désérialisé ma date de manière incorrecte. Il aurait dû être le 19/04/2018 12:00 mais désérialisé au 18/04/2018 20:00. NewtonSoft.Json.JsonConvert l'a désérialisé comme prévu.
Rich
21

Vous pouvez également consulter le DataContractJsonSerializer

Pieter Germishuys
la source
1
c'est mieux car il est compatible avec .NET 3.5
Mahmoud Fayez
il est également assez rapide que JavaScriptSerializer,
David
16

System.Json fonctionne maintenant ...

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

PM> Install-Package System.Json -Version 4.5.0

Échantillon :

// 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
la source
1
Essayer de trouver un exemple de la façon d'utiliser correctement le System.Json moderne m'a amené ici, après d'innombrables résultats pour Json.NET/Newtonsoft.Json/"Newtson.Json "et les itérations plus anciennes de System.Json depuis longtemps obsolètes. Merci pour ça.
monkey0506
1
Cela m'a beaucoup aidé. Merci beaucoup.
MAK
10

Utilisez cet outil pour générer une classe basée sur votre json:

http://json2csharp.com/

Et puis utilisez la classe pour désérialiser votre json. Exemple:

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]

Références: 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
la source
9

Essayez le code suivant:

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
la source
Merci, je voulais la partie ["result" + variable] parce que je voulais utiliser des variables à utiliser ici que vous ne pouvez pas facilement faire avec JSON.NET.
PHPGuru
Cette ligne fait-elle quelque chose ... JavaScriptSerializer js = new JavaScriptSerializer (); Merci d'avance.
Chris Catignani
9

System.Text.Json

.NET core 3.0 est livré avec System.Text.Jsonce qui signifie que vous pouvez désérialiser / sérialiser JSON sans utiliser de bibliothèque tierce.

Pour sérialiser vos classes en chaîne JSON:

var json = JsonSerializer.Serialize(order);

Pour désérialiser le JSON en une classe fortement typée:

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

Donc, si vous avez une classe comme ci-dessous:

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

Une chose à noter est que System.Text.Json ne gère pas automatiquement camelCaseles propriétés JSON lors de l'utilisation de votre propre code (cependant, il le fait lors de l'utilisation des requêtes MVC / WebAPI et du classeur de modèle).

Pour résoudre ce problème, vous devez passer JsonSerializerOptionsen paramètre.

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 est également disponible pour .Net Framework et .Net Standard en tant que package Nu-get System.Text.Json

haldo
la source
1
Et si vous n'avez pas de cours? Que faire si vous ne savez que vaguement ce que les données json vont contenir? Ou si les clés existent?
Cherona
Utilisation de @Cherona JsonDocument.Parse.
haldo
5

Les éléments suivants du site msdn devraient, je pense, aider à fournir des fonctionnalités natives pour ce que vous recherchez. Veuillez noter qu'il est spécifié pour Windows 8. Un exemple du site est répertorié ci-dessous.

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

Il utilise l' espace de noms Windows.Data.JSON .

TargetofGravity
la source
6
Sympa, mais "Client minimum pris en charge: Windows 8"
watbywbarif
je pense que ce n'est plus pris en charge et maintenant il y a newtonsoft json dll icouldnt trouver windows.data.json
virtouso
3
@virtouso, comme watbywbarif l'a souligné, il est en fait plutôt nouveau, mais le support minimal de Microsoft ne fonctionne que sous Windows 8.
TargetofGravity
4

Vous pouvez utiliser les extensions suivantes

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
la source
0

Je pense que la meilleure réponse que j'ai vue a été @MD_Sayem_Ahmed.

Votre question est "Comment puis-je analyser Json avec C #", mais il semble que vous souhaitiez décoder Json. Si vous voulez le décoder, la réponse d'Ahmed est bonne.

Si vous essayez d'accomplir cela dans ASP.NET Web Api, le moyen le plus simple consiste à créer un objet de transfert de données qui contient les données que vous souhaitez affecter:

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

Vous avez simplement ajouté l'en-tête application / json à votre demande (si vous utilisez Fiddler, par exemple). Vous utiliseriez ensuite cela dans l'API Web ASP.NET comme suit:

//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
}

Cela m'a beaucoup aidé lorsque je travaillais dans mon Web Api et m'a rendu la vie super facile.

cr1pto
la source
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
la source
-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
la source
2
Vous feriez mieux d'expliquer votre solution au lieu de simplement publier une ligne de code. Vous pouvez lire Comment écrire une bonne réponse .
Massimiliano Kraus
N'oubliez pas d'inclure System.Webdans vos références de projet.
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
la source