Search code examples
c#multithreadingasp.net-coreblazordotnet-aspire

Is it possible to start multiple instances of a Thread or BackgroundWorker from a Blazor program, and start them inside .NET Aspire?


I want to run a worker (as Thread or BackgroundWorker) multiple times inside a .NET Aspire AppHost project, which is started from a Blazor Website.

I have the Projects (AppHost [Aspire], Web [Blazor], Worker [dll]).

Since I'm new to Aspire I don't know if this is even possible or how to do it.

I tried using the aspire builder.Services.AddHostedServices(); which did not work due to the namespace not being found because of the using Projects; which is needed for the blazor project as far as I understand.

I also tried registering it as a project which kinda worked.. well at least it started event if only once and only at the boot without any control over it via the web project.


Solution

  • I don't think it is possible to run dynamically times instances in aspire. For one instance, you could expose endpoint to start/stop the worker which can be access using blazor httpclient. Such as following:
    Aspire

    builder.AddProject<Projects.WorkerService1>("workerservice1");
    

    Worker project

    var builder = WebApplication.CreateBuilder(args);
    builder.AddServiceDefaults();
    builder.Services.AddHostedService<Worker>();
    var app = builder.Build();
    
    app.MapGet("/", () => "Worker API is running...");
    app.MapGet("/api/worker/start", async(ILogger<Worker> logger,HttpContext context) =>
    {
        var worker = context.RequestServices.GetHostedService<Worker>();
        worker.StartService(); 
        logger.LogInformation("Start command received.");
        return   ("Worker started");
    });
    
    app.MapGet("/api/worker/stop", (ILogger<Worker> logger, HttpContext context) =>
    {
        var worker = context.RequestServices.GetHostedService<Worker>();
        worker.StopService();
        logger.LogInformation("Stop command received.");
        return ("Worker stopped");
    });
    app.Run();
    

    Worker.cs

    public class Worker : BackgroundService
    {
        private CancellationTokenSource _cts;
    
        public Worker()
        {
            _cts = new CancellationTokenSource();
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!_cts.Token.IsCancellationRequested && !stoppingToken.IsCancellationRequested)
            {
                Console.WriteLine("myservice running");
                await Task.Delay(1000, stoppingToken);
            }
        }
        public void StopService()
        {
            _cts.Cancel();
        }
        public void StartService()
        {
            _cts = new CancellationTokenSource(); 
            ExecuteAsync(_cts.Token); 
        }
    }
    

    Blazor

    @inject HttpClient Http
    <h3>Worker Control</h3>
    <button @onclick="StartWorker">Start Worker</button>
    <button @onclick="StopWorker">Stop Worker</button>
    @code {
        private async Task StartWorker()
        {
            await Http.PostAsync("http://worker-1/api/worker/start", null);
        }
        private async Task StopWorker()
        {
            await Http.PostAsync("http://worker-1/api/worker/stop", null);
        }
    }