Search code examples
dependency-injectioncontrollerblazor-webassembly

POC sharing value among controllers not working


I have a need load an object one time into memory and to have multiple controllers access the same data -- the data will only change with code changes, i.e. will only be set by the constructor and will not change through the lifetime of the application and the data will be identical for each user.

My application is a Blazor WebAssembly application and has the Server, Client, and Shared projects with Controllers in the Server project.

From my understanding, the best way to accomplish this is to create a Singleton Service. As a POC, I have created a simple service that provides a Counter as a way to demonstrate that my data is preserved with each call to the service.

When I execute, each time I execute from the client the service returns a "1st call" message via the Controller rather than what I expected - the "call number" to increment with each call.   First question: Does a Singleton Service sound like the correct approach to solve this?

Second question: Why is the counter value reset with each call to the controller/Service?

My code is very simple, but here goes:

The Interface:

public interface IServicePOC
{
    string CallService();
}

The Service:

    public class ServicePOC : IServicePOC
{
    readonly IServicePOC servicePOC;

    public int CallCount { get; set; } = 0;

    //public ServicePOC(IServicePOC servicePOC)
    public ServicePOC()
    {
        this.servicePOC = servicePOC;
    }
    public string CallService()
    { 
        // Implement your data retrieval logic here
        CallCount++;
        return "Hello from your service! (Call #" + CallCount.ToString() + ")";
    }
}

Registering the Service in Startup:

services.AddSingleton<IServicePOC, ServicePOC>();

The Controller:

    private readonly IServicePOC servicePOC;
    public ServicePOCController(ApplicationDbContext context, ILogger<ServicePOCController> logger,
                UserManager<ApplicationUser> userManager, IServicePOC servicePOC)
    {
        this.logger = logger;
        this.userManager = userManager;

        this._context = context;
        this.servicePOC = new ServicePOC();
    }

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var user = await userManager.GetUserAsync(User);

        if (user != null)
        {
            logger.LogInformation($"User.Identity.Name: {user.UserName}");
        }

        string rtrn = "Not Yet Called";

        rtrn = servicePOC.CallService();
        string jsonString = JsonSerializer.Serialize(rtrn);

        return Ok(jsonString);
    }
}

Solution

  • First question: Does a Singleton Service sound like the correct approach to solve this?

    If you want to maintain a state in the same request instance, yes! singleton would help there. However if you want updated value in an other request instance, then use static.

    Second question: Why is the counter value reset with each call to the controller/Service?

    You don't need to inject interface into service class constructor. Modify that as below:

    public class ServicePOC : IServicePOC
    {              
        public int CallCount { get; set; } = 0;
        
        public string CallService()
        {
            // Implement your data retrieval logic here
            CallCount++;
            return "Hello from your service! (Call #" + CallCount.ToString() + ")";
        }
    } 
    

    Controller

     private readonly IServicePOC _servicePOC;
    
        public ServicePOCController(IServicePOC servicePOC, ...)
        {
            _servicePOC = servicePOC,
            ...
        }
    
        [HttpGet]
        public async Task<IActionResult> Get()
        {
            ...
            .
    
            rtrn = _servicePOC.CallService();
            string jsonString = JsonSerializer.Serialize(rtrn);
    
            return Ok(jsonString);
        }
    }
    

    Result:

    enter image description here