StephenCleary / AsyncEx

A helper library for async/await.
MIT License
3.49k stars 358 forks source link

TestDispatcher #239

Closed TDishop closed 2 years ago

TDishop commented 3 years ago

Is there a way to control AsyncContextThread thread creation and also keep context/thread available for more than one set of tasks? For some integration test projects, I would like to create a TestDispatcher during test assembly initialization and use it to initially create many objects and then dispatch back to thread just like Assembly.Current.Dispatcher.Invoke would do. I didn't see any example like this. Seems like all examples just execute a limited set of operations on a context. Also, what is recommended approach for using in .netframework projects (.net48) since latest version is only .netstandard1.3 and 2.0 Should this be asked in a different issue? And there have been no updates recently. Is this because .netcore5 will supported more of this behavior out of the box?

AsyncContextThread.cs.txt TestDispatcher.cs.txt

StephenCleary commented 3 years ago

Is there a way to control AsyncContextThread thread creation and also keep context/thread available for more than one set of tasks?

Yes. This is considered an advanced usage, so some of the members are hidden from IntelliSense by default. You can create a new AsyncContextThread, and that instance will already be running its main loop. You can then queue tasks to it by using AsyncContextThread.Context.Factory, and when you're done with it you can call AsyncContextThread.JoinAsync to asynchronously wait for all continuations to complete.

For some integration test projects, I would like to create a TestDispatcher during test assembly initialization and use it to initially create many objects and then dispatch back to thread just like Assembly.Current.Dispatcher.Invoke would do.

AsyncContextThread provides a single-threaded context, but it does not provide an actual Win32 message pumping windows procedure loop. If your code under test is using Invoke and friends to update in-memory data structures (e.g., ViewModels that are not bound to actual UI components), then that would work fine. But if they're using Invoke to actually update UI components, then you would need to use a real Dispatcher instance like this (unsupported) code does.

Also, what is recommended approach for using in .netframework projects (.net48) since latest version is only .netstandard1.3 and 2.0?

net48 supports netstandard2.0, so it works fine with a normal NuGet install.

And there have been no updates recently. Is this because .netcore5 will supported more of this behavior out of the box?

No; .NET Core doesn't include much AsyncEx behavior. .NET has added a little bit over the years (and I remove it from AsyncEx when that happens). This library is mostly "done"; there's not many features planned. Better support for ValueTasks would be nice, as well as a few other optimizations, but overall there's not been a need to change this library recently.

TDishop commented 3 years ago

This is how I am calling: _asyncThread = new AsyncContextThread(); _asyncContext = _asyncThread.Context; _synchContext = _asyncContext.SynchronizationContext;

// call non async action on thread synchContext.Send( => { act(); }, null); // call non async function on thread return _synchContext.Send(() => { return myFunc(); }); // call asyn action return _synchContext.PostAsync(() => { return act(); }); // call async function return _synchContext.PostAsync(() => { return asyncFunc(); });

Are those correct or should I be using something simpler?

The only thing I can't do is control how the thread is created. I don't think I need the a windows procedure loop or pump messages but I would like to be able to set a control property so I don't have to add conditionals. That requires STA. Probably would be better to refactor out so that is not needed, but not sure how easy with some third party controls/libraries.

TDishop commented 3 years ago

Don't see anyway to force STA from outside Nito.AsyncEx

StephenCleary commented 3 years ago

I don't think I need the a windows procedure loop or pump messages... That requires STA.

An STA thread requires a message pump. It you do need an STA thread, then AsyncContextThread will not work for you. I'm not aware of any library that would provide this functionality, so I would recommend using WpfContext.