Consider the following JSON:
{
"Code": 2,
"Body": {
"Dynamic-Key": {
"Key1": "Val1",
"Key2": "Val2"
}
}
}
Defining the following classes structure:
[DataContract]
class JsonResponse
{
[DataMember]
public string Code { get; set; }
[DataMember]
public JsonResponseBody Body { get; set; }
}
[DataContract]
class JsonResponseBody
{
[DataMember(Name = "Dynamic-Key")]
public DynamicKeyData Data { get; set; }
}
[DataContract]
class DynamicKeyData
{
[DataMember]
public string Key1 { get; set; }
[DataMember]
public string Key2 { get; set; }
}
I can deserialize the given JSON with the following code:
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JsonResponse));
JsonResponse responseData = serializer.ReadObject(responseStream) as JsonResponse;
However in my case the "Dynamic-Key" is not known and is defined by user input value.
What is the right way to handle this kind of JSON definition?
Considerations:
The JSON is of a third party Api, so changing it is not an option.
In my case I don't care about the Dynamic-Key name, so if there is an option to always map to one generic name it will do the job.
Thanks in advance.
Do you definitely need to use WCF? Otherwise I'd recommend looking at Json.NET. There's a number of extensibility mechanisms such as Contract Resolvers
Store the JSON in a string let suppose in strResult.
Then you can deserialize it into the JsonResponse object as follows:
JsonConvert is the class in Newtonsoft.Json.JsonConvert dll. You can use it as follows:
JsonResponse object= (JsonResponse)JsonConvert.DeserializeObject(strResult, typeof(JsonResponse));
Related
so I have a problem:
The code in JSON that you see there is a response that a webpage gives me. And the thing I want to do is really simple:
I just want to parse for example the "user_id", or "class".
I tried few things on stackoverflow that I found but no one works...
{
"data": {
"user": {
"class": "user",
"user_id": "81046537",
"etp_guid": "76411082-73ab-5aaa-9242-0bb752cf97a4",
},
},
}
Thanks !
There are many ways you can extract the user_id from the json. The most common way is to use Newtonsoft.Json package.
Assuming the json is stored as a string, you can call JObject.Parse().
var data = "{'data': {'user': {'class': 'user','user_id': '81046537','etp_guid': '76411082-73ab-5aaa-9242-0bb752cf97a4'} } }";
JObject jObject = JObject.Parse(data);
var userId = jObject["data"]["user"]["user_id"];
Console.WriteLine($"User id {userId}");
If your json is stored as a n object, then call JObject jObject = new JObject(data)
A preferred way is to serialise your json using business object. Simply create classes to match the json structure. e.g:
public class Response
{
public Data Data { get; set; }
}
public class Data
{
public User User { get; set; }
}
public class User
{
public string Class { get; set; }
public string User_id { get; set; }
public string Etp_guid { get; set; }
}
Then deserialize your object. e.g:
var response = JsonConvert.DeserializeObject<Response>(data);
Console.WriteLine($"User id {response.Data.User.User_id}");
I don't want to use Newtonsoft's Json.Net library. I'm avoiding any third-party dependencies if I can help it in this project.
If I have JSON that looks like this:
{
"has_more_items": false,
"items_html": "...",
"min_position": "1029839231781429248"
}
and I have a class that looks like this:
public class TwitterJson
{
bool hasMore { get; set; } // has_more_items
string rawText { get; set; } // items_html
string nextKey { get; set; } // min_position
}
and I have a JsonObject containing the above JSON:
JsonObject theJson = JsonObject.Parse(result);
How do I deserialize the JsonObject into my class? I've been trying to find a clear example of this, and everything I've found uses Json.Net.
I've been trying to find a clear example of this, and everything I've found uses Json.Net.
Because reinventing existing functionality is a waste of time especially when all the hard work has already been done for you.
If you insist on not using it then you will have to manually construct the object model based on the expected JSON.
For example, assuming publicly available properties
public class TwitterJson {
public bool hasMore { get; set; } // has_more_items
public string rawText { get; set; } // items_html
public string nextKey { get; set; } // min_position
}
Then parsing the above to the desired object model
JsonObject theJson = JsonObject.Parse(result);
var model = new TwitterJson {
hasMore = theJson.GetNamedBoolean("has_more_items"),
rawText = theJson.GetNamedString("items_html"),
nextKey = theJson.GetNamedString("min_position")
};
As mentioned by #Dimith, you need to decorate your class with [DataContract] and [DateMember], Please refer to below code which will convert your JSON into a given object.
// Deserialize a JSON string to a given object.
public static T ReadToObject<T>(string json) where T: class, new()
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
return ser.ReadObject(stream) as T;
}
}
Class:
[DataContract]
public class TwitterJson
{
[DataMember(Name = "has_more_items")]
bool hasMore { get; set; } // has_more_items
[DataMember(Name = "items_html")]
string rawText { get; set; } // items_html
[DataMember(Name = "min_position")]
string nextKey { get; set; } // min_position
}
Sample on how to use:
var result = "{\"has_more_items\": false, \"items_html\": \"...\",\"min_position\": \"1029839231781429248\"}";
var obj = ReadToObject<TwitterJson>(result);
You have to decorate your class with [DataContract] and [DataMember] attributes. Write the json into a memory stream and deserialize using DataContractJsonSerializer
Here is a more elaborated sample.
In addition to #Nkosi's answer below are some Comparisons between JSON.net and other alternatives:
JSON.Net vs DataContractJsonSerializer
JSON.Net vs Windows.Data.Json
I'm creating objects to store the JSON data I will be receiving and cannot figure out the right way to structure the objects. Basically, I can be receiving two different objects that only have differences in the body, so I wish to make a base class.
public class SampleBase
{
public string url { get; set; }
public string resource { get; set; }
public string Body body { get; set; }
}
This is an example of the base, with the Body object declared below
public abstract class Body{ }
I then have two separate files for the versions of the base object I can receive, with an example below:
public class SampleObject : SampleBase
{
public class Body
{
public string bodyproperty { get; set; }
}
}
I am doing this just to be efficient with the classes since they share some properties. The SampleBase class will never be called, instead incoming json will be deserialized into SampleObject. Is this best practice?
Edit: Going by this example, the JSON is received as
{
"url": "xxxxxxxxxx",
"resource": "xxxxxxx",
"body": {
"bodyproperty": "xxxx",
}
}
Your class structure can heavily depend on your choice of serializer. For example, the DataContractJsonSerializer can technically handle inherited classes, but it does it in somewhat of a clunky way. You need to define all the known inheritors of your base type on the base type.
Personally, I would use composition rather than inheritance in your case. Here's an example using the DataContractJsonSerializer:
[DataContract]
public class Wrapper<T> where T : Body
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "resource")]
public string Resource { get; set; }
[DataMember(Name = "body")]
public string T Body { get; set; }
}
[DataContract]
public class Body
{
[DataMember(Name = "bodyproperty")]
public string BodyProperty { get; set; }
}
Then you'd use the class like any other generic.
Wrapper<Body> obj = new Wrapper<Body>();
Edit: Since this is a MVC application, you'll likely be working with the JavascriptSerializer. The DataContract and DataMember can be ignored but the structure of the classes is still relevant.
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Wrapper<Body>>(json);
I get this response string from the Bitly api:
{ "status_code": 200,
"status_txt": "OK",
"data":
{ "long_url": "http:\/\/amazon.de\/",
"url": "http:\/\/amzn.to\/1mP2o58",
"hash": "1mP2o58",
"global_hash": "OjQAE",
"new_hash": 0
}
}
How do I convert this string to a dictionary and how do I access the value for the key "url" (without all the \)
This isn't just some ordinary string. This is a data structure in JSON format, a common and well-established format, originally used in Javascript but now rather common as a data transfer mechanism between services and clients.
Rather than reinventing the wheel and parsing the JSON yourself, I suggest you use an existing JSON library for C#, such as JSON.NET, which will eat up that string and parse it into .NET objects for you.
Here's a code sample, taken from JSON.NET's documentation, showing its usage:
string json = #"{
'href': '/account/login.aspx',
'target': '_blank'
}";
Dictionary<string, string> htmlAttributes =
JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Console.WriteLine(htmlAttributes["href"]);
// /account/login.aspx
Console.WriteLine(htmlAttributes["target"]);
// _blank
If you add a package like Newtonsoft's Json to your project, you can deserialize the Json in to an anonymous type. You can then fetch the url from that. This is available via NuGet within Visual Studio and provides support for async or sync serialization/deserialization.
public string GetUrl(string bitlyResponse)
{
var responseObject = new
{
data = new { url = string.Empty },
};
responseObject = JsonConvert.DeserializeAnonymousType(bitlyResponse, responseObject);
return responseObject.data.url;
}
I'd use JSON.NET.
http://james.newtonking.com/json
MIT License which means if you're doing anything commercial you are good.
I don't think you would want to go straight to a Dictionary, because there is some stuff there that isn't a one to one relationship. So you could make a class like the following.
public class BitlyData
{
public string LongUrl{ get; set; }
public string Url { get; set; }
public string Hash { get; set; }
public string GlobalHash { get; set; }
public string NewHash { get; set; }
}
You could then use Json.NET to turn that String into an JObject. So we'll call your string bitlyString.
JObject bitlyObject = JObject.Parse(bitlyString);
Now we have that all that is left to do is access the data.
BitlyData theData = JsonConvert.DeserializeObject<BitlyData>(bitlyObject["data"]);
Then you can access the url (and any other pieces) using the getters.
Of course you could make it even better by having class that handles the other bits as well so you just do one serialisation.
1)Add these classes to your project
public class Rootobject
{
public int status_code { get; set; }
public string status_txt { get; set; }
public Data data { get; set; }
}
public class Data
{
public string long_url { get; set; }
public string url { get; set; }
public string hash { get; set; }
public string global_hash { get; set; }
public int new_hash { get; set; }
}
2)Add a reference to JSON.NET
3)
string jsonString= "YOUR JSON STRING";
Rootobject weps = JsonConvert.DeserializeObject<Rootobject>(jsonString);
Console.WriteLine(weps.status_code);
if (weps.data != null)
{
Console.WriteLine(weps.data.url);
Console.WriteLine(weps.data.global_hash);
//...
}
I am trying to deserialize a json response from a google api, so i thought i would define a couple classes to help with it:
[DataContract]
public class DetectionResult:ResponseData
{
[DataMember(Name="language")]
public string Language
{ get; set; }
[DataMember(Name="isReliable")]
public bool IsReliable
{ get; set; }
[DataMember(Name="confidence")]
public double Confidence
{get;set;}
}
[DataContract]
public abstract class ResponseData
{
[DataMember(Name = "error")]
public TranslationError Error
{ get; set; }
}
[DataContract]
public class TranslationError
{
[DataMember(Name="code")]
public int Code
{ get; set; }
[DataMember(Name="message" )]
public int Message
{ get; set; }
}
[DataContract]
[KnownType(typeof(DetectionResult))]
public class RequestResult
{
[DataMember(Name="responseStatus")]
public int ResponseStatus
{ get; set; }
[DataMember(Name="responseDetails")]
public string ResponseDetails
{ get; set; }
[DataMember(Name = "responseData")]
public ResponseData Response
{ get; set; }
}
The response I get after making the request is:
{"responseData": {"language":"en","isReliable":false,"confidence":0.114892714}, "responseDetails": null, "responseStatus": 200}
and use this code to deserialize it:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream stream = response.GetResponseStream())
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(RequestResult));
RequestResult result = (RequestResult)serializer.ReadObject(stream);
stream.Close();
}
But am getting an exception stating "Cannot create an abstract class". Shouldnt it know about the DetectionResult class and properly deserialize it?
In your response data there is no way to infer a concrete type. The type to deserialize is not specified in the response.
From MSDN:
To preserve type identity, when serializing complex types to JSON a
"type hint" can be added, and the deserializer recognizes the hint and
acts appropriately. The "type hint" is a JSON key/value pair with the
key name of "__type" (two underscores followed by the word "type").
The value is a JSON string of the form
"DataContractName:DataContractNamespace" (anything up to the first
colon is the name). Using the earlier example, "Circle" can be
serialized as follows.
http://msdn.microsoft.com/en-us/library/bb412170.aspx
See the section related to polymorphism.
Have you tried putting the KnownType attribute on ResponseData instead of RequestResult?
In that code sample you need [KnownType(typeof(DetectionResult))] to be an attribute of ResponseData rather than RequestResult.
I don't know if that's sufficient to resolve your problem
From my experience working with the DataContractSerializer and the XmlSerializer, when an unexpected type is met during serialization process, those serializers throw an exception; they don't simply do the best they can. Maybe the DataContractJsonSerializer does not support KnownTypes at all.