UnityWebRequest result can't be deserialized to JSON

Started by
11 comments, last by NDraskovic 6 years, 2 months ago

Hey guys,

I have a really weird problem. I'm trying to get some data from a REST service. I'm using the following code:
 


private void GetTheScores()
    {
        UnityWebRequest GetCommand = UnityWebRequest.Get(url);
        UnityWebRequestAsyncOperation operation = GetCommand.SendWebRequest();

        if (!operation.webRequest.isNetworkError)
        {
            ResultsContainer rez = JsonUtility.FromJson<ResultsContainer>(operation.webRequest.downloadHandler.text);
            Debug.Log("Text: " + operation.webRequest.downloadHandler.text);
        }
    }

The problem is that when I'm in Unity's editor, the request doesn't return anything (operation.webRequest.downloadHandler.text is empty, the Debug.Log command just prints "Text: "), but when I enter the debug mode and insert a breakpoint on that line, then it returns the text properly. Does anyone have an idea why is this happening?

The real problem I'm trying to solve is that when I receive the text, I can't get the data from the JSON. The markup is really simple:


[{"id":1,"name":"Player1"},{"id":2,"name":"Player2"}]

and I have an object that should accept that data:


[System.Serializable]
public class ResultScript {

    public int id;
    public string name;    
}

There is also a class that should accept the array of these objects (which the JSON is returning):


[System.Serializable]
public class ResultsContainer {

    public ResultScript[] results;

}

But when I run the code (in the debug mode, to get any result) I get an error: ArgumentException: JSON must represent an object type. I've googled it but none of the proposed solutions work for me.

Also (regardless if I'm in the debug mode or not) when I try to do some string operations like removing or adding characters to the GET result, the functions return an empty string as a result

Can you help me with any of these problems?

Thank you

Advertisement

while my experience with json is limited the provided json does not seem to be correct, rather incomplete.

Either I would have done 

 


rez.results=JsonUtility.FromJson<ResultsContainer>(myJsonString);

or modified json as 


{"results":[{"id":1,"name":"Player1"},{"id":2,"name":"Player2"}]}

I am not sure if something else is the issue as I said I have limited experience here.

Tried it but now I get ArgumentException: JSON parse error: Missing a name for object member.

Did you try with the modified json? For modified json you can keep the original rez=JsonUtility.fromJson

I find Json To POJO Class converter really helpful. I know this isn't java, but the code helps. It is possible that the serialization from the object is not being done properly.

Yeah I changed it so that it looks like an object, but didn't help.

I pulled just one entry from the array and hardcoded it into the function, and then it converts the object properly, so in worst case scenario, I'll parse the string myself and convert them one by one. 

The other part of the question is still puzzling me.

I am not clear, single hardcoded entry  works for you. If you take single entry 


{"id":2,"name":"Player2"}

and it converts correctly, then please check the type you are converting as this is of type ResultScript and should not be able to convert ResultContainer.

It makes sense if you are doing conversion for ResultScript type one by one.

Also a small correction.


rez.results=JsonUtility.FromJson<ResultsScript>(myJsonString);

 

The unity forum however say that the json array deserialisation is not supported directly and you have to use a wrapper class

Please check that when you are using the modified json I mentioned in my previous reply you are using the following. 


rez=JsonUtility.FromJson<ResultsContainer>(myJsonString);

 

When you deserialize JSON in unity, the JSON must be one object (in your example you start with a list), also, if you ResultsContainer contains an array with ResultScript named "results", the returned JSON must contain a list with the same variable name, like this:

 


{
    "results": [{
            "id": 1,
            "name": "Player1"
        },
        {
            "id": 2,
            "name": "Player2"
        }
    ]
}

If you change your web service to return that JSON, maybe it will work.

I can't change the data on the server side, so I've added the "{\"results\": to the text I get (and of course the following closing bracket). Now I don't get any errors, but the results array is null.

If your top level data is an array, then your serializable object must also be an array.

An object with an array member is different from just an array. Thus, you want to de-serialize into an array. It sounds like Unity's JSON doesn't support that (although that's legal JSON -- arrays and objects are allowed at top level) and you can't change the server, so you're in a tough spot.

If your data comes back as "empty" then chances are that you're being hit by some kind of web security restriction. In general, scripts that run from domain X, will not have access to data loaded from domain Y, unless the headers on the response from domain Y specifically white-list domain X. This is to avoid credentials theft and cross-site scripting of various kinds. The concept is called "cross-origin resource sharing" and you can find a link about it here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Perhaps the Unity editor implements those restrictions, and the service you're talking to does not include the appropriate headers.

Try looking at the data in Wireshark to see what you actually get on the wire. Also, try looking in the Unity web request documentation for properties that may affect CORS.

enum Bool { True, False, FileNotFound };

Yeah, the data is just an array. I made my own simple parser, fortunatelly the data is not too complicated, so I'm just going trough the string and pulling out entries one by one and then using JSON to convert them to the objects I need, so let's say that this part is solved (it's not pretty, but it works). 

I managed to bypass the WebRequest problem by using WWW class instead of WebRequest, and that class works perfectly.

Thanks to everyone for your help.

This topic is closed to new replies.

Advertisement