I have to consume a so called web service implemented by a dumb monkey which is returning some garbage after the proper Json response.
Something like this:
{
"Property1": 1,
"Property2": 2,
"Property3": 3
}<?xml version='1.0' ?>Maybe some other gibberish nonsense I wish to discard.
Now, I could just search for "<?xml" and split, but I was wondering if I can use a stream reader or something to read up to the closing } and then discard the rest.
I'm using C# and Json.Net.
You can also set JsonSerializerSettings.CheckAdditionalContent = false to tell the serializer to ignore any content after the end of the deserialized JSON object:
var result = JsonConvert.DeserializeObject<Dictionary<string, long>>(json, new JsonSerializerSettings { CheckAdditionalContent = false })
Oddly enough it is necessary to do this explicitly despite the fact that the default value seems to be false already, since the underlying field is nullable.
I knew there had to be a simple and robust way:
public T ReadTypeAndDiscardTheRest<T>(string json)
{
using (var sr = new StringReader(json))
using (var jsonReader = new JsonTextReader(sr))
{
var token = JToken.Load(jsonReader);
return token.ToObject<T>();
}
}
[Test]
public void TestJsonDiscarding()
{
var json = #"{""Key"":""a"", ""Value"":""n""}<?xml>aaaa";
var kp = ReadTypeAndDiscardTheRest<KeyValuePair<string, string>>(json);
Assert.That(kp.Key, Is.EqualTo("a"));
Assert.That(kp.Value, Is.EqualTo("n"));
}
As always, Json.Net FTW.
Related
Is there any way to read a JSON object from the stream where it's followed by other data, and thus the only way to find out that we should stop reading is by reaching the position where the object's opening brace is closed?
{
"SomeData": "blahblah",
"SubObject": {
"SomeData": "blahblah}{{"
}
}
... and some more text (not JSON)
I assume you're going to use Json.Net library. In this case it will cater for your particular use case out of the box.
consider the following:
var s = "{ \"SomeData\": \"blahblah\", \"SubObject\": {\"SomeData\": \"blahblah}{{\" } } sdfsdfsdf... and some more data";
var obj1 = JsonConvert.DeserializeObject(s, new JsonSerializerSettings() {
CheckAdditionalContent = false // this is the key here, otherwise you will get an exception
});
JsonSerializer serializer = new JsonSerializer();
var obj2 = serializer.Deserialize(new JsonTextReader(new StringReader(s))); // no issues here either
So there is 1 website from where I need to get this JSON data.
The link is direct (I am using the website's API )
THe problem is, the file is HUGE!. Tens of Thousands of Lines.. Even more..
I have visual studio 2013 and what I need to do is download that JSON data in a callback and then parse it to get a specific value. I am using Newtonsoft.JSON to parse it and here is what I have thought will be able to parse it
var obj = JsonConvert.DeserializeObject<JContainer>(jsonText);
var value = (int)obj["response"]["prices"]["5021"]["6"]["0"]["current"]["value"];
The problem is, how do I download all of that data and convert it into C# classes? Is there another way?
Thanks a lot.
EDIT: If not JSON, I have option to download it in JSONP and VDF format
Here is the link of the JSON data - http://backpack.tf/api/IGetPrices/v3/?format=json&key=52f75dab4dd7b82f698b4568
I got it working by doing this
using (var webClient = new System.Net.WebClient())
{
var json = webClient.DownloadString("http://backpack.tf/api/IGetPrices/v3/?format=json&key=00a00aaa0aa0a00a000a0000");
Newtonsoft.Json.Linq.JObject o = Newtonsoft.Json.Linq.JObject.Parse(json);
var value = (int)o["response"]["prices"]["5021"]["6"]["0"]["current"]["value"];
Console.WriteLine(value);
}
Thanks for your help everybody!!
Try restsharp. It let you do something like
var prices = client.Execute<Prices>(request);
Where Prices is the class that matches the returned schema
Looking at the comment Brandon posted, he's right in principle, but you don't have to switch to Newtonsoft if you don't want. You just need to use a different JSON.NET API
var serializer = new JsonSerializer();
using (var stream = File.OpenRead("C:\\Users\\gweakliem\\Downloads\\sotest.js"))
{
using (StreamReader streamReader = new StreamReader(stream))
{
using (JsonReader reader = new JsonTextReader(streamReader))
{
var aThing = serializer.Deserialize<JContainer>(reader);
var aValue = (int) aThing["response"]["prices"]["5021"]["6"]["0"]["current"]["value"];
Console.WriteLine("Read a value " + aValue);
}
}
}
If you're concerned about blocking on this thread while reading, it looks like you're going to have to write some code. I don't see awaitable methods on JsonTextReader or JsonSerializer, so I expect that those methods will block.
Now if you want to turn this into objects, here's a couple other SO posts:
deserialize json into .net object using json.net
dynamic JContainer (JSON.NET) & Iterate over properties at runtime
Or this post covers a bunch of deserialization options.
private static void WriteJson(string filepath,
string filename,
JsonSchema jsonschema)
{
using (TextWriter writer = File.CreateText(
#"C:\Users\ashutosh\Desktop\Output\" + filename + ".js"))
using (var jtw = new JsonTextWriter(writer))
{
jtw.Formatting = Formatting.Indented;
jsonschema.WriteTo(jtw);
}
//var json = JsonConvert.SerializeObject(
// jsonschema, Formatting.Indented,
// new JsonSerializerSettings {
// NullValueHandling = NullValueHandling.Ignore });
// File.WriteAllText(
// #"C:\Users\ashutosh\Desktop\Output\" + filename + ".js", json);
}
I am creating a JSONSchema from JSON.net , and then writing it out . I get a
Invalid Operation Exception Sequence contains no matching element
But when I use the commented code instead of the usual stuff. No such exception appears.
1) What is causing this exception?
2) I would have used the second method happily but it doesn't feel intuitive and it will print out the integer value of the JsonType for schema.Type instead of the (array,integer,bool etc..)
What can I do to get out of this situation?
UPDATE
The exception happens when the "Properties" property of the JsonSchema has count = 0 .
Properties is Dictionary<String,JsonSchema>. I have initialise it so it is not null. Eventually the code may or may not add elements to it . so , the count may remain 0.
By default, enums will be serialized to theirs corresponding integer value. You can change that easily by supplying StringEnumConverter in your serializer settings:
var json = JsonConvert.SerializeObject(jsonschema, Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Converters = new List<JsonConverter> { new StringEnumConverter() }
});
Edit:
I run this simple test code:
var schema = new JsonSchemaGenerator().Generate(typeof(CustomType));
Debug.Assert(schema.Properties.Count == 0);
using (TextWriter textWriter = File.CreateText(#"schema.json"))
using (var jsonTextWriter = new JsonTextWriter(textWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
schema.WriteTo(jsonTextWriter);
}
// CustomType is a class without any fields/properties
public class CustomType { }
Code above serializes schema correctly to:
{
"type": "object",
"properties": {}
}
Is the schema you are generating correct? It seems as if serializer was "thinking" it should deal with some properties when there are actually none. Can you show type you generate schema from? There might be a problem with type which causes invalid schema to generate - but still, I cannot reproduce it.
I'm using HttpWebRequest method to "GET" data from a specific url that the returned data supposed to be in json format. My code are something like
WebRequest request = WebRequest.Create("https://xxx.xxxxxxxx.com/xxxxxxx");
request.Method = "GET";
request.ContentType = "application/json";
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
}
The responseText value as I observed are
[
{
"webinarKey":5303085652037254656,
"subject":"Test+Webinar+One",
"description":"Test+Webinar+One+Description",
"organizerKey":73563532324,
"times":[{"startTime":"2011-04-26T17:00:00Z","endTime":"2011-04-26T18:00:00Z"}]
},
{
"webinarKey":9068582024170238208,
"name":"Test+Webinar+Two",
"description":"Test Webinar Two Description",
"organizerKey":73563532324,
"times":[{"startTime":"2011-04-26T17:00:00Z","endTime":"2011-04-26T18:00:00Z"}]
}
]
As you can see it is in json format, but I don't know how to set it as a json object, so I can get it's field value as something like
string webinarKey=responseText[0].webinarKey;
Am I right?
JavaScriptSerializer ser = new JavaScriptSerializer();
MyClass package = null;
package = ser.Deserialize<MyClass>(item);
Where item is your response text, and MyClass is the .net class you are returning. then you can access the properties of your object.
You have to parse the response (that is a textstring with JSON) with a JSON parser/deserializer. For example: Json.net
http://msdn.microsoft.com/en-us/library/bb412179.aspx
WCF has a DataContractJSONDeserializer.
You would need to define your types as .net objects that had properties that "look" like the json data coming back. I don't get the impression that you are actually using WCF in your application but you may still be able to use the DataContractJSONDeserializer anyway. You just need to instruct it the type you want it to deserialze as and the type needs to be marked with a DataContract attribute.
Heres plenty more info
http://msdn.microsoft.com/en-us/library/bb412170.aspx
You can almost always get away with using the JavaScriptSerializer class. There will be numerous variations on this, and I can see suggestions in other answers already, though this might well suffice. Namely, you'll want to look into the Deserialize<T> method, with a signature of:
public T Deserialize<T>(
string input
)
One advantage, if this suits, is that it is a readily available class in System.Web.Extension and removes the requirement for 'third party components'.
One possibility for this is to use a JObject instance. YOu can pass it a string and then extract the values easily:
JObject jobj = JObject.Parse(resultString);
someValue = jobj[0]["webinarKey"];
I'm attempting to use the following code to serialize an anonymous type to JSON:
var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray());
However, I get the following exception when this is executed:
Type
'<>f__AnonymousType1`3[System.Int32,System.Int32,System.Object[]]'
cannot be serialized. Consider marking
it with the DataContractAttribute
attribute, and marking all of its
members you want serialized with the
DataMemberAttribute attribute. See
the Microsoft .NET Framework
documentation for other supported
types.
I can't apply attributes to an anonymous type (as far as I know). Is there another way to do this serialization or am I missing something?
Try the JavaScriptSerializer instead of the DataContractJsonSerializer
JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);
As others have mentioned, Newtonsoft JSON.NET is a good option. Here is a specific example for simple JSON serialization:
return JsonConvert.SerializeObject(
new
{
DataElement1,
SomethingElse
});
I have found it to be a very flexible, versatile library.
You can try my ServiceStack JsonSerializer it's the fastest .NET JSON serializer at the moment. It supports serializing DataContract's, Any POCO Type, Interfaces, Late-bound objects including anonymous types, etc.
Basic Example
var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>();
Note: Only use Microsofts JavaScriptSerializer if performance is not important to you as I've had to leave it out of my benchmarks since its up to 40x-100x slower than the other JSON serializers.
For those checking this around the year 2020:
Microsoft's System.Text.Json namespace is the new king in town. In terms of performance, it is the best as far as I can tell:
var model = new Model
{
Name = "Test Name",
Age = 5
};
string json = JsonSerializer.Serialize(model);
As some others have mentioned, NewtonSoft.Json is a very nice library as well.
The fastest way I found was this:
var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);
Namespace: System.Web.Script.Serialization.JavaScriptSerializer
Please note this is from 2008. Today I would argue that the serializer should be built in and that you can probably use swagger + attributes to inform consumers about your endpoint and return data.
Iwould argue that you shouldn't be serializing an anonymous type. I know the temptation here; you want to quickly generate some throw-away types that are just going to be used in a loosely type environment aka Javascript in the browser. Still, I would create an actual type and decorate it as Serializable. Then you can strongly type your web methods. While this doesn't matter one iota for Javascript, it does add some self-documentation to the method. Any reasonably experienced programmer will be able to look at the function signature and say, "Oh, this is type Foo! I know how that should look in JSON."
Having said that, you might try JSON.Net to do the serialization. I have no idea if it will work
You could use Newtonsoft.Json.
var warningJSON = JsonConvert.SerializeObject(new {
warningMessage = "You have been warned..."
});
A faster alternative with Microsofts' new library on System.Text.Json
var warningJSON = JsonSerializer.Serialize(new {
warningMessage = "You have been warned..."
});
Assuming you are using this for a web service, you can just apply the following attribute to the class:
[System.Web.Script.Services.ScriptService]
Then the following attribute to each method that should return Json:
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
And set the return type for the methods to be "object"
public static class JsonSerializer
{
public static string Serialize<T>(this T data)
{
try
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream();
serializer.WriteObject(stream, data);
string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
stream.Close();
return jsonData;
}
catch
{
return "";
}
}
public static T Deserialize<T>(this string jsonData)
{
try
{
DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
T data = (T)slzr.ReadObject(stream);
stream.Close();
return data;
}
catch
{
return default(T);
}
}
}