Convert JSON curl to C# - c#

I have the following curl code:
curl 'localhost:8983/solr/sessions/update?commit=true' -H 'Content-type:application/json' -d '[{"Session_SessionId":"da7007e9-fe7a-4bdf-b9e4-1a55034cf08f","Session_HasComments":{"set":true}}]'
I am trying to convert to C#, but I am getting an error every time so unsure if my code is correct...
Here's what I have so far:
string path = "http://localhost:8983/solr/sessions/update?commit=true";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"Session_SessionId\":\"" + sessionId + "\"," +
"\"" + fieldName + "\":{\"set\":\"" + fieldValue + "\"}}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
It always seems to error () on this line:
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
The error i get is:
The remote server returned an error: (400) Bad Request.","StackTrace":" at System.Net.HttpWebRequest.GetResponse()
Any ideas? Thanks in advance!
Dave

Maybe it's that you have removed square brackets in your JSON content that you are streaming into request? Try adding the [ ] back to the start/end of data. Although the "BadRequest" is usually quite strict error that tells you that your HTTP request is malformed, your server may actually return that code also for other cases - like missing session id - which probably occurred here.
note the diff:
-d '[{"Session_SessionId":"da70.....
^ bracket
and
string json = "{\"Session_SessionId\":\"" + sessionId + "\"," + ....
^ no bracket
and the same at the end of data.
But, of course, that's just a guess. :)

Your request cannot be understood by the server. Did you check the output of json variable. I believe the JSON string is not generating properly.
Why don't you use JavaScriptSerializer.Serialize to create JSON string.

Your use the Update Handler with a JSON object will need to follow the JSON format outlined in Update JSON - Update Commands

As another user has suggested your JSON output does not match the CURL. Try the following rather than typing the text.
var data = new[]
{
new
{
Session_SessionId = "da7007e9-fe7a-4bdf-b9e4-1a55034cf08f",
Session_HasComments = new {set = true}
}
};
var json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(data);
Also, you are using the using keyword to write the data through, and attempt to handle response while inside the block - it probably does make a difference but it might be worth moving this outside this block.
Lastly, you may need to encode the data as a byte array.
Here is the code implementing the above suggestions.
string path = "http://localhost:8983/solr/sessions/update?commit=true";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
var data = new[]
{
new
{
Session_SessionId = "da7007e9-fe7a-4bdf-b9e4-1a55034cf08f",
Session_HasComments = new {set = true}
}
};
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(data);
byte[] byteData = new System.Text.ASCIIEncoding().GetBytes(json);
httpWebRequest.ContentLength = byteData.Length;
using (Stream stream = httpWebRequest.GetRequestStream())
{
stream.Write(byteData,0,byteData.Length);
}
HttpWebResponse resp = (HttpWebResponse)httpWebRequest.GetResponse();
string respStr = new StreamReader(resp.GetResponseStream()).ReadToEnd();
Console.WriteLine("Response : " + respStr);

Just use SolrNet. If you are doing this with Solr 4+, you need to download latest code and built it yourself, but that's very easy.

Dave, it worked for me.
You were missing square brackets. Just replace respective line with below:
string json = "[{\"Session_SessionId\":\"" + sessionId + "\"," +
"\"" + fieldName + "\":{\"set\":\"" + fieldValue + "\"}}]";

Related

C# Convert string to JSON errors

