Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

services.AddSingleton, service's constructor is never called

tl;dr

services.AddSingleton<ISomeService, SomeService>();
// SomeService not instantiated nor initialized?

In a variation on the classic SignalR Chat app, I'm monitoring changes to a SQL Server table and reporting them in real-time through SignalR. Watch this video for 10 seconds to get the idea. My code is adapted from this project. The chat part works fine.

Changes to the SQL Server table are supposed to be monitored by class SqlDependencyService. However, its constructor is never called, and that's where it should get a reference to the SignalR hub.

Here's my Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddSignalR();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    // No instantiation ?!?
    services.AddSingleton<IDatabaseChangeNotificationService, SqlDependencyService>();

    // My lame attempt at forcing instantiation:
    SqlDependencyService sqlDS = serviceProvider.GetService<SqlDependencyService>();
    //sqlDS.Config(); // Fails, sqlDS is null.
}

And here's part of my SqlDependencyService class:

public class SqlDependencyService : IDatabaseChangeNotificationService
    {
        private readonly IConfiguration configuration;
        private readonly IHubContext<ChatHub> chatHub;

        // Never gets called!        
        public SqlDependencyService(IConfiguration configuration, IHubContext<ChatHub> chatHub)
        {
            this.configuration = configuration;
            this.chatHub = chatHub;
        }

        // Never gets called!    
        public void Config()
        {
            SubscribeToPersonTableChanges();
        }

        private void SubscribeToPersonTableChanges()
        {
            // ...
        }

        // ...
    }

Here's the service's interface:

public interface IDatabaseChangeNotificationService
{
    void Config();
}

As stated, the constructor is never called. Additionally, I don't see how the Config method could possibly be invoked - some ASP.NET Core convention magic?

I don't have this issue with the HomeController, whose constructor is called and passed an IHubContext<ChatHub>:

public class HomeController : Controller
{
    private readonly IHubContext<ChatHub> chatHub;

    public HomeController(IHubContext<ChatHub> chatHub)
    {
        this.chatHub = chatHub;
    }

    // ...
}
like image 653
Excelosaurus Avatar asked Dec 14 '22 11:12

Excelosaurus


1 Answers

Just adding a service won't cause it to be instantiated, you actually need to inject it into something for the container to call it's constructor. It looks like you want the service to be available at startup, so I would recommend using the Configure method in startup:

public void Configure(IApplicationBuilder app, IDatabaseChangeNotificationService dbService)
{
    dbService.Config();

    //snip
}
like image 173
DavidG Avatar answered Dec 21 '22 22:12

DavidG