Kyle L.
Kyle L.

Reputation: 634

Running a Singleton instance method on app start up using dependency injection dotnet core

I have a generated webapi .NET Core application with a Queue class that continuously loops through a List<Item> object where an Item is a wrapper around a data model and includes some metadata to do some task asynchronously. This Queue class needs to be accessible in a controller and I have it registered with the DI framework (I think) properly. My issue is that I need for the BeginProcessing method to begin running when the application starts and for the instance passed to the controller to be the same as the one running the method and I am unsure the best route to go. Any help is appreciated. Anything not included in this context (i.e. Program, etc. is all pretty much default still.

See Below.

Queue.cs:

public class Queue : IQueue
{
    public List<Item> Items { get; set; }

    public void BeginProcessing()
    {
        while(true)
        {
            if (!(Items.Count < 1))
            {
                Item Item = Items[0];
                if (!Item.Push())
                {
                    Console.WriteLine("Generic Error Message, not final implementation.");
                }
                Items.Remove(Item);
            }
        }
    }
}

Item.cs

public class Item
{
    public SomeDataModel Data { get; set; } 
    public string Topic { get; set; }
    public string Timestamp { get; set; }

    public Item(SomeDataModel newData, string newTopic, string newTimestamp)
    {
        Data = newData;
        Topic = newTopic;
        Timestamp = newTimestamp;
    }

    public bool Push()
    {
        Producer p = new Producer("identifier");
        return p.Ingest(Data);
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddSingleton<IQueue, Queue>();
    }

Upvotes: 0

Views: 3161

Answers (2)

Kyle L.
Kyle L.

Reputation: 634

I ended up finding a solution for my use case without relying on absurd abstraction or some other obscure part of the .NET framework. Whether it is best practice or not, I do not know. But it works and does what I need and at the end of the day, that is what everyone really wants.

My solution:

Register your Singleton in the DI framework, inject the dependency into the Configure method, then kick off the processing method into another thread.

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton<IQueue, Queue>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IQueue queue)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    Task.Run(() => queue.BeginProcessing());

    app.UseHttpsRedirection();
    app.UseMvc();
}

Upvotes: 1

Zakk Diaz
Zakk Diaz

Reputation: 1093

You should create some background worker to handle the queue thread.

public void BeginProcessing()
{
    while(true)
    {

This will catch the calling thread into an infinite loop. Try using a task or backgroundworker. You could even put it inside the queue its self to hide it from the main app.

To start BeginProcessing, from main, get your built container and query for your IQueue. call your IQueue.BeginProcessing() and continue your startup as normal. If everything works as expected, whenever IQueue get's injected into a controller, it will have been the same one you started BeginProcessing on & you should have access to it in a controller context

Upvotes: 1

Related Questions