- Home /
Weird problem with Async Task and UnityWebRequest
Hi everyone Currently, I am struggling with a weird problem. I am using UnityWebRequest to retrieve data from an API and I am using async Tasks to do this. This is a basic working task which awaits the SendWebRequest() method:
public static async Task<T> Request<T>(string url)
{
UnityWebRequest request = fetchPrep(url); // function which prepares request for API fetch
await request.SendWebRequest();
if (request.isHttpError)
{
throw new System.Exception("HTTP ERROR " + request.error + url);
}
JsonSerializerSettings setting = jsonSerializerPrep();
string json = request.downloadHandler.text;
Debug.Log(json);
T fetch = JsonConvert.DeserializeObject<T>(json);
return fetch;
}
As I said this code works and there are no errors. Now I wanted to experiment with async tasks to improve this library: glTFast
But if I try to implement an async task with an await SendWebRequest() in the class GltfAsset.cs just like in my example, it doesn't work and says:
Assets\GLTFast\GltfAsset.cs(31,13): error CS1061: 'UnityWebRequestAsyncOperation' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'UnityWebRequestAsyncOperation' could be found (are you missing a using directive or an assembly reference?)
Could you explain why it is working in my example? I am using the same "using's" and in my example an own class in my own namespace with no extensions..
Thanks in advance!
Answer by sacredgeometry · Aug 10, 2019 at 09:01 AM
The exception tells you what the problem is.
UnityWebRequestAsyncOperation does not contain an extension method called GetAwaiter.
You cant await the result of SendWebRequest because its not an "async" method i.e. its not using the modern async/ await pattern.
Looking it up it seems to use an event/ callback instead.
see: Unitys example code
There is an even called completed that fires when the request returns. All you need to do is remove the async/ await modifiers and add a method for handling that callback event.
Failing that you could just use the much more mature libraries in .NETs Http namespace to do your http requests. or just yield return the result
I know this makes sense. But read the first part of my initial post. The await works for this first code snippet which I posted even tough it shouldn't... It's really weird and I don't have an explanation...
The await shouldn't work for line 4 as its not an await-able method call.
Edit: See the next comment for clarification
What you could do is wrap it in a task ins$$anonymous$$d.
Also: Whoops! Sorry for getting the lines mixed up I assumed it was there because that was the only await.
But my answer is relevant just swap out the line I am talking about to line 31 in the GltfAsset.cs file ins$$anonymous$$d
Answer by K0ST4S · Mar 27, 2020 at 07:34 AM
Async keyword calls GetAwaiter() method by default. You must have an extension method GetAwaiter() for UnityWebRequest or other web class. It does not work in that project because that project does not have reference to your main project, where the extension method is defined.
Answer by SujitKadam · Jun 19, 2020 at 01:09 PM
please check this: https://gist.github.com/krzys-h/9062552e33dd7bd7fe4a6c12db109a1a
Answer by Develax · Jul 02, 2021 at 08:24 PM
public static class UnityWebRequestExtension
{
public static TaskAwaiter<UnityWebRequest.Result> GetAwaiter(this UnityWebRequestAsyncOperation reqOp)
{
TaskCompletionSource<UnityWebRequest.Result> tsc = new();
reqOp.completed += asyncOp => tsc.TrySetResult(reqOp.webRequest.result);
if (reqOp.isDone)
tsc.TrySetResult(reqOp.webRequest.result);
return tsc.Task.GetAwaiter();
}
}
Usage:
string text = null;
UnityWebRequest req = UnityWebRequest.Get(url);
UnityWebRequest.Result result = await req.SendWebRequest();
if (result == UnityWebRequest.Result.Success)
text = req.downloadHandler.text;
else
Debug.LogError($"{result}: {req.error}");