I'm having an issue while trying to read a Json string in unity.
I created Classes based on the json response im receiving
but im not able to deserialize this json
Where I did wrong, can anybody help?
{
"status": 200,
"isSuccess": true,
"message": "Suggestion Found",
"response": {
"result": [
{
"OriginalWord": "goodboy",
"suggests": [
{
"suggestWords": "good boy"
},
{
"suggestWords": "Cordoba"
},
{
"suggestWords": "Catawba"
},
{
"suggestWords": "Catawba's"
}
]
}
]
}
}
My Classes
[Serializable]
public class Suggest
{
[SerializeField]
public string suggestWords { get; set; }
}
[Serializable]
public class Result
{
[SerializeField]
public string OriginalWord { get; set; }
[SerializeField]
public List<Suggest> suggests { get; set; }
}
[Serializable]
public class Response
{
[SerializeField]
public int status { get; set; }
[SerializeField]
public bool isSuccess { get; set; }
[SerializeField]
public string message { get; set; }
[SerializeField]
public List<Result> result { get; set; }
}
Im Deserializing like this
Response response = JsonUtility.FromJson<Response>(jsonString);
Above every class there got to be [System.Serializable] this is because UnityEngine has its own implementation of Serializable so you got to indicate its the System's that you want to use rather then Unity's. You also dont need to have [SerializeField] since this is if you want to show the property in Unity's inspection window and since this will not go onto any gameobject you dont need this. You just got to make it public.
Also in the class public class Response if you want json to map correctly you wouldnt use public List<Result> result { get; set; }, it would have to be named response and it will have to be 1 object not a list. So you can create a class called Results and have it have a list variable called result and it will be a list of type Result (no s). and in the result it would have the OriginalWord and a list of Suggest called suggests
Moreover, you must have a constructor for each class for it to work. So it would look like this:
[System.Serializable]
public class Suggest
{
public string suggestWords;
public Suggest(string suggestWords)
{
this.suggestWords = suggestWords;
}
}
[System.Serializable]
public class Result
{
public string OriginalWord;
public List<Suggest> suggests;
public Result(string OriginalWord, List<Suggest> suggests)
{
this.OriginalWord = OriginalWord;
this.suggests = suggests;
}
}
[System.Serializable]
public class Results
{
public List<Result> result;
public Results(List<Result> result)
{
this.result = result;
}
}
[System.Serializable]
public class Response
{
public int status;
public bool isSuccess;
public string message;
public Results response;
public Response (int status, bool isSuccess, string message, Result response)
{
this.status = status;
this.isSuccess = isSuccess;
this.message = message;
this.response = response;
}
}
Related
First off, I am working with the Google recaptcha RESTful service trying to get the JSON object into a class. With WSDL's, Visual Studio will generate all this code for you so that it is easy to work with, but RESTful it seems you have to do everything yourself, am I missing something? I am working with VS2019 and would have thought there is some way to import this stuff to make life easy. I have yet to find anything, so...
Google is returning:
{
"success": false,
"error-codes": [
"invalid-input-response",
"invalid-input-secret"
]
}
I would like to deserialize it into this:
[DataContract]
public class GoogleReCaptchaResponse
{
[DataMember(Name = "success")]
public bool Success { get; set; }
[DataMember(Name = "error-codes")]
public List<string> ErrorCodes { get; set; }
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { get; set; }
}
I see the error-codes in the ExtensionData, but ErrorCodes is always null. What do I have wrong?
https://dotnetfiddle.net/RtjbwR
You should use JsonPropertyName attribute from System.Text.Json.Serialization namespace
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
public class GoogleReCaptchaResponse
{
[JsonPropertyName("success")]
public bool Success { get; set; }
[JsonPropertyName("error-codes")]
public List<string> ErrorCodes { get; set; }
}
public class Program
{
public static void Main()
{
GoogleReCaptchaResponse json = System.Text.Json.JsonSerializer.Deserialize<GoogleReCaptchaResponse>("{ \"success\": false, \"error-codes\": [\"invalid-input-response\",\"invalid-input-secret\"]}");
if (json.ErrorCodes == null)
{
Console.WriteLine("no Error Codes");
}
else
{
Console.WriteLine("Error Codes!");
}
}
}
I know it should work but it doesn't and i have no idea what the heck is wrong with that.
The Root["parameters"]-Dictionary is properly deserialized but the List of Parameter-References in root["paths"]["/alliances/"]["get"]["parameters"] is a bulk of null's.
I've shortened the Content. Origninal is here.
Switching from (my own) SwaggerParameter.Deserializable (which works fine in Root) to JSchema just changes from producing null's to throwing exception "Could not resolve schema reference '#/parameters/datasource'."
[TestClass()]
public class RootNode_Tests
{
static string s_sContent = #"{
""parameters"":{
""X-User-Agent"":{
""description"":""Client identifier, takes precedence over User-Agent"",
""in"":""header"",
""name"":""X-User-Agent"",
""type"":""string""
},
""datasource"":{
""default"":""tranquility"",
""description"":""The server name you would like data from"",
""enum"":[
""tranquility"",
""singularity""
],
""in"":""query"",
""name"":""datasource"",
""type"":""string""
}
},
""paths"":{
""/alliances/"":{
""get"":{
""operationId"":""get_alliances"",
""parameters"":[
{
""$ref"":""#/parameters/datasource""
},
{
""$ref"":""#/parameters/X-User-Agent""
}
]}
}
}
}";
[TestMethod]
public void Deserialize_Test()
{
TestRoot tr = JsonConvert.DeserializeObject<TestRoot>(s_sContent, new JsonSerializerSettings()
{
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead, // shouldnt be neccessary
Formatting = Formatting.Indented,
PreserveReferencesHandling = PreserveReferencesHandling.All,
TraceWriter = new DbgPrintTracer()
});
}
public class DbgPrintTracer : ITraceWriter
{
public TraceLevel LevelFilter => TraceLevel.Verbose;
public void Trace(TraceLevel level, string message, Exception ex) => Debug.Print($"{level}: {message} ({ex})");
}
public abstract class _TestBase
{
[JsonExtensionData]
public Dictionary<string, object> m_dictAdditional { get; protected set; }
}
public class TestRoot : _TestBase
{
[JsonProperty("parameters")]
//[JsonConverter(typeof(ParamCollectionConverter))]
//public Dictionary<string,SwaggerParameter.Deserializable> m_dictParameters { get; protected set; } /* DESERIALIZES PROPERLY */
public Dictionary<string, JSchema> m_dictParameters { get; protected set; }/* DESERIALIZES PROPERLY TOO */
[JsonProperty("paths")]
public Dictionary<string, Paths> m_dictPaths { get; protected set; }
}
public class Paths : Dictionary<string, Method>
{
}
public class Method : _TestBase
{
[JsonProperty("parameters")]
// [JsonConverter(typeof(ParamCollectionConverter))]
// public List<SwaggerParameter.Deserializable> m_lstParams { get; protected set; } /* ONLY NULL's, NO EXEPTIONS */
public List<JSchema> m_lstParams { get; protected set; } /* EXCEPTION: Couldnt resolve reference-Path. */
}
}
I have to create a post request in Json in this format.
{
"request": {
"application": "APPLICATION_CODE",
"auth": "API_ACCESS_TOKEN",
"notifications": [{
"send_date": "now", // YYYY-MM-DD HH:mm OR 'now'
"ignore_user_timezone": true, // or false
"content": "Hello world!"
}]
}
}
This is my first time serializing Json String and I have no idea how to do this, I have tried a few different things but could never get the exact format.
Would really appreciate any kind of help.
Thanks!
First, you cannot put comment on a json file, but I guess it was just there for now.
Then you can paste your json in converters like this one http://json2csharp.com/
And you get the following:
public class Notification
{
public string send_date { get; set; }
public bool ignore_user_timezone { get; set; }
public string content { get; set; }
}
public class Request
{
public string application { get; set; }
public string auth { get; set; }
public List<Notification> notifications { get; set; }
}
public class RootObject
{
public Request request { get; set; }
}
Now you need to fix a few issues that are required for JsonUtility:
[Serializable]
public class Notification
{
public string send_date;
public bool ignore_user_timezone;
public string content;
}
[Serializable]
public class Request
{
public string application;
public string auth;
public List<Notification> notifications;
}
[Serializable]
public class RootObject
{
public Request request;
}
Finally:
RootObject root = JsonUtility.FromJson<RootObject>(jsonStringFile);
You can also use SimpleJSON like this ;
string GetRequest () {
JSONNode root = JSONNode.Parse("{}");
JSONNode request = root ["request"].AsObject;
request["application"] = "APPLICATION_CODE";
request["auth"] = "API_ACCESS_TOKEN";
JSONNode notification = request ["notifications"].AsArray;
notification[0]["send_date"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
notification[0]["ignore_user_timezone"] = "true";
notification[0]["content"] = "Hello world!";
return root.ToString ();
}
My Activity code is:
private void MClient_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
string json = Encoding.UTF8.GetString(e.Result);
var Details = JsonConvert.DeserializeObject(json);
}
My doctor.cs class code is:
namespace App12
{
public class Doctor
{
public string DoctorId { get; set; }
public string doctorName { get; set; }
public string specialityId { get; set; }
public string experiance { get; set; }
public string fee { get; set; }
}
public class RootObject
{
public Doctor doctor { get; set; }
}
}
JSON array is:
{
"0": {
"DoctorId": "1",
"doctorName": "DR.Rama",
"specialityId": "1",
"experiance": "5 years",
"fee": "300rs"
}
}
I am trying to show this in textview but it gives me an error:
System.InvalidCastException: Specified cast is not valid.
You have two problems here.
Your class structure doesn't quite match up with the shape of the JSON data. This JSON isn't technically an array either; it's a dictionary. You need to deserialize into a Dictionary<string, Doctor>.
When calling JsonConvert.DeserializeObject you need to specify a type parameter. If you don't, the return type will be JObject. This may be the cause of the InvalidCastException.
Try it like this:
var dict = JsonConvert.DeserializeObject<Dictionary<string, Doctor>>(json);
From there you can loop through the doctors like this:
foreach (var doctor in dict.Values)
{
textView.Append(doctor.doctorName);
}
iam using a RequestClass with the Route anotation to call a Json-Client POST method.
Now, while the paramters are structured like this
public class GetTicketRequest: IReturn<JsonObject>
{
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
}
The BackendAPI needs them to be nesten in "data" in the json request, so more like
{
"data":[
{"cartid":123,
"priceId":11}]
}
Is there any way to transfrom the request object for the body before calling
JsonServiceClient _restClient = new JsonServiceClient(baseUrl);
JsonObject oneResponse = _restClient.Post(options);
This solution is useful where many DTOs require to be wrapped & converted, and is highly reusable, with no changes to your existing DTOs.
You can convert the requests of the JsonServiceClient by overriding the methods that handle preparing the requests for sending. Which means implementing your own extended JsonServiceClient as given below.
If you want to do this for all verbs then you override it's Send<TResponse> methods (otherwise, if it's just for POST then uncomment the commented out code, and remove the Send methods).
public class MyJsonServiceClient : JsonServiceClient
{
public Dictionary<Type, Func<object, object>> DtoConverters = new Dictionary<Type, Func<object, object>>();
public MyJsonServiceClient() {}
public MyJsonServiceClient(string baseUri) : base(baseUri) {}
public MyJsonServiceClient(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri) {}
public override TResponse Send<TResponse>(object request)
{
return base.Send<TResponse>(ConvertRequest(request));
}
public override TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request)
{
return base.Send<TResponse>(httpMethod, relativeOrAbsoluteUrl, ConvertRequest(request));
}
/*
public override TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object requestDto)
{
return base.Post(relativeOrAbsoluteUrl, ConvertRequest(requestDto));
}
*/
object ConvertRequest(object request)
{
Type dtoType = request.GetType();
return (DtoConverters.ContainsKey(dtoType)) ? DtoConverters[dtoType](request) : request;
}
}
Usage:
So given this DTO:
[Route("/test", "POST")]
public class TicketRequest : IReturnVoid
{
public string CartId { get; set; }
public string PriceId { get; set; }
}
You simply add the converter:
var client = new MyJsonServiceClient("http://localhost:9000");
// Simple converter for TicketRequest
client.DtoConverters.Add(typeof(TicketRequest), dto => {
var d = (TicketRequest)dto;
return new {
data = new {
CartId = d.CartId.ToInt(),
PriceId = d.PriceId.ToInt()
}
};
});
client.Post(new TicketRequest { CartId = "123", PriceId = "456" });
i solved this issue using a typed data property
public class GetTicketRequest: IReturn<JsonObject>
{
public class TicketCreateData
{
public int priceId {
get;
set;
}
}
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
public List<TicketCreateData> data {
get {
var list = new List<TicketCreateData>();
list.Add(new TicketCreateData {
priceId = this.PriceId.ToInt()
});
return list;
}
set {
data = value;
}
}
}
To notes on this:
if neede, use DataContract/DataMember(Name="") to rename fields or only do partial serializing
Do never use structs for, like in this case, the data class - they are not serializeable at all
in my spefici case data even needs to be an array, thats why i used the list