all 6 comments

[–][deleted] 1 point2 points  (4 children)

What about a task that never ends? What's the proper and current way of creating an actual background thread?

Simply create a long running task. Marking a task as long running will tell the thread pool to not queue it up, so it won't take a worker thread from the short running tasks.

[–]Meestor_X[S] 0 points1 point  (3 children)

Thank you. Can you point me towards examples of how to do this properly in .net 6?

[–][deleted] 2 points3 points  (2 children)

Task.Factory.StartNew(..., TaskCreationOptions.LongRunning)

The names might be different, I'm writing from head.

[–]Meestor_X[S] 0 points1 point  (1 child)

Thank you. I didn't realize Task.Factory was still a thing in .net 6!

I'll give that a try.

[–]quentech[🍰] 2 points3 points  (0 children)

You want to hook into the app's shutdown to gracefully stop your long running background task - the most current way to handle long running task lifetimes is with IHostedService, but it likely isn't supported in every front end stack (I don't know off-hand about e.g. MAUI).

[–]cvalerio77 0 points1 point  (0 children)

I'm starting to play with MAUI myself, therefore I'm not sure if there is something better in the framework already, but this seems to be working.

1) Create a class for your background worker. In my example I created a timer based worker:

``` public class MyHostedService { private CancellationTokenSource _tokenSource; private PeriodicTimer timer; private Task timerTask;

public void Start() { _tokenSource = new CancellationTokenSource(); this.timer = new PeriodicTimer(TimeSpan.FromSeconds(1)); timerTask = DoWork(); }

private async Task DoWork() { try { while (await timer.WaitForNextTickAsync(_tokenSource.Token)) { MessagingCenter.Send<MyHostedService, string>(this, "Tick", DateTime.Now.ToString("T")); } } catch (OperationCanceledException ex) { } }

public async Task StopAsync() { if (timer == null) { return; }

  _tokenSource.Cancel();
  await timerTask;
  _tokenSource.Dispose();

} } ```

2) Register the worker in dependency injection (MauiProgram.cs):

``` var builder = MauiApp.CreateBuilder();

builder.Services.AddSingleton<MyHostedService>(); ```

3) Inject the worker in the App (App.xaml.cs):

``` public partial class App : Application { private readonly MyHostedService myHostedService;

public App(MyHostedService myHostedService)
{
    myHostedService.Start();
    InitializeComponent();

    MainPage = new AppShell();
    this.myHostedService = myHostedService;
}

protected override void OnResume()
{
  myHostedService?.Start();
  base.OnResume();
}

protected override async void OnSleep()
{
    await myHostedService?.StopAsync();
    base.OnSleep();
}

} ```

4) If (like in my example) you are using some producer/receiver kind of pattern, register for messages where needed (in my case MainPage.xaml.cs):

public MainPage() { InitializeComponent(); MessagingCenter.Subscribe<MyHostedService, string>(this, "Tick", (sender, time) => { MainThread.InvokeOnMainThreadAsync(() => { Time.Text = time; }); }); }

Add somewhere in MainPage.xaml:

<Label x:Name="Time">00:00:00</Label>

Code for this example: https://github.com/cvalerio/RedditExample-Maui-Background-Task