15

Does something like Dispatcher exist for .NET Core?

I need to create a thread in .NET Core, and be able to send actions to be invoked on the thread. Also, I'd like to be able to use a TaskScheduler that can be used for async/await stuff.

Does this exist somewhere?

Paul Knopf
  • 9,568
  • 23
  • 77
  • 142
  • 2
    I don't see any evidence of research here. Can you provide some links and explain how they didn't help you? – rory.ap Jan 19 '17 at 17:45
  • AFAIK Task.Run should still be there and function just fine, have you tried this already? Dispatcher is largely important for things like GUI applications. – Clint Jan 19 '17 at 17:47
  • ```WindowsBase``` (which is where ```Dispatcher```) is, doesn't run on .NET Core, only normal CLR. – Paul Knopf Jan 19 '17 at 17:47
  • Doesn't sound like a .NET Framework vs .NET Core issue, rather a GUI vs console app vs web service issue. Web services don't have long-lived threads, they are request-driven. Whatever project type you are building on .NET Core, will not have access to `Dispatcher` even if you built it with full .NET Framework. – Ben Voigt Jan 19 '17 at 17:47
  • 1
    For reasons that would take a while to explain, I have native objects that must be managed from a single thread. I also have event handlers from another source that need to be raised on the ```Dispatcher``` or ```Thread``` that created the native objects. The ```TaskScheduler.Default``` uses the thread pool. This could be done if I could reference ```WindowsBase```, but I can't. This is a long-running console service. – Paul Knopf Jan 19 '17 at 17:51
  • I'll take all these comments as a "no, it doesn't exist." – Paul Knopf Jan 19 '17 at 17:52
  • `WindowsBase` and `Dispatcher` don't exist in a console app, they're part of WPF GUI message handling. Has nothing to do with .NET Core. – Ben Voigt Jan 19 '17 at 17:53
  • You can absolutely reference ```WindowsBase``` and use it from a command line. I have done it before. It works in unit tests as well. – Paul Knopf Jan 19 '17 at 17:54
  • I found another question where someone manually implemented what I am looking for. I will try to make something work with it. http://stackoverflow.com/questions/30719366/run-work-on-specific-thread – Paul Knopf Jan 19 '17 at 17:55
  • It's still part of WPF, you've been using the console from a WPF app (which is allowed). As for "something like", `System.Threading.SynchronizationContext` should exist, and you should be able to get a context from your thread owning the native objects, and use that for event-passing. – Ben Voigt Jan 19 '17 at 17:55
  • Can you provide me some detail? For example, if I ```Task.Run``` a thread for my native objects, how do I ensure that it will process messages indefinitely, instead of just ending? ```while(true) { await Task.Yeild(); }```? – Paul Knopf Jan 19 '17 at 18:01

5 Answers5

9

Just as reference: You can do like both answers of codevision and JBSnorro:

Edit .csproj file manually. The project file should look like something similar to this (For Core 3.1 use 3.1 instead of 3.0):

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
    <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <UseWPF>true</UseWPF>
    </PropertyGroup>
</Project>

If the project is unloaded, use Reload Project from the context menu.

Note: UseWPF should be added but also the "Project Sdk" type should be modified.

Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119
7

It's not built-in, but my AsyncContext and AsyncContextThread types are available in a library that would fit your need.

AsyncContext takes over the current thread:

AsyncContext.Run(async () =>
{
  ... // any awaits in here resume on the same thread.
});
// `Run` blocks until all async work is done.

AsyncContextThread is a separate thread with its own AsyncContext:

using (var thread = new AsyncContextThread())
{
  // Queue work to the thread.
  thread.Factory.Run(async () =>
  {
    ... // any awaits in here resume on the same thread.
  });
  await thread.JoinAsync(); // or `thread.Join();`
}

AsyncContext provides a SynchronizationContext as well as a TaskScheduler/TaskFactory.

codevision
  • 5,165
  • 38
  • 50
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • So, If I wan't to run a "UI" thread in a console app, inside of ```AsyncCOntext.Run```, I'd get the ```SynchronizationContext```, and then do ```while(!exit) { await Task.Yeild(); }```? Then, using the ```SynchronizationContext```, I can use that to schedule tasks to be executed on that thread? – Paul Knopf Jan 20 '17 at 15:55
  • 1
    @PaulKnopf: If you want a separate thread that you can queue work do, I'd recommend using `AsyncContextThread` as shown. There's no need to capture `SynchronizationContext` - just use `AsyncContextThread.Factory` to queue work. You also don't need the `while` - the thread waits for more work until `Join`/`JoinAsync`/`Dispose` is called. – Stephen Cleary Jan 20 '17 at 18:29
  • Beautiful! Thanks a lot, much appreciated! – Paul Knopf Jan 20 '17 at 20:35
2

With .NET Core 3.0 you can now use Dispatcher class, but it will work only on Windows, and under netcoreapp3.0 TFM, so you cannot deploy your application on Linux or Mac.

You should add to your CSharp project following parameter

<PropertyGroup>
   ...
   <UseWPF>true</UseWPF>
   ...
</PropertyGroup>

and then you can use System.Windows.Threading.Dispatcher in your application.

codevision
  • 5,165
  • 38
  • 50
0

Check that the SDK reference in the .csproj is pointed to Microsoft.NET.Sdk.WindowsDesktop, see here.

JBSnorro
  • 6,048
  • 3
  • 41
  • 62
0

I don't believe there is one built in to .NET Core that is cross-platform,. However, most libraries that mimic WPF and WinForms on other platforms have their own dispatchers/invokers to support multithreading:

  • Avalonia's Avalonia.Threading.Dispatcher - Mimics System.Windows.Threading.Dispatcher. This will probably be your most cross-platform solution (API | Source Code)

  • GTKSharp's Gtk.Application.Invoke - Mimics WinForm's Control.Invoke (Docs | Source Code)

There is also Monodevelop's DispatchService

DaMaxContent
  • 150
  • 1
  • 13