EDIT2: So, after a few hours of more testing, … it seems that UIToolkit works fine with async/await methods, but it’s HttpWebRequest (from Microsoft) that it has problems with. When I did a drop-in replacement using the more modern HttpClient class (also from Microsoft) then everything worked fine and as expected. It is possible that something on the web changed while I was testing/debugging. I’m going to assume it’s some set of issues inside HWR (which is much older than HttpClient) and stop worrying about it :). I’ll leave this thread here in case anyone else runs into similar issues. But TL;DR: “async/await works fine, if they don’t - it’s something else broken. Probably HttpWebRequest! Instead … use HttpClient!”
EDIT1: It seems like any use of a C# ‘async’ method crashes if it tries to access elements in the UIToolkit hierarchy (I changed my example below to not use GCE at all, and the same crashes happen).
It seems (experimentally) that the GCE callback does something that breaks C#'s async/await.
I can invoke async methods during GCE callbacks, and they run fine.
However, if any async method at any time references anything in the UIToolkit hierarchy - Unity terminates execution. Something as innocuous as:
{
var container = new VisualContainer();
rootVisualContainer.Add( container );
callAsync( container );
}
public void async callAsync( VisualElement v )
{
Debug.Log( "v = "+v ); // this line crashes in Unity editor
}
NB: there are no errors. UIToolkit just kills execution. I’m not sure if this is a bug or if I’m doing something wrong - but I’m assuming there’s no situation in which UIToolkit should just be terminating without at least throwing an error of some kind.
Is this a known bug? Is UIToolkit incompatible with async/await? (Unity only finally became compatible with these core features about 2-3 years ago, so I guess UIToolkit maybe is still using some old code? But I thought the Editor is supposed to be compatible with C# async/await now).
In general, most UI objects should be considered “not thread-safe”.
If you want to have a web request update something that makes it’s way to the UI, you’ll need to have some level of indirection, such as a data notification queue or message pump. I believe it may be possible to schedule an update call with EditorApplication.update from a background thread, but I haven’t tested it. It would only invoked on the main thread.
Why are UI objects unsafe? Where is that documented? What threads are allowed to access them? Unity staff have been aggressively rewriting core engine code for the past 5 years to replace unsafe parts that could only run on the Main thread, or to throw exceptions in all cases where the rewrite wasn’t (yet) possible. I see no exceptions here.
NB: when using HttpClient I am seeing zero problems with async methods, everything is stable and consistent.
Just in general, both and Unity and with other native applications, you generally only run the UI updates on the main thread. Async/Await doesn’t necessarily run on another thread in Unity. It may actually run on the main thread if you’re not using custom scheduling or something from normal .NET that naturally runs on a background thread.
That being said, this could just be a weird GC incompatibility, as I wouldn’t be surprised if some UI objects are backed by C++ objects just like GO/MonoBehaviour/ScriptableObjects are, and things can get flaky on some native<->Managed transitions if there’s some corner case in the compiled IL.
I’d submit a formal bug report or min repro if it’s indeed working fine with HTTPClient.
I’ll use it for a few weeks first just to be sure :).
But if it works fine with HttpClient then I’m not sure it’s worth logging a bug. As I understand it: Microsoft considers HttpClient a complete replacement for all their other networking code (even though nothing is marked Obsolete, it’s de facto obsolete), so … it was my mistake to try using code that Microsoft now discourages (even though their docs don’t say that, informally they seem to discourage it on StackOverflow etc).
Assuming it continues working with HttpClient then … there are much more valuable issues I’d like to see fixed first (most of which I’ve logged bugs for already). But I’ll keep an eye on it and if it fails again I’ll report it.