aspnet / DependencyInjection

[Archived] Contains common DI abstractions that ASP.NET Core and Entity Framework Core use. Project moved to https://github.com/aspnet/Extensions

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager` from root provider.

chikien276 opened this issue · comments

I'm creating my own Facebook Login Provider for my webapi project, the code like
in ConfigureServices method

services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

then later in that method

services.AddSingleton<IImmutableDictionary<string, ILoginProvider>,
                        ImmutableDictionary<string, ILoginProvider>>(ctx =>
                        {
                            FacebookAppSetting setting = new FacebookAppSetting
                            {
                                AppId = Configuration["FacebookAppSetting:AppId"],
                                AppSecret = Configuration["FacebookAppSetting:AppSecret"]
                            };
                            var fbProvider = new FacebookLoginProvider(setting, ctx.GetService<UserManager<ApplicationUser>>());
                            var builder = ImmutableDictionary.CreateBuilder<string, ILoginProvider>();
                            builder.Add(fbProvider.ProviderName, fbProvider);
                            return builder.ToImmutable();
                        });

My current DotNetCore version is 2.0.0-preview3-006908, my aspnet packages are

<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview2-final" />

Before the second block was added, everything work fine, after that, I got the error like this

InvalidOperationException: Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager`1[MyPackage.ApplicationUser]' from root provider.

on command var fbProvider = new FacebookLoginProvider(setting, ctx.GetService<UserManager<ApplicationUser>>());

Any clue why ?
P/S: every thing work fine for me at version 1.1.2

I suspect UserManager<ApplicationUser> is a scoped service and we added a validation preventing resolving scoped services from the root scope (it turns them into singletons). Solution is to change IImmutableDictionary<string, ILoginProvider> registration to be scoped too.

@chikien276

P/S: every thing work fine for me at version 1.1.2

This could be a hidden bug in your 1.x application. The DbContext won't be disposed until the end of your application which means the backing DbConnection is kept alive and out of the pool. That may not matter if there's only a single one but it's something to be aware of.

Thanks for pointing it out. I've changed to Scoped and it works fine for now. Also, I didn't think about DbContext life-cycle neither. The reason why I chose IImmutableDictionary<string, ILoginProvider> to be Singleton is FacebookLoginProvider had quite expensive constructor. May be I have to find another way.

BTW, Is there any way can I inject a collection of implementations a interface, say ILoginProvider, into other users (controllers, services) ?

You can inject IEnumerable<ILoginProvider> to get all registered instances of a service type.