In a .NET 3.5 Compact Framework / Windows CE app, I need to consume some WebAPI methods that return json. RestSharp looks like it would be great for this, except that it's not quite CF-ready (see Is Uri available in some other assembly than System in .NET 3.5, or how can I resolve Uri in this RestSharp code otherwise? for details).
So, I will probably use HttpWebRequest. I can return the value from the WebAPI methods with this code:
string uri = "http://localhost:48614/api/departments";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webResponse = (HttpWebResponse)webRequest.GetResponse();
if ((webResponse.StatusCode == HttpStatusCode.OK) && (webResponse.ContentLength > 0))
{
StreamReader reader = new StreamReader(webResponse.GetResponseStream());
MessageBox.Show("Content is " + reader.ReadToEnd());
}
else
{
MessageBox.Show(string.Format("Status code == {0}", webResponse.StatusCode));
}
...but in order to use what's returned from reader.ReadToEnd():
...I need to convert it back to json so that I can then query the data with LINQ to JSON using either JSON.NET (http://json.codeplex.com/) or SimpleJson (http://simplejson.codeplex.com/)
Is that realistically possible (converting StreamReader data to JSON)? If so, how?
UPDATE
I'm trying to deserialize the "json" (or string that looks like json) with this code:
string uri = "http://localhost:48614/api/departments";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "GET";
var webResponse = (HttpWebResponse)webRequest.GetResponse();
if ((webResponse.StatusCode == HttpStatusCode.OK) && (webResponse.ContentLength > 0))
{
StreamReader reader = new StreamReader(webResponse.GetResponseStream());
DataContractJsonSerializer jasonCereal = new DataContractJsonSerializer(typeof(Department));
var dept = (Department)jasonCereal.ReadObject(reader.ReadToEnd());
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}", dept.AccountId, dept.DeptName));
}
...but get two err msgs on the "var dept =" line:
0) The best overloaded method match for 'System.Runtime.Serialization.XmlObjectSerializer.ReadObject(System.IO.Stream)' has some invalid arguments
1) Argument '1': cannot convert from 'string' to 'System.IO.Stream'
So reader.ReadToEnd() returns a string, and DataContractJsonSerializer.ReadObject() expects a stream, apparently. Is there a better approach for this? Or, if I'm on the right track (although currently a section of track has been removed, so to speak), how should I get past this hurdle?
UPDATE 2
I added the System.Web.Extensions reference and then "using System.Web.Script.Serialization;" but this code:
JavaScriptSerializer jss = new JavaScriptSerializer();
var dept = jss.Deserialize<Department>(s);
MessageBox.Show(string.Format("accountId is {0}, deptName is {1}",
dept.AccountId, dept.DeptName));
...but the second line fails with:
"Type 'bla+Department' is not supported for deserialization of an array."
What type should receive the call to jss.Deserialize()? How is it defined?
Well,
the ReadToEnd() method is used to read the stream into a string and output it. If you need a stream out to pass it to a method requiring a stream, you shouldn't use this method.
From what I read on this page , it seems the BaseStream property of your reader would be more appropriate to use then.
Related
For a .NET Core project, I'm consuming a public API that returns data formatted as JSON. However, some (not all) of their responses have a BOM character at the start of the string, which causes Visual Studio and Json.NET to not recognize the string as valid JSON. As a result, I get an error when using JsonConvert.DeserializeObject() to deserialize the string into my POCO object. I've been told by the API developers that the BOM is included by design, and that I should "set Json.Net to expect that". Is there a way to set Json.NET to handle the BOM without stripping it off the string manually?
Example follows, by request. You can see when the API GET completes successfully, I'm having to trim the BOM manually from the start of the string, otherwise the call to DeserializeObject() fails because the string is not valid JSON.
private static MyPOCO GetObjectFromApi(string url)
{
MyPOCO poco = new MyPOCO();
RestClient client = new RestClient(url);
RestRequest request = new RestRequest(Method.GET);
IRestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
poco = JsonConvert.DeserializeObject<MyPOCO>(response.Content.TrimStart((char)65279)); // trim the byte order marker character at the start of the string
//poco = JsonConvert.DeserializeObject<MyPOCO>(response.Content); // this would throw an error because response.Content is not valid JSON
}
else
{
MyLogger.WriteLog("Api returned failure response");
}
return poco;
}
Is JSON parsing possible into a type data or any other form where I can access each individual item within F# using built-in Microsoft provided library?
Following is an output generated by the following code.
"{"account_type":"type1","address":"US","preferred_languages":["en","ar","cn"],"displayName":"John","last_name":"Doe"}"
type Token = {access_token: string; refresh_token: string}
type Authentication =
new() = {}
static member token = null;
member this.RequestToken(credentials) =
let url = "example.com"
let request = WebRequest.Create(url) :?> HttpWebRequest
request.Method <- "POST"
request.ContentLength <- (int64)data.Length
use requestStream = request.GetRequestStream()
requestStream.Write(data, 0, (data.Length))
requestStream.Flush()
requestStream.Close()
let response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
let output = reader.ReadToEnd()
reader.Close()
response.Close()
request.Abort()
Authentication.token = JsonConvert.DeserializeObject<Token>(output)
// the value or constructor "Token" is not defined
Preferably in a type, for instance
type Token = {access_token: string; refresh_token: string}
Edit
Attempting using JSON.net
You will need to use an external library of some kind. If you want to get the most out of F#, you can solve this very nicely using the F# Data JSON type provider.
The type provider can infer type of JSON data from a sample, so you could parse the above data by using your sample response to guide the inference and then use the inferred type to parse more data:
open FSharp.Data
// Define a type using a sample JSON
type Account = JsonProvider<"""
{ "account_type":"type1","address":"US",
"preferred_languages":["en","ar","cn"],
"displayName":"John","last_name":"Doe"}""">
// Now, parse actual data you loaded from somewhere
let parsed = Account.Parse(data)
// Access all the members using a member generated by the type provider.
parsed.AccountType
parsed.Address
parsed.PreferredLanguages |> Seq.length
Using the code below, I've managed to create a jsonArray with the following format:[{"id":3},{"id":4},{"id":5}]
var jArray = new JsonArray();
int numOfChildren = 10;
for (int i = 0; i < numOfChildren; i++)
{
if (CONDITION == true)
{
var jObj = new JsonObject();
int id = SOMEID;
jObj.SetNamedValue("id", JsonValue.CreateNumberValue(id));
jArray.Add(jObj);
}
I am now trying to send "JsonArray" to a server using PostAsync as can be seen below:
Uri posturi = new Uri("http://MYURI");
HttpContent content = new StringContent(jArray.ToString(), Encoding.UTF8, "application/json");
System.Net.Http.HttpResponseMessage response = await client.PostAsync(postUri, content);
On the server side of things though, I can see that the post request contains no content. After digging around on the interwebs, it would seem that using jArray.ToString() within StringContent is the culprit, but I'm not understanding why or if that even is the problem in the first place. So, why is my content missing? Note that I'm writing this for UWP aplication that does not use JSON.net.
After much digging, I eventually Wiresharked two different applications, one with my original jArray.ToString() and another using JSON.net's JsonConver.SerializeObject(). In Wireshark, I could see that the content of the two packets was identical, so that told me that my issue resided on the server side of things. I eventually figured out that my PHP script that handled incoming POST requests was too literal and would only accept json posts of the type 'application/json'. My UWP application sent packets of the type 'application/json; charset=utf-8'. After loosening some of my content checking on the server side a bit, all was well.
For those who are looking to serialize json without the use of JSON.net, jsonArray.ToString() or jsonArray.Stringify() both work well.
You should use a Serializer to convert it to string.
Use NewtonSoft JSON Nuget.
string str = JsonConvert.SerializeObject(jArray);
HttpContent content = new StringContent(str, Encoding.UTF8, "application/json");
System.Net.Http.HttpResponseMessage response = await client.PostAsync(postUri, content);
I have a JSON file that contains what I believe to be a correct JSON string:
{"title": "exampleTitle", "tipTitle": "exampleTipTitle", "tip": "exampleTip"}
I'm trying to parse said file and take out the 3 values then store them in variables, however currently, it parses each individual character as a separate object, therefore:
JSONobj[1] = "
and so on. Assuming that currentLocation = the directory location of the json file.
Code
var jsonLocation = currentLocation + "json.txt";
var request = new XMLHttpRequest();
request.open("GET", jsonLocation, false);
request.send(null);
var returnValue = request.responseText;
var JSONobj = JSON.parse(JSON.stringify(returnValue));
var headerTitle = JSONobj[0];
A few clarifications, the stringify is in because it was throwing an unexpected token error. I've tried changing the file tile to .json instead but that also makes no difference. "It also gives off a XMLHttpRequest on the main thread is deprecated" but I'm not particularly sure how to solve that issue. Any help would be appreciated.
var returnValue = request.responseText;
Here returnValue is a string of JSON.
"{\"title\": \"exampleTitle\", \"tipTitle\": \"exampleTipTitle\", \"tip\": \"exampleTip\"}
var JSONobj = JSON.parse(JSON.stringify(returnValue));
Here you convert the string of JSON to JSON. So you have a JSON string representing a string, and that string is a representation of a data structure in JSON.
"\"{\\"title\\": \\"exampleTitle\\", \\"tipTitle\\": \\"exampleTipTitle\\", \\"tip\\": \\"exampleTip\\"}"
Then you parse it and convert it back to the original string of JSON.
"{\"title\": \"exampleTitle\", \"tipTitle\": \"exampleTipTitle\", \"tip\": \"exampleTip\"}
So you end up back where you start.
Just don't use JSON.stringify here, and you'll convert your JSON to a JavaScript object:
var javascript_object = JSON.parse(returnValue);
Then you have an object, but it doesn't have a 0 property so it doesn't make sense to access it with javascript_object[0]. The properties have names, such as javascript_object.title.
Your JSON doesn't describe an array, so indexing into it with an index like 0 doesn't make sense. Your JSON describes an object, which will have properties with the names title, tipTitle, and tip.
Additionally, you're overdoing your parsing: You just want to parse, not stringify (which is the opposite of parsing):
var JSONobj = JSON.parse(returnValue);
So:
var JSONobj = JSON.parse(returnValue);
var headerTitle = JSONobj.title;
console.log(headerTitle); // "exampleTitle"
Side note: By the time you've assigned it to the variable you've called JSONobj, it isn't JSON anymore, it's just a normal JavaScript object, so that name is a bit misleading. If you're writing source code, and you're not dealing with a string, you're not dealing with JSON anymore. :-)
I'm consuming a rest service with ServiceSatck framework. Now I want to get the raw bytes.
Suppose the url is http://xx.xxx.xxx.xx/Myservice/api/hello.
In this Seeing the Http Response content in ServiceStack it seems to be using get method but I used post method.
EDIT:
I used the code
`var x = "http://xx.xxx.xxx.xx/Myservice/api/hello".PostJsonToUrl(new MyRequestDTO() { RequestData = hello }).ToArray();
I did get the raw bytes. However comparing with RestSharp method, there are about 200 bytes lost.
Using RestSharp method, the code is:
var aResponse = restClient.Execute(MyRequestDTO);
byte[] bytes = aResponse.RawBytes;
The documentation for ServiceStack's typed .NET clients shows how you can access the raw bytes:
byte[] responseBytes = client.Get<byte[]>("/poco/World");
var dto = responseBytes.FromUtf8Bytes().FromJson<PocoResponse>();
dto.Result //Hello, World
Or as a Stream:
using (Stream responseStream = client.Get<Stream>("/poco/World")) {
var dto = responseStream.ReadFully().FromUtf8Bytes().FromJson<PocoResponse>();
dto.Result //Hello, World
}
You don't even need to use the type clients for getting raw bytes, you can just as easily use a HTTP Util extension method:
byte[] rawBytes = "http://example.org/Myservice/api/hello".GetBytesFromUrl();
HOW to POST JSON and retrieve bytes using HTTP Utils extensions
var dtoBytes = new MyRequestDTO { ... }.ToJson().ToUtf8Bytes();
var responseBytes = "http://example.org/Myservice/api/hello".PostBytesToUrl(
dtoBytes, contentType:"application/json");