How to pass data from a controller to a background service
S

2

6

I'm trying to write a simple web api project with a background service executing a method every second. This method loops over a list and just prints out (for the moment) some statistics. I declared a new list in the constructor of the background service.

I'm currently encountering some issues with adding and removing items from inside the controller.

public UsersController(IUserBackgroundService userService)
{
   private readonly IUserBackgroundService _userService;

   public UserController(IUserBackgroundService userService)
   {
       _userService = userservice;
   }

   [HttpPost]
   public IActionResult PostUser(User user)
   {
      _userService.Add(user) 
   }
}

public UserService: BackgroundService, IUserService
{
    private List<User> Users;

    public UserService()
    {
       Users = new List<Users>();
    }
    protected override ExecuteAsync(CancellationToken token)
    {
        //this will execute the GenerateUserStats every second
    }

    //this method is being executed every second 
    protected Task GenerateUserStatistics()
    {
        Console.WriteLine($"Nr. of users {users.count}");
        foreach(var user in users)
        {
            Console.WriteLine($"{user.fname} {user.sname}");
        }
    }

    //add a user to the collection
    // this is called by the PostUser method of my controller.
    public void AddUser(User user)
    {
        Users.Add(user);
    }

    public void RemoveUser(string id)
    {
        var user = Users.FirstOrDefault(u => u.Id == id);
        Users.Remove(user);
    }
}

I'd expect that every time I call the PostUser() the Users list should increase and my GenerateStatistics() method should print out the correct values, instead all it prints out is Nr of users 0.

I registered the service as a hostedservice and a singleton. I omitted some things from the code for the moment because I don't have the code on this machine.

Southland answered 25/9, 2019 at 20:9 Comment(1)
You need data storageDasyure
B
6

Register your backgroundService as the IHostedService in the ConfigureServices of Startup.cs like below :

 services.AddSingleton<UserService>();
 services.AddSingleton<IHostedService, UserService>(
            serviceProvider => serviceProvider.GetService<UserService>());

Then dependency inject service in controller :

 public class UsersController : ControllerBase
{
    private readonly UserService _userService;

    public UsersController(UserService userService)
    {
        _userService = userService;
    }

    [HttpPost]
    public IActionResult PostUser(User user)
    {
        _userService.AddUser(user);
        return Ok();
    }
}

Reference :https://github.com/simpleinjector/SimpleInjector/issues/596

Boorish answered 26/9, 2019 at 9:39 Comment(0)
S
3

For .NET 6 this fixes the issue too!

This has been a very long on going issue which is centered around how BackgroundService is registered.

So instead of:

    // services.AddHostedService<MYServiceBackground>();

You do as this says:

services.AddSingleton<MYServiceBackground>();
services.AddSingleton<IHostedService, MYServiceBackground>(
                   serviceProvider => serviceProvider.GetService<MYServiceBackground>());

Endpoints can finally be created (you do NOT need [FromServices]:

    app.MapGet("/background/State", (MYServiceBackground worker) =>
    {
        return worker?.state;
    }).WithTags("Background");

    app.MapPost("/background/on", (MYServiceBackground service) =>
    {
        service.state.IsServiceEnabled = true;

        return service.state;
    }).WithTags("Background");
Sheerlegs answered 27/6, 2023 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.