Part of a public class I have builds a data structure for dataTables plugin.
The code to build the data structure is:
var response = "{ \"data\": [";
response = response + "[";
response = response + "\"Clark, Keith\",";
response = response + "\"Corporate\",";
response = response + "\"XXX-XXX-XXXX\",";
response = response + "\"XXX-XXX-XXXX\",";
response = response + "\"XXXX#XXXX.com\"";
response = response + "],";
response = response + "[";
response = response + "\"Clark, Keith\",";
response = response + "\"Corporate\",";
response = response + "\"YYY-YYY-YYYY\",";
response = response + "\"YYY-YYY-YYYY\",";
response = response + "\"YYYY#XXXX.com\"";
response = response + "]";
response = response + "] }";
return response;
This runs fine and creates the table as expected. Where I am running into issues is when I try to add HTML markup to a field. I want to use a font awesome icon next to the name to indicate status like this:
<i class="fa fa-arrow-up" style="color: #00ff00;" aria-hidden="true">
I have tried modifying my code to read:
response = response + "\"<i class=\"\"fa fa-arrow-up\"\" style=\"\"color: #00ff00;\"\" aria-hidden=\"\"true\"\">Clark, Keith\",";
But now I am receiving an error that the JSON is not properly formatted. Am I missing something or can HTML markup not be used inside a JSON structure?
The problem is that you're generating an invalid json string literal.
"<i class=""fa fa-arrow-up"" style=""color: #00ff00;"" aria-hidden=""true"">Clark, Keith",
Quotes are escaped using literal backslashes, not doubling them.
You would have had to do this instead:
"\"<i class=\\\"fa fa-arrow-up\\\" style=\\\"color: #00ff00;\\\" aria-hidden=\\\"true\\\">Clark, Keith\","
This demonstrates why exactly you shouldn't be generating strings like this. There are tools out there that can do this for you and safely, use them. Json.net will make easy work out of this.
var markup = "<i class=\"fa fa-arrow-up\" style=\"color: #00ff00;\" aria-hidden=\"true\">";
var response = new JObject
{
["data"] = new JArray
{
new JArray
{
markup + "Clark, Keith",
"Corporate",
"XXX-XXX-XXXX",
"XXX-XXX-XXXX",
"XXXX#XXXX.com",
},
new JArray
{
markup + "Clark, Keith",
"Corporate",
"YYY-YYY-YYYY",
"YYY-YYY-YYYY",
"YYYY#XXXX.com",
},
}
};
return response.ToString();
With that said, you shouldn't be adding markup to your data. Data is data and nothing more. If you want to affect how it is displayed, that markup should be added to your view.

Deserialize JSON data with C#

