0

I have an ASP.NET core application that implements a singleton service.

I would like errors to be sent to Bugsnag so I've added IClient bugsnag to my constructor but am getting the following error during startup:

Cannot consume scoped service 'Bugsnag.IClient' from singleton

I cannot find anything in the Bugsnag docs that mentions IClient being scoped or how to construct a singleton instance to use in my application.

As mentioned in the comments, a possible solution would be to use IServiceScopeFactory to create a scope to use in the singleton. This is not ideal because the whole reason for using Bugsnag is to have something that catches all unhandled errors in the application and reports them to a central point for monitoring.

UPDATE: since posting the question I came across a GitHub issue addressing this problem.

jhhwilliams
  • 2,297
  • 1
  • 22
  • 26
  • Does this answer your question? [Create scope factory in asp.net core](https://stackoverflow.com/questions/55381340/create-scope-factory-in-asp-net-core) – JHBonarius Mar 31 '21 at 13:18
  • So yes, it's possible. You just have to create a local scope when you want to use it. **don't keep the scoped objects!!!** You want to dispose them as soon as your finished with them. Scoped and transient services are intended to have a short lifetime. – JHBonarius Mar 31 '21 at 13:20
  • This is what I've done as a temporary solution. It is impractical to manually add Bugsnag to every service in the application so I'll try the GitHub issue's temporary solution next. – jhhwilliams Mar 31 '21 at 14:03
  • You could make a new singleton service that has the only task of generating a scoped instance of `Bugsnag` every time it's needed/accessed. And then inject that service in all your singleton services. _((I think) I know your pain. I've recently joined a project where almost everything is a singleton. Bad design choices from the start of the project 5 years ago. And now it's 500,000 lines of spaghetti code...)_ – JHBonarius Mar 31 '21 at 14:10

1 Answers1

0

In short, you couldn't register the service as singleton , since the IClient has been registered as scoped but it called in the singleton service.

When we have a scoped instance, each time we load the page, a new instance of our ChildService is created and inserted in the parent service.

Whereas when we do a singleton, it keeps the exact same instance (Including the same child services). When we make the parent service a singleton, that means that the child service is unable to be created per page load.

ASP.NET Core is essentially stopping us from falling in this trap of thinking that a child service would be created per page request, when in reality if the parent is a singleton it’s unable to be done. This is why the exception is thrown.

If you want to use iclient in the singleton service, it's impossible. The right way is make that singleton service to scoped.


Update:

As @JHBonarius says, we could inject the IServiceScopeFactory to the singleton sercive and manage the scope service.

More details, you could refer to below codes:

public class Singleton : ISingleton 
{

    private readonly IServiceScopeFactory scopeFactory;

    public Singleton(IServiceScopeFactory scopeFactory)
    {
        this.scopeFactory = scopeFactory;
    }

    public void MyMethod() 
    {
        using(var scope = scopeFactory.CreateScope()) 
        {
            var db = scope.ServiceProvider.GetRequiredService<yourservice>();

            // when we exit the using block,
            // the IServiceScope will dispose itself 
            // and dispose all of the services that it resolved.
        }
    }
}
Brando Zhang
  • 22,586
  • 6
  • 37
  • 65
  • Does this mean that every single service in my application would have to be scoped for Bugsnag to work? How would this apply to HttpClient (for instance)? – jhhwilliams Mar 31 '21 at 07:41
  • Yes, if you want to call scope service you should make sure the parent service is the scope service. – Brando Zhang Mar 31 '21 at 08:08
  • I don't agree. I for instance have a background service that checks the DB every now-and-then to see if things were modified in a certain way and kicks off managed tasks. That background service is a continuously running singleton. The DBcontext scoped. So I create a local scope (with the `IServiceScopeFactory`) every time I need it. Just an example, you can think of more. – JHBonarius Mar 31 '21 at 14:16