2

Is it somehow possible to resolve a scoped service in a singleton service's method being called by a scoped one?

E.g. i have a singleton service "GlobalService" and a scoped one "UserService".

If the UserService executes a method "Job" in "GlobalService", is it somehow possible to get scoped services in this method by using Assembly.GetCallingAssembly()? Otherwise I need to pass all the required parameters.

Thank you ✌

tris
  • 863
  • 4
  • 9
  • 22

2 Answers2

1

@DeepkaMishra's answer won't work in all scenarios.

I used it myself in blazor webassembly loggingprovider and httpcontext came as null. For more details, read this, just adding quoted text here.

Think of HttpContext as a telephone call. If you pick the phone up when no-one has called then there is no context i.e. it is null. When someone does call then you have a valid context. This is the same principal for a web call. The Configure method in Startup is not a web call and, as such, does not have a HttpContext.

Working solution, I found is provided in this.

 public class PersistedConfigurationService : IPersistedConfigurationService
    {
        private readonly IServiceProvider _serviceProvider;
    
        public PersistedConfigurationService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public async Task Foo()
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                //here you can get the scoped service
                 var context = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
                 // do something with context
            }
        }
    }
Bala teja
  • 23
  • 1
  • 10
  • This way you always create a new scope consuming new scopes instances! The calling service won't be the same like the one, you'd resolve here. The best way would be to use HttpContext's ServiceProvider is available, otherwise create a new scope. – tris Sep 26 '22 at 10:49
  • @tris if you are referring to `httpContextAccessor.HttpContext.RequestServices.GetRequiredService`, this won't work as mentioned at the start of this answer. I am still facing issues with my proposed approach as well i.e. not able to get httpclient token for clients resolved this way. If you know a different approach, do provide. – Bala teja Sep 26 '22 at 11:06
  • The question is: why is you HttpContext null? I guess you are running asynchronous work outside the context? Just pass the HttpContext's ServiceProvider to your work and use it there. This will work. – tris Sep 27 '22 at 07:09
0

Singleton would have one single instance which can be used by your scoped service. Your scoped service method can use singleton service instance.

If you call a singleton service's method, you can get the scoped service object in it. You can use IHttpcontextAccessor to resolve the scoped service instance inside that method.

internal class Singleton
{
    private readonly IHttpContextAccessor httpContextAccessor;

    public Singleton(IHttpContextAccessor httpContextAccessor)
    {
        this.httpContextAccessor = httpContextAccessor;
    }
    public int Job()
    {
        return httpContextAccessor.HttpContext.RequestServices.GetRequiredService<Scoped>().MyProperty;
    }
}

You would need to register these service in Startup's ConfigureServices method:

services.AddHttpContextAccessor();
services.AddScoped<Scoped>();
services.AddSingleton<Singleton>();
Deepak Mishra
  • 2,984
  • 1
  • 26
  • 32
  • So I need at least the IHttpContextAccessor as a parameter? That is my current solution - I'd like to remove it. Can you please type me some kind of _pseudo code_? – tris Apr 22 '20 at 13:24
  • You would need IHttpContextAccessor to access scoped service instance inside singleton service methods, there is no other way which I know. – Deepak Mishra Apr 22 '20 at 13:34
  • Ok, thank you. So since IHttpContextAccessor is scoped per definition I need to pass it in the method _Job_? E.g. void Job(IHttpContextAccessor context){} – tris Apr 22 '20 at 13:58
  • Thank you very much! :) – tris Apr 22 '20 at 14:20
  • @tris, I have registered the classes directly, you might want to register with their interfaces. – Deepak Mishra Apr 22 '20 at 14:21
  • 1
    Thank you very much! :) I see! Didn't knew the IHttpContextAccessor was available in a Singleton! Thank you very much! Brilliant! :) – tris Apr 22 '20 at 14:25