Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: [. - c#

I'm doing C# JSON <-> PHP JSON for the first time.
Thought I'd get on an easy road but seems like I've hit the rock.
I'm fairly sure that JSON from Newtonsoft allows "[" character but not sure why i have this error instead?
Here's my C# code:
public class SystemJSON
{
public bool Status { get; set; }
public string Message { get; set; }
public string ResponseData { get; set; }
}
public static class SystemCall
{
public static String Post(string uri, NameValueCollection pairs)
{
byte[] response = null;
using (WebClient wc = new WebClient())
{
response = wc.UploadValues(uri, pairs);
}
return Encoding.Default.GetString(response);
}
}
string system_Response = SystemCall.Post("http://127.0.0.1:8080/edsa-NEFS%20(PHP)/api.php", new NameValueCollection()
{
{"do_work", Functions.Get_Department_List.ToString()},
{"api_data", null }
});
**SystemJSON systemJSON = JsonConvert.DeserializeObject<SystemJSON>(system_Response);** //<-- Error happens here.
if(systemJSON.Status == true)
{
//do stuff here
}else
{
MessageBox.Show(this, systemJSON.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
And here's my PHP code:
<?php
// Load Request
$function_name = isset($_POST['do_work']) ? $_POST['do_work'] : '';
$api_data = isset($_POST['api_data']) ? $_POST['api_data'] : '';
// Validate Request
if (empty($function_name))
{
SystemResponse(false, 'Invalid Request');
}
if (!function_exists($function_name))
{
SystemResponse(false, 'API Method Not Implemented');
}
// Call API Method
call_user_func($function_name, $api_data);
/* Helper Function */
function SystemResponse($responseStatus, $responseMessage, $responseData = '')
{
exit(json_encode(array(
'Status' => $responseStatus,
'Message' => $responseMessage,
'ResponseData' => $responseData
)));
}
/* API Methods */
function Get_Department_List($api_data)
{
//Test ------------------------------------------START
$node = array();
$dept = array();
$responseData = array();
$dept['id'] = 1;
$dept['name'] = "General";
$dept['description'] = "Forms, Samples, Templates, Catalogs, etc";
$dept['status'] = 1;
array_push($node, $dept);
$dept['id'] = 2;
$dept['name'] = "Test";
$dept['description'] = "Testing";
$dept['status'] = 1;
array_push($node, $dept);
$responseData["dept"] = $dept;
SystemResponse(true, 'SUCCESS', $responseData);
//Test ------------------------------------------END
}
?>
And here's my error:
Newtonsoft.Json.JsonReaderException HResult=0x80131500
Message=Unexpected character encountered while parsing value: {. Path
'ResponseData', line 1, position 51.

The problem is that your C# SystemJSON class does not match the structure of the incoming JSON correctly.
ResponseData in your C# SystemJSON class is listed as a string but your PHP appears to be pushing out a complex object inside that property. You can't deserialise an object into a string - there is no way for the deserialiser to know how to translate the object structure into a suitable string, and anyway it's not generally a useful or logical thing to do. So instead it throws an error to say the object structure doesn't match.
The specific error you're seeing means the deserialiser is expecting a " to denote the start of a string but instead it's seeing { denoting the start of another object.
Why is this happening? Well, your PHP code will produce a JSON response which looks like this:
{
"Status": true,
"Message": "SUCCESS",
"ResponseData": {
"dept": {
"id": 2,
"name": "Test",
"description": "Testing",
"status": 1
}
}
}
Live demo here
As you can see, ResponseData contains an object, which has a "dept" which in turn is another object with four more properties.
To deserialise this properly, your SystemJSON class will need to be altered, and you'll also need two sub-classes to help it out:
public class SystemJSON
{
public bool Status { get; set; }
public string Message { get; set; }
public ResponseData ResponseData { get; set; }
}
public class ResponseData {
public Department dept {get; set; }
}
public class Department {
public string id {get; set; }
public string description {get; set; }
public int status {get; set; }
}
You will now be able to deserialise the JSON correctly. Here is a live demo of the deserialisation.
P.S the [ character appears to be irrelevant here...it's unclear why you referred to that in your question.
P.P.S. From looking at your PHP I'm guessing that you may be intending to return different data structures in ResponseData depending on which parameter was specified for do_work - i.e. depending on which PHP function is called. If so then you'll need to amend your C# accordingly so that it deserialises to a different concrete class depending on which API method it requests. Or you could possibly cheat and specify ResponseData as dynamic, which will then accept any data structure it received, albeit with the caveat that it's now effectively loosely-typed and so you lose certain benefits when compiling the code such as checking for valid usage of property names, data types etc.

Related

Convert JSON containing `\u####` to Unicode string

I would need some help for a string conversion from unicode (\u03a9\u039c\u0395\u0393\u0391) to normal string (ΩΜΕΓΑ).
I made a function that theoretically should work but it doesn't work instead. I don't understand what I'm doing wrong.
I receive json data with webclient.DownloadString:
{"id": "94401626335", "username": "\u03a9\u039c\u0395\u0393\u0391"}
I get the \u03a9\u039c\u0395\u0393\u0391 and send it to the function:
DecodeFromUtf8(username)
public string DecodeFromUtf8(string utf8String)
{
try
{
var output = WebUtility.HtmlDecode(utf8String);
return output;
}
catch (Exception ex)
{
return utf8String;
}
}
the function always returns me: \u03a9\u039c\u0395\u0393\u0391
and not: ΩΜΕΓΑ
Why?
i can't use external libraries like system.text.json
Thanks
use a json deserializer , let it do the work
public class Ooo {
public string id { get; set; }
public string username { get; set; }
}
var json = #"{""id"": ""94401626335"", ""username"": ""\u03a9\u039c\u0395\u0393\u0391""}";
var ooo = System.Text.Json.JsonSerializer.Deserialize<Ooo>(json) ;
Console.WriteLine("string = " + ooo.username);
}
gives (my console has a glyph misssing, but its show correctly in the debugger)

RestSharp How to deal with different JSON response formats for same query

I've been fighting with this for a while and I think is time to ask for some help.
I'm using RestSharp to connect to my local PHP REST API. The format I'm returning the api results is as follows (JSON):
{
"estado": "login_correcto",
"content": {
"id": 1,
"nombreusuario": "daniaguado",
"contrasena": "qwerty",
"email": "daniel#zadecon.com",
"nivelacceso": 5,
"created_at": "2017-08-01 10:31:16",
"updated_at": "-0001-11-30 00:00:00"
}
}
For this, I've created a custom Usuario class (User) and a custom ResponseUsuario as follows:
class Usuario
{
public int id { get; set; }
public string nombreusuario { get; set; }
public string contrasena { get; set; }
public string email { get; set; }
public int nivelacceso { get; set; }
public string created_at { get; set; }
public string updated_at { get; set; }
}
Then the ResponseUsuario:
class ResponseUsuario
{
public string estado { get; set; }
public Usuario content { get; set; }
}
The response is being parsed ok when the response is ok (202) and the user exists.
But, when the login is incorrect, in "content" I'm returning a message, not an User:
{
"estado": "login_incorrecto",
"content": "La contraseña es incorrecta / Password incorrect"
}
So, If I use ResponseUsuario there, queryResult.Data is null, because it cannot map the content to the Usuario class. The fact is that if I don't use ResponseUsuario and instead use a Response class, in which content variable is type object, I cannot cast it to Usuario and I cannot deal with it.
This is the more general Response class which I understand I should be using for all my queries:
class Response
{
public string estado { get; set; }
public object content { get; set; }
}
Finally, this is my RestSharp query:
ApiClient api = new ApiClient(); // Just create the client with some common parameters
var request = new RestRequest("usuarios/login", RestSharp.Method.POST);
request.AddParameter("nombreusuario", textbox_usuario.Text);
request.AddParameter("contrasena", textbox_contrasena.Text);
var queryResult = api.cliente.Execute<ResponseUsuario>(request);
if (queryResult.StatusCode == System.Net.HttpStatusCode.OK)
{
Usuario u = (Usuario) queryResult.Data.content; // Gives error when using Execute<Response> (object content)
String s = queryResult.Data.estado;
Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
}
else
{
Console.Out.WriteLineAsync($"Query Failed: {queryResult.StatusDescription}, estado: {queryResult.Data.estado}"); // Giving error when using Execute<ResponseUsuario>
}
How can I fix the cast to Usuario (or the matching class for content)? I think the Response class should be common to all my queries to the API and then cast the Content part to it's appropiate class, but I don't know how to do it.
Really late to the party. I have met a similar problem when an API returned different structures on error vs. 200. I gave up RestSharp's typed call and explicitly deserialize the payload.
var response = RestClient.Execute<IdamValidationResultApiModel>(request);
if (response.IsSuccessful)
var t1 = JsonConvert.DeserializeObject<FirstType>(response.Content);
else
var t2 = JsonConvert.DeserializeObject<SecondType>(response.Content);
check if (queryResult.Data.content is Usuario) and cast only if it is true
else cast to string.
Does each response return a different Http status code? I'm guessing that you're returning a 401 from your rest api. If this is the case:
You can then use a switch to deal with other status codes.
HttpStatusCode statusCode = queryResult.StatusCode;
int numericStatusCode = (int)statusCode;
switch (numericStatusCode)
{
case 202:
dynamic content = queryResult.Data.content;
Usuario u = content.content;
String s = queryResult.Data.estado;
Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
break;
case 401:
//Deal with the failed login
break;
}
Finally, the reason that you're getting an error, is because you're trying to cast the response object which is of type UsarioResponse to Usario. You need to navigate the json to find content.content (as seen above)
I finally solved the issue by generating a custom Reflection from the Dictionary Object to the class, that is, at the end, a custom parser.
I created a new class Tools and added a conversion function:
public static T CastToObject<T>(IDictionary<string, object> dict) where T : class
{
Type type = typeof(T);
T result = (T)Activator.CreateInstance(type);
foreach (var item in dict)
{
type.GetProperty(item.Key).SetValue(result, item.Value, null);
}
return result;
}
And on the Api Query, added a switch-case depending on the Status code:
var queryResult = api.cliente.Execute<Response>(request);
switch(queryResult.StatusCode)
{
case System.Net.HttpStatusCode.OK:
Usuario u = Tools.CastToObject<Usuario>((IDictionary<string, object>)queryResult.Data.content);
String status = queryResult.Data.estado;
Console.Out.WriteLineAsync($"OK - {u.nombreusuario} - {u.email} - Acceso: {u.nivelacceso}");
break;
case System.Net.HttpStatusCode.NotFound:
Console.Out.WriteLineAsync($"Login Failed: User does not exists");
break;
case System.Net.HttpStatusCode.Unauthorized:
Console.Out.WriteLineAsync($"Login Failed: Incorrect Password");
break;
default:
Console.Out.WriteLineAsync($"Error when connecting to the API");
break;
}
Further I'll need to deal with responses containing list inside the content field but I think the procedure will be something similar to this one: to create a custom parser for the content field and cast it to my class.

A better way to deserialize JSON?

I am posting to an API that may return either 1 of the following 2 formats of JSON strings:
{
"MessageType": 6,
"Message": "Unable to SAVE new record. Invalid posted data."
}
or
{
"Model": {
"Id": "1-6Q0RZ9",
...
},
"ResponseResult": {
"MessageType": 10,
"Message": "Successfully saved, Record Id = 1-6Q0RZ9"
}
}
I need to retrieve the results from MessageType and have tried every if condition I can think of to read the results, because the syntax or retrieving the key:value is different for each JSON string, and there are no other flags to trigger one or the other. So the code I used is:
string result = eml.PostData("API/Save", dataJSON.ToString());
var returnresult = new JavaScriptSerializer().Deserialize<dynamic>(result);
try {
var responseresults = returnresult["ResponseResult"];
rr = responseresults["MessageType"];
rrtxt = responseresults["Message"];
} catch (Exception ex) {
rr = returnresult["MessageType"];
rrtxt = returnresult["Message"];
}
Which works great. If there is a valid Db post it returns the second JSON which is parsed correctly by the TRY statement, if not it throws a "key not found" error and parses the returned string in the CATCH statement (the first JSON example). Obviously this is horrible code but I cannot think of another way to do this, and I was wondering if anyone had suggestions? (please?)
Thanx in advance.
How about deserializing the response to an object with all of the properties on each return type and then just checking the values?
public class ReturnObject
{
public YourModel Model {get;set;}
public ResultObject ResponseResult {get;set;}
public int? MessageType {get;set;}
public string Message {get;set;}
}
string result = eml.PostData("API/Save", dataJSON.ToString());
var returnresult = new JavaScriptSerializer().Deserialize<ReturnObject>(result);
{
if(returnresult.MessageType.HasValue)
{
var messageType = returnResult.MessageType.Value;
etc etc.
}
}

How to Deserialize a JSON array in List (C#)

I am struggling with a subject that has a lot of variants in this forum but I can't seem to find one that suits me, and I think it's because of the way that my JSON array is :(
I'm not an expert but I already manage to "almost" get the end...
I need to get hand in "Success" and "Status" value. But also the different "Addresses".
My JSON (is called responseFromServer):
{
"success":true,
"addresses":
[
{"DPID":658584,"SourceDesc":"Postal\\Physical","FullAddress":"1/8 Jonas Street, Waimataitai, Timaru 7910"},
{"DPID":658585,"SourceDesc":"Postal\\Physical","FullAddress":"2/8 Jonas Street, Waimataitai, Timaru 7910"},
{"DPID":658583,"SourceDesc":"Postal\\Physical","FullAddress":"3/8 Jonas Street, Waimataitai, Timaru 7910"}
],
"status":"success"
}
Then, based on lot of examples in this forum, taking bits and pieces I created my classes:
public class jsonDataTable
{
public bool success { get; set; }
public IEnumerable<dtaddresses> addresses { get; set; }
public string status { get; set; }
}
public class dtaddresses
{
public int DPID { get; set; }
public string SourceDesc { get; set; }
public string FullAddress { get; set; }
}
Then I'm going to Deserialize:
public void _form_OnCallingAction(object sender, ActionEventArgs e)
{
...
...
JavaScriptSerializer js = new JavaScriptSerializer();
jsonDataTable jsonArray = js.Deserialize<jsonDataTable>(responseFromServer);
...
string tb = jsonArray.status.ToString();
string tb2 = jsonArray.success.ToString();
...
...
List<dtaddresses> _listAddresses = new List<dtaddresses>
{
new dtaddresses()
};
...
...
try
{
string tb3 = _listAddresses.Count.ToString();
string tb4 = _listAddresses[0].FullAddress;
}
catch (Exception ex)
{
CurrentContext.Message.Display(ex.Message + ex.StackTrace);
}
...
...
...
CurrentContext.Message.Display("Raw Response from server is: {0}", responseFromServer);
//Returns all the content in a string to check. OK! :)
CurrentContext.Message.Display("The success value is: {0} ", tb);
//Returns the Status Value (in this case "success") OK! :)
CurrentContext.Message.Display("The status value is: {0} ", tb2);
//Returns the Success Value (in this case "true") giggity giggity! All Right! :)
CurrentContext.Message.Display("The n. of addresses is: {0} ", tb3);
//Returns how many addresses ( in this case is returning 0) not ok... :(
CurrentContext.Message.Display("The address value is: {0} ", tb4);
// Returns the Fulladdress in index 0 (in this case nothing...) not ok... :(
Can any one help me to understand why I can access the values in the "dtaddresses" class?
This is the far that I went...
The following piece of code I copied from your question is creating a brand new list that has nothing to do with your deserialized data. Thus it's always going to be a single element list, where the first element contains only default values, which is what you are seeing in tb3 and tb4 later on.
List<dtaddresses> _listAddresses = new List<dtaddresses>
{
new dtaddresses()
};
Instead, assign jsonArray.addresses to _listAddresses, such as:
List<dtaddresses> _listAddresses = jsonArray.addresses.ToList()
Or you can forget about _listAddresses completely, and just simply reference jsonArray.addresses directly, such as:
string tb3 = jsonArray.addresses.Count().ToString();
string tb4 = jsonArray.addresses.First().FullAddress;

Dictionary of Objects doesn't work as JSON

I have spent WAY too much time trying to figure out how to pull all the values I need to from my C# application using JS and JSON. It works fine when I just use simple structures, such as an array, but I need to be able to grow the list at runtime.
Right now, the best I could figure out was doing a Dictionary with an incrementing key value, and the other 3 values as a class object. However, this seems to crash out my C# application.
What would be the best way to do this?
Relevant C# Code:
public class ChatData
{
string userName;
string message;
System.DateTime timestamp;
public ChatData(string name, string msg)
{
userName = name;
message = msg;
timestamp = System.DateTime.Now;
}
}
else if (string.Equals(request, "getchat"))
{
//string since = Request.Query.since;
Dictionary<int, ChatData> data = new Dictionary<int, ChatData>();
data.Add(1, new ChatData("bob", "hey guys"));
data.Add(2, new ChatData("david", "hey you"));
data.Add(3, new ChatData("jill", "wait what"));
return Response.AsJson(data);
}
Relevant Javascript:
function getChatData()
{
$.getJSON(dataSource + "?req=getchat", "", function (data)
{
//$.each(data, function(key, val)
//{
//addChatEntry(key, val);
//})
});
}
You haven't explained what Response.AsJson is and how it is implemented but if it uses JavaScriptSerializer you will get the following exception:
Unhandled Exception: System.ArgumentException: Type
'System.Collections.Generic. Dictionary`2[[System.Int32, mscorlib,
Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089],[ChatData, Test, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null]]' is not supported for
serialization/deserialization of a dictionary, keys must be strings or
objects.
which is pretty self-explanatory. You cannot use integers as keys if you intend to JSON serialize this structure. Also because your ChatData class no longer has a default/parameterless constructor you won't be able to deserialize a JSON string back to this class (but I guess you don't need this yet).
So one possible solution to your problem would be to use:
Dictionary<string, ChatData> data = new Dictionary<string, ChatData>();
data.Add("1", new ChatData("bob", "hey guys"));
data.Add("2", new ChatData("david", "hey you"));
data.Add("3", new ChatData("jill", "wait what"));
Now of course this being said and looking at the javascript you commented out and what you intend to do, as I already explained you in your previous question, dictionaries are not serialized as javascript arrays, so you cannot loop over them.
Long story short, define a class:
public class ChatData
{
public string Username { get; set; }
public string Message { get; set; }
public DateTime TimeStamp { get; set; }
}
and then fill an array of this class:
var data = new[]
{
new ChatData { Username = "bob", Message = "hey guys" },
new ChatData { Username = "david", Message = "hey you" },
new ChatData { Username = "jill", Message = "wait what" },
};
return Response.AsJson(data);
and finally consume:
$.getJSON(dataSource, { req: 'getchat' }, function (data) {
$.each(data, function(index, element) {
// do something with element.Username and element.Message here, like
$('body').append(
$('<div/>', {
html: 'user: ' + element.Username + ', message:' + element.Message
})
);
});
});
Why not simply use a typed list? Also, you'll need a default constructor to serialize/deserialize it. Note how I've modified your class to use properties
as well. Note, as #rudolf_franek mentions, you can add an ID property to the ChatData class if you need to be able to link to it.
public class ChatData
{
public ChatData()
{
TimeStamp = DateTime.Now;
}
public int ID { get; set; }
public string Who { get; set; }
public string Said { get; set; }
public DateTime TimeStamp { get; set; }
}
...
var data = new List<ChatData>
{
new ChatData { ID = 1, Who = "bob", Said = "hey guys" },
...
};
return Response.AsJson( data );

Categories

Resources