I am a new user in C# and I'm haveing some problems with my code.
I cant deserialize JSON data and I cant understand why:
webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); // Create a request to get server info
webRequest.Method = "GET";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.CookieContainer = cookieJar; //set container for HttpWebRequest
webResponse = (HttpWebResponse)webRequest.GetResponse(); // Get the response.
reader = new StreamReader(webResponse.GetResponseStream());
ServerInfo outObject = JsonConvert.DeserializeObject<ServerInfo>(reader.ToString());
my_label_ServerInfo.Text = outObject.message;
the server info class:
public class ServerInfo
{
public string message { get; set; }
public string message_timestamp { get; set; }
}
In C#,
reader.ToString()
will by default return the name of the class. In this case, "System.IO.StreamReader"
What you want is
reader.ReadToEnd()
which will return the entire contents of the stream as a string.
That should cause it to work, but be aware that it's not best practice. A few areas for consideration as you learn more about C#:
As Aron mentioned, you should wrap all your streams and readers in "using" statement to take advantage of the Dispose pattern which will let the runtime know it can release resources right away rather than waiting for the finalizer
As Fred demonstrated in his code, you can avoid converting the stream to a string and just let the Json.Net library do that.
To ensure that you properly escape and format the request URL, you could use the UriBuilder class: new UriBuilder("http", ip, port, path).Uri)
You could use the newer and async friendly HttpClient class to download the data.
Although Jeff is correct in WHY it doesn't work correctly. His answer still isn't the correct way to "fix" your code. Strings are very inefficient in C# (like almost EVERY programming language, and we avoid them as much as possible).
So you should be doing this instead.
//STOP USING member fields (when possible),
//you encourage threading problems with member fields.
var webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........"); // Create a request to get server info
webRequest.Method = "GET";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.CookieContainer = cookieJar; //set container for HttpWebRequest
var webResponse = (HttpWebResponse)webRequest.GetResponse();
//ALWAYS dispose your disposable correctly
//Not disposing HttpStreams will cause you to leak TCP/IP
//ports.
using(var stream = webResponse.GetResponseStream())
using(var reader = new StreamReader(stream))
{
JsonSerializer serializer = new JsonSerializer();
ServerInfo outObject = (ServerInfo)serializer.Deserialize(reader, typeof(ServerInfo));
my_label_ServerInfo.Text = outObject.message;
}
What is the json that comes in your response body?
You might want to start off with a little test to make sure that the response body can correctly deserialize into your ServerInfo class. This is a matter of personal preference, but I like to do things a bit more explicitly as it helps to minimize unexpected behavior down the road.
For example, you could decorate your ServerInfo class like this:
// I chose MemberSerialization.OptIn so that all members need to be
// included explicitly, rather than implicitly (which is the default)
[JsonObject(MemberSerialization.OptIn)]
public class ServerInfo
{
[JsonProperty]
public string message { get; set; }
[JsonProperty]
public string message_timestamp { get; set; }
}
Then, you read the full HttpWebResponse body into a string like this:
reader = new StreamReader(webResponse.GetResponseStream());
string responseBody = reader.ReadToEnd();
reader.Close();
And lastly, you deserialize the response body into your ServerInfo class like this:
ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo>(responseBody);
This is assuming your json will come in the following format (or of a similar structure):
{
"message": "Test Message",
"message_timestamp": "2015-04-04T20:00:00"
}
Of course you should first check if your actual input deserializes correctly. I tried the format above in a unit test with this simple snippet:
var sb = new StringBuilder();
sb.Append("{");
sb.AppendLine();
sb.AppendFormat("\"{0}\": \"{1}\"", "message", "Test Message");
sb.Append(",");
sb.AppendLine();
sb.AppendFormat("\"{0}\": \"{1}\"", "message_timestamp", "2015-04-04T20:00:00");
sb.AppendLine();
sb.Append("}");
string json = sb.ToString();
ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo>(json);
EDIT: I completely agree with Aron in that you shouldn't unnecessarily use member fields and always make sure to dispose streams properly.
Improving my original answer with his suggestions, the following code I suggested earlier:
webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........");
webRequest.Method = "GET";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.CookieContainer = cookieJar;
webResponse = (HttpWebResponse)webRequest.GetResponse();
reader = new StreamReader(webResponse.GetResponseStream());
string responseBody = reader.ReadToEnd();
reader.Close();
ServerInfo serverInfo = JsonConvert.DeserializeObject<ServerInfo>
my_label_ServerInfo.Text = serverInfo.message;
Would change into this, which will perform better and is less prone to errors (I removed the comments for brevity, see Aron's answer for the explanations):
var webRequest = (HttpWebRequest)WebRequest.Create("http://" + Ip.ToString() + ":" + Port.ToString() + "........");
webRequest.Method = "GET";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.CookieContainer = cookieJar;
var webResponse = (HttpWebResponse)webRequest.GetResponse();
using (var stream = webResponse.GetResponseStream())
using (var reader = new StreamReader(stream))
{
JsonSerializer serializer = new JsonSerializer();
ServerInfo serverInfo = (ServerInfo)serializer.Deserialize(reader, typeof(ServerInfo));
my_label_ServerInfo.Text = serverInfo.message;
}
This will still work with the explicit JSON serialization attributes I added to your ServerInfo class. Note that they are not strictly necessary if the property names match up. I do this mainly just to show you how to gain more control over the serialization behavior without the need to implement a custom JsonSerializer.
I'd suggest the approach of accessing JSON values with structured JSON types (object and array), without having to predefine types (such as the ServerInfo type) to deserialize into.
JsonObject serverinfo = (JsonObject)JsonObject.Load(responseStream);

How to print all results of a JSON API call

I'm making a web-app that needs data through an API. I am trying to re-purpose some of the developer's example code of a different function than the original code was written for. Here's the important part:
WebRequest request = WebRequest.Create(urlPrefix + "getthingjson/" + Key);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
// Parse returned JSON into data
//
using (var web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
var jsonString = responseFromServer;
var jss = new JavaScriptSerializer();
var ThingsList = jss.Deserialize<List<Things>>(jsonString);
string ThingsListStr = "";
foreach (Things x in ThingsList)
ThingsListStr = ThingsListStr + ", " + x.Name;
MessageBox.Show(ThingsListStr);
}
I know that I need to change 'Name' in order to get a different piece of info on the 'Things' call. The thing is, I need to call results on a different function, instead of 'Things' say 'Details'. I don't know what to look for in place of 'Name' since when I search that it returns nothing. How could I just deserialize all of what JSON returns? Sorry if my terminology was off or I made a simple mistake, I'm new to JSON and C#. Thanks!
To get Details instead of Name property you should:
Check if you receive this data in json.
Adjust your c# class with Details property if it doesn't exist. (Go to Things class and add new Details property)
Change
ThingsListStr = ThingsListStr + ", " + x.Name;
to
ThingsListStr = ThingsListStr + ", " + x.Details;

save picture in cloud

I am saving data on Buddy cloud. Earlier I was saving string data and it was fine. Now I have to save picture but I am getting exception "Bad Request". Actually, they specify that its type should be "file". I don't know how to specify that. Below is the code and I have to do this using API.
documentation: http://dev.buddyplatform.com/Home/Docs/Create%20Picture/HTTP?
byte[] image = File.ReadAllBytes(imagePath);
string url = "https://api.buddyplatform.com/pictures";
// how to specify type below line ? how to correct ?
string parameters = "{data:'" + image + "'}";
HttpWebRequest request = null;
HttpWebResponse response = null;
request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Add("Authorization", "Buddy " + SharedData.buddyTOKEN);
// send request
StreamWriter sw = new StreamWriter(await request.GetRequestStreamAsync());
sw.WriteLine(parameters);
sw.Close();
// get response
response = (HttpWebResponse)await request.GetResponseAsync();
You won't be able to create the request body (your parameters string) by concatenating a string with a byte[]. This will end up calling ToString() on a byte[], leaving you with a request that looks like:
{ data:'System.Byte[]' }
Since this is being sent as a JSON request, it's likely that Buddy is expecting a base64 encoded file. This is how you would encode your file in base64 and insert it into the request:
string parameters = "{data:'" + Convert.ToBase64String(bytes) + "'}";
Result:
{data:'FxgZGurnIBlBCtIAIQ[...rest of your file...]'}

Send object through HttpWebRequest (REST Service)

I have a REST Service that accepts a id in the URL for PUT requests. So far the PUT request looks like this:
string url = "http://localhost:3596/WidgetManager.svc/Widgets/" + TextBox3.Text;
WebRequest req = WebRequest.Create(url);
req.Method = "PUT";
using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(resp.GetResponseStream());
Label4.Text = reader.ReadToEnd();
}
But I also need to send a Widget object in my request.
Widget w = new Widget();
w.Name = "worked!!!";
w.CogCount = 1000;
w.SprocketSize = 2000;
I saw a lot of examples on how to send strings. But what about objects like this?
You could serialise it using XML or JSON.
If it is such a small object, you could write your own small method like
.toJSON() {
return '{"Name":"' + this.name + '", "CogCount":' + this.CogCount + ', "SprocketSize":' + this.SprocketSize + '}';
}
//Output: '{"Name":"worked!!!", "CogCount":1000, "SprocketSize":2000}'
On the other hand: C# provides powerful (XML) serialisation tools!
This here: http://www.codeproject.com/Articles/1789/Object-Serialization-using-C is only one of many examples.
But if you use PHP or similar, JSON might even be more interesting.

Categories

Resources