I manged to get my json returned but I am having trouble returning it back into my class says cause its array. But I am using a deserialize method helper i studied from books. And should work.
So the question I need answered is how does my class need to be properly structured to decode the json into the city object.
I am grabbing my json via method which works
/// <summary>
/// Utility function to get/post WCFRESTService
/// </summary>
/// <param name="methodRequestType">RequestType:GET/POST</param>
/// <param name="methodName">WCFREST Method Name To GET/POST</param>
/// <param name="bodyParam">Parameter of POST Method (Need serialize to JSON before passed in)</param>
/// <returns>Created by David</returns>
private async Task<string> WCFRESTServiceCall(string methodRequestType, string methodName, string bodyParam = "")
{
string ServiceURI = "/launchwebservice/index.php/webservice/" + methodName;
HttpClient httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(methodRequestType == "GET" ? HttpMethod.Get : HttpMethod.Post, ServiceURI);
if (!string.IsNullOrEmpty(bodyParam))
{
request.Content = new StringContent(bodyParam, Encoding.UTF8, "application/json");
}
HttpResponseMessage response = await httpClient.SendAsync(request);
string jsongString = await response.Content.ReadAsStringAsync();
return jsongString;
}
Then I am using the deserialize method
public static class Helpers
{
public static List<T> Deserialize<T>(this string SerializedJSONString)
{
var stuff = JsonConvert.DeserializeObject<List<T>>(SerializedJSONString);
return stuff;
}
}
I am calling the above in the following manner
string jsonresult = await WCFRESTServiceCall("GET", "cinema_city");
var data = jsonresult.Deserialize<Citys>();
var dialog = new MessageDialog(jsonresult);
await dialog.ShowAsync();
Which when I check jsonresult it is indeed returning the json but in square brackets for some reason.
Which gives me the following error:
My Class of city is as follows
public class City
{
public string id { get; set; }
public string timing_title { get; set; }
}
public class Citys
{
public List<City> city { get; set; }
}
Edit To Show The jason data
{"city":[{"id":"5521","timing_title":"Lahore"},{"id":"5517","timing_title":"Karachi"},{"id":"5538","timing_title":"Islamabad"},{"id":"5535","timing_title":"Rawalpindi"},{"id":"5518","timing_title":"Hyderabad"},{"id":"5512","timing_title":"Faisalabad"},{"id":"8028","timing_title":"Gujranwala"},{"id":"8027","timing_title":"Gujrat"}]}
Edit to show error
Error on dezerilize event ?
For your classes json going to be:
For City class
{ id: "some string", timing_title:"some string" }
and for Citys class:
{ city: [ { id: "some string", timing_title:"some string" }, ... ] }
I belive you have a typo in property name - it is city now, but really should be cities.
Another issue I see is that you are mixing together Citys class and List. They are not the same and you cannot serialize/deserialize them to each other.
Correct json for List going to be:
[ { id: "some string", timing_title:"some string" } ,... ]
compare it to Citys class above.
UPDATE: After reading it again, you are trying to deserialize List to Citys. That is what your exeption says. Probably that is what you wanted to say:
public static class Helpers
{
public static T Deserialize<T>(this string SerializedJSONString)
{
var stuff = JsonConvert.DeserializeObject<T>(SerializedJSONString);
return stuff;
}
}
string jsonresult = await WCFRESTServiceCall("GET", "cinema_city");
var data = jsonresult.Deserialize<Citys>();
var dialog = new MessageDialog(jsonresult);
await dialog.ShowAsync();
Related
I am pulling data from API. I am getting an error while deserializing. please help me.
error:
System.Text.Json.JsonException: '',' is invalid after a single JSON value. Expected end of data. Path: $ | LineNumber: 0 | BytePositionInLine: 128.'
data i pull:
{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}
my c# codes:
Index.cs :
var result = await Api<Company>.pullDataAsync("https://localhost:5001/api/PesinIskontolar/companyGet");
api.cs:
public class Api<T> where T : class
{
public async static Task<T> pullDataAsync(string url)
{
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
IRestResponse response = await client.ExecuteAsync(request);
return Json_Convert<T>.deserializeProcess(apiFormat(response.Content));
}
public static string apiFormat(string response)
{
var result = response.Replace("\\", "").Replace("[","").Replace("]","");
return result.Substring(1, result.Length - 2);
}
}
Json_Convert.cs:
public class Json_Convert<T> where T : class
{
public static T deserializeProcess(string response)
{
return JsonSerializer.Deserialize<T>(response);
}
}
dal:
public string getCompany()
{
......
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
string data = JsonConvert.SerializeObject(dt);
baglanti.Close();
baglanti.Dispose();
return data;
}
api:
[HttpGet("companyGet")]
public IActionResult companyGet()
{
return Ok(_firmaServices.getCompany());
}
Since some friends said that there is a problem with the api, I added other codes.
company class:
public class Company
{
public int firmano { get; set; }
public string adi { get; set; }
}
Your JSON is invalid, should be:
[{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}]
instead of:
{"firmano":128257,"adi":"- FATİH YILMAZ"},{"firmano":128446,"adi":"-MEHMET ÜSTÜN"}
Also, instead of calling response.Content prior to deserialization, you need to call await response.Content.ReadAsStringAsync() method to actually read the returning json string from the server.
As you pulling a list of two companies, your deserialization should be deserializing to a list instead of a single object, so you need to delete the apiFormat method and call await Api<IEnumerable<Company>>.pullDataAsync instead of await Api<Company>.pullDataAsync
You should deserialize List< Company >, not just Company so use this code
var result = await Api<List<Company>>.pullDataAsync("https://localhost:5001/api/PesinIskontolar/companyGet");
and fix your generic code by removing apiFormat(response.Content), replace it by just content. it will prevent removing [] from your json, this is what causes an exception
public async static Task<T> pullDataAsync(string url)
{
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
IRestResponse response = await client.ExecuteAsync(request);
return Json_Convert<T>.deserializeProcess(response.Content); //fix here!!!
}
and according to your response.Content, you company class should be changed
public partial class Company
{
[JsonPropertyName("firmano")]
public int firmano { get; set; }
[JsonPropertyName("Column1")]
public string adi { get; set; }
}
1.Try to use known class as Company instate of
2.Json converter does not like special characters like '(Some times People are using the ' char, to write a letter like è, and this can bracke the Json String). You can do like .Replace("'", "''")
3.Use encoding UTF8.
4.Control the API Site in Debug and see the Response creation..
5. before subtracting the end 2 chars check if the string has this chars. better do this operations after you get the response.
return result.Substring(1, result.Length - 2);
I created a database with JSON columns in mysql.
API defined in Swagger.
Writing JSON to the database works without problems, but when reading, the value of the JSON field is shown as an escaped string and not JSON
Here is part of model:
/// <summary>
/// Gets or Sets Doc
/// </summary>
[DataMember(Name="doc")]
public Dictionary<string, string> Doc { get; set; }
I also tried with string type and Dictionary<string, object> but unsuccessful.
Get method is here:
public virtual IActionResult GetDataById([FromRoute][Required]int? dataId, [FromRoute][Required]string jsonNode)
{
if(_context.Data.Any( a => a.Id == dataId)) {
var dataSingle = _context.Data.SingleOrDefault( data => data.Id == dataId);
return StatusCode(200, dataSingle);
} else {
return StatusCode(404);
}
}
}
And resulting JSON resposne looks like this one:
{
"field1": "value1",
"field2": "value2",
"doc": "{\"key1\":\"value1\",\"key2\":\"value2\",\"key3\":{\"subkey3-1\":\"value3-1\",\"subkey3-2\":\"value3-2\"}}"
}
but correct JOSN should be linke this one:
{
"field1": "value1",
"field2": "value2",
"doc": {
"key1":"value1",
"key2":"value2",
"key3":{
"subkey3-1":"value3-1",
"subkey3-2":"value3-2"
}
}
}
If I try to return just "Doc" (JSON) field, response JSON is properly formatted.
I tried different serialization/deserialization but unsuccessful.
If I have public Dictionary<string, string> Doc { get; set; } in Model I got error:
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HM1VN0F0I0IM", Request id "0HM1VN0F0I0IM:00000001": An unhandled exception was thrown by the application.
System.InvalidOperationException: The property 'Data.Doc' is of type 'Dictionary<string, string>' which is not supported by current database provider. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
and for public string Doc { get; set; } in Model I got "doc" field value as escaped string as I mention above.
What would be the best way to go about this?
A few days later I found a resolution.
You need a one helper method that converts a string to object, exactly JObject if you use Json.NET - Newtonsoft.
public static JObject getJsonOutOfData (dynamic selectedData)
{
var data = JsonConvert.SerializeObject(selectedData);
var jsonData = (JObject)JsonConvert.DeserializeObject<JObject>(data);
if (selectedData.Doc != null) {
JObject doc = JObject.Parse(selectedData.Doc);
JObject docNode = JObject.Parse("{\"doc\":" + doc.ToString() + "}");
var jsonDoc = (JObject)JsonConvert.DeserializeObject<JObject>(docNode.ToString());
jsonData.Property("doc").Remove();
jsonData.Merge(jsonDoc, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Union
});
}
return jsonData;
}
and call it in the IActionResult method
public virtual IActionResult GetDataById([FromRoute][Required]int? accidentId, [FromRoute][Required]string jsonNode)
{
if (_context.Data.Any( a => a.Id == accidentId)) {
var accidentSingle = _context.Data.SingleOrDefault( accident => accident.Id == accidentId);
var result = getJsonOutOfData(accidentSingle);
return StatusCode(200, result.ToString());
} else {
return StatusCode(404);
}
}
In order to use unescaped JSON in POST/PUT requests, you should have a string type as a property type of JSON filed in the database model, and create an additional "request" model and set JSON property as "Object" type:
Database Model:
[DataMember(Name="doc")]
public string Doc { get; set; }
Request Model:
[DataMember(Name="doc")]
public Object Doc { get; set; }
For example Create model looks like:
public virtual IActionResult CreateData([FromBody]DataCreateRequest body)
{
var accidentObject = new Data() {
ColumnOne = body.ColumnOne,
ColumnTwo = body.ColumnTwo,
ColumnThree = body.ColumnThree,
Doc = (bodyDoc != null) ? body.Doc.ToString() : "{}"
};
_context.Data.Add(accidentObject);
_context.SaveChanges();
return StatusCode(200, getJsonOutOfData(accidentObject));
}
I need to wrap an api call with my own api to avoid CORS and so I can avoid exposing credentials to the client. Can anyone help me to figure out what I'm doing wrong?
This works in a webform but I don't know how to put its an api controller class.
When I try to return the objects with the code below it throws an error
Controller:
public class sampleController : ApiController
{
public IEnumerable<sample> GetSample()
{
string url = String.Format("sampleurl.json");
WebRequest requestObj = WebRequest.Create(url);
requestObj.Credentials = new NetworkCredentials("USER", "PW");
requestObj.Method = "GET";
HttpWebResponse responseObj = null;
responseObj = (HttpWebResponse)requestObj.GetResponse();
string str = null;
using (Stream stream = responseObj.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
str = sr.ReadToEnd();
sr.Close();
}
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
sample sampleList = (sample).ser.Deserializer(str, typeof(sample));
return sampleList.Root_Object;
}
}
Model:
public class sample
{
public List<Root_Object> Root_Object {get; set;}
}
public class Root_Object
{
public string listItemOne { get; set; }
public string listItemTwo { get; set; }
}
JSON
{
"Root_Object": [
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
},
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
},
{
"ListItemOne": "Value",
"ListItemTwo": "Value"
}
]
}
I expected to be able to return all objects from Root_Object. The return statement gives me an error of
"Cannot implicitly convert type 'System.Collections.Generic.IList<project.Models.Root_Object>' to 'System.Collections.Generic.IEnumerable<project.Models.sample>'. An explicit conversion exists(are you missing a cast?)"
Assuming the GetSample() method is supposed to be a pass-through API, meaning you don't intend to change the JSON format at all, then you need to make two changes:
Change the return type of your method from IEnumerable<sample> to sample
Change the method to return sampleList instead of sampleList.Root_Object.
If you're instead trying to "unwrap" the list of objects, then the other two answers are correct.
Should you not be returning IEnumerable<Root_Object> as the type? You currently have it as IEnumerable<sample>.
Your method requires a return type of IEnumerable<sample>, but you are returning sampleList.Root_Object, which is itself a list of Root_Object
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.
We have got a Odata response as below:
"{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}"
Now say we have a class:
public class myValidationResult
{
public myValidationResult()
{
Messages = new List<string>();
}
public List<string> Messages { get; set; }
public bool IsValidEntity { get; set; }
}
This class used in MyOdataController class as below:
public class MyODataController : ODataController
{
[Authorize(Roles = "Admin")]
public async Task<IHttpActionResult> Post(T entity)
{
myValidationResult vResult = new myValidationResult();
vResult.Messages.Add("message 1");
vResult.Messages.Add("message 2");
vResult.Messages.Add("message 3");
vResult.Messages.Add("message 4");
vResult.IsValidEntity = false;
var strResult = JsonConvert.SerializeObject(vResult);
var resp = Content(HttpStatusCode.BadRequest, strResult );
return resp;
}
}
For the client Consuming this, we created below Class:
public class OData<T>
{
[JsonProperty("odata.context")]
public string Metadata { get; set; }
public T value { get; set; }
}
In the method where we call the Odata method & store response in 'msg':
var resp = msg.Result.Content.ReadAsStringAsync().Result;
resp is:
"{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}"
var odatares = JsonConvert.DeserializeObject<OData<myValidationResult>>(resp);
But the above line giving error:
Can not convert value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false} to <.....namespace......>myValidationResult
Please suggest accordingly.
The OData response contains a string, not an instance of myValidationResult. Also, the response looks like it's missing some backslashes. (Are you sure the response shown is exactly what you received from the service?)
You can either fix the serialization of myValidationResult on the service:
// Don't serialize vResult yourself. OData will do it for you.
var resp = Content(HttpStatusCode.BadRequest, vResult );
Or deserialize in two steps as follows.
var data = "{\r\n \"#odata.context\":\"http://localhost/ApplicationService/model/$metadata#Edm.String\",\"value\":\"{\\\"Messages\\\":[\\\"message 1\\\",\\\"message 2\\\",\\\"message 3\\\",\\\"message 4\\\"],\\\"IsValidEntity\\\":false}\"\r\n}";
var outer = Newtonsoft.Json.JsonConvert.DeserializeObject<OData<string>>(data);
var inner = Newtonsoft.Json.JsonConvert.DeserializeObject<myValidationResult>(outer.value);
One more thing: The JsonProperty on OData<T> should be named #odata.context.
In my case the OData response did not contain a string but an object array which contains the data string as its first element. So in this case reading the data should look like this:
var outer = Newtonsoft.Json.JsonConvert.DeserializeObject<OData<object[]>>(data);
var inner = Newtonsoft.Json.JsonConvert.DeserializeObject<myValidationResult>(outer.value[0].ToString());