How to make a script wait for a UnityWebRequest to finish for WebGL without a coroutine?
Hello!
I'm writing code that goes out to an API and gets data in JSON, I have created classes to use the JSON utility to decode this JSON. Therefore(As far as I'm aware) I need to use a method instead of a coroutine to return the data that I get from the JSON decode. So in order to make the method wait for the UnityWebRequest to finish, I was using a while method. I found out that it will make the WebGL freeze, So I've been trying to find a way to make it wait without using a coroutine.
Here's My Code:
public TaskList FindTasks()
{
const string URL = "https://api.harvestapp.com/v2/tasks";
using (UnityWebRequest www = UnityWebRequest.Get(URL))
{
www.SetRequestHeader("user-agent", "MyApp (max@benmiller.com)");
www.SetRequestHeader("Authorization", "Bearer " + AccessToken);
www.SetRequestHeader("Harvest-Account-Id", AccountID);
www.Send();
while (!www.isDone)
{
}
new WaitUntil(www.isDone);
if (www.isHttpError)
{
Debug.LogError("UnityWebError: " + www.error);
return null;
}
else
{
string Value = www.downloadHandler.text;
TaskList JsonData = JsonUtility.FromJson<TaskList>(Value);
return JsonData;
}
}
}
[Serializable]
public class TaskList
{
public List<Task> tasks;
}
[Serializable]
public class Task
{
public int id;
public string name;
public bool billable_by_default;
public string default_hourly_rate; // No clue what type this should be.
public bool is_default;
public bool is_active;
public DateTime created_at;
public DateTime updated_at;
}
Answer by Getsumi3 · Aug 14, 2020 at 08:54 AM
Hi.
I had a similar task with 2 cases.
Case 1: I was receiving a KeyValuePair json and to save it as intended I was in need to save the response as a Dictionary and not a List (to make sure that keys and values match). So Instead of using Unity's JSONUtility I was using MiniJSON(click for redirect) that works perfect inside coroutines and able to be saved as a Dictionary. Example:
public Dictionary<string, object> categories = new Dictionary<string, object>();
public IEnumerator GetJson()
{
//not familiar with SendRequestHeader so I'm using old WWWForms
WWWForm form = new WWWForm();
form.AddField("user-agent", user_agent);
form.AddField("auth-token", token);
form.AddField("account-id", accountId);
var uwr = UnityWebRequest.Post(url_api, form);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.LogFormat("Error downloading file: <color=red>{0}</color> | Error code: <color=red>{1}</color>", uwr.downloadHandler.text, uwr.error);
}
else
{
var jsonResponce = MiniJSON.Json.Deserialize(uwr.downloadHandler.text) as Dictionary<string, object>;
//saving data to a variable
categories = jsonResponce;
}
}
Case 2: Same as case 1 but the json was a mess and was using Unity's JSONUtility. The idea was to do 2 coroutines. First coroutine was UWR request. In this you're getting the response and saving it to a variable (without decoding). Second coroutine is the one that were waiting for first to finish and than decode the response. Example:
private string uwr_response = ' ';
private bool isLoaded = false;
private void Start()
{
LoadJson();
}
//this coroutine to get the response
public IEnumerator GetJson()
{
isLoaded = false;
//not familiar with SendRequestHeader so I'm using old WWWForms
WWWForm form = new WWWForm();
form.AddField("user-agent", user_agent);
form.AddField("auth-token", token);
form.AddField("account-id", accountId);
var uwr = UnityWebRequest.Post(url_api, form);
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.LogFormat("Error downloading file: <color=red>{0}</color> | Error code: <color=red>{1}</color>", uwr.downloadHandler.text, uwr.error);
}
else
{
uwr_response = uwr.downloadHandler.text;
isLoaded = true;
}
}
//this one to wait for response and decode
private IEnumerator WaitingForJson()
{
while (!isLoaded)
yield return new WaitForSeconds(0.1f);
TaskList.DecodeJson(uwr_response);
}
//this one to be called when you need the json (probably in Start() method)
private void LoadJson()
{
StartCoroutine(GetJson());
StartCoroutine(WaitingForJson());
}
[Serializable]
public class TaskList
{
public void DecodeJson(string json)
{
TaskList packedData = JsonUtility.FromJson<TaskList>(json);
}
}
Your answer
Follow this Question
Related Questions
Error in BUILD with UnityWebRequest but not in Editor 0 Answers
UnityWebRequest error on WebGL 0 Answers
How to retrieve nested JSON variable - sendMessage WebGL 0 Answers
UnityWebRequst. CORS problem. 0 Answers
How do I enable CORS in my webgl game? 0 Answers