In a asp.net core 2.1 MVC application I have the following code coming a bit from a Github from a nugget and some addition made by me :
public static IServiceCollection AddIdentityMongoDbProvider<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupIdentityAction, Action<MongoIdentityOptions> setupDatabaseAction) where TUser : UserEntity where TRole : RoleEntity
{
services.AddIdentity<TUser, TRole>(setupIdentityAction ?? (x => { }))
.AddRoleStore<RoleStore<TRole>>()
.AddUserStore<UserStore<TUser, TRole>>()
.AddDefaultTokenProviders();
var dbOptions = new MongoIdentityOptions();
setupDatabaseAction(dbOptions);
var userCollection = new IdentityUserCollection<TUser>(dbOptions.DbType, dbOptions.ConnectionString);
var roleCollection = new IdentityRoleCollection<TRole>(dbOptions.DbType, dbOptions.ConnectionString);
// Add collections and stores in services for DI
services.AddTransient<IIdentityUserCollection<TUser>>(x => userCollection);
services.AddTransient<IIdentityRoleCollection<TRole>>(x => roleCollection);
services.AddTransient<ITenantStore<TenantEntity, TUser>>(x => new TenantStore<TenantEntity, TUser>(dbOptions.DbType, dbOptions.ConnectionString, userCollection));
services.AddTransient<ILicenseStore<LicenseEntity>>(x => new LicenseStore<LicenseEntity>(dbOptions.DbType, dbOptions.ConnectionString));
// Identity Services
services.AddTransient((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(userCollection, roleCollection, x.GetService<ILookupNormalizer>())));
services.AddTransient<IRoleStore<TRole>>(x => new RoleStore<TRole>(roleCollection));
return services;
}
So as you can see it's using the dependency injection, but i'm asking myself somes questions :
1) the userCollection and roleCollection are 'local' variable that are then passed into DI. But then how is the lifecycle of those object managed? I mean are they never disposed because they are used in DI? Or are they creating each time?
2) Is there a difference between
services.AddTransient<ILicenseStore<LicenseEntity>>(x => new LicenseStore<LicenseEntity>(dbOptions.DbType, dbOptions.ConnectionString));
And
services.AddTransient<ILicenseStore<LicenseEntity>>(new LicenseStore<LicenseEntity>(dbOptions.DbType, dbOptions.ConnectionString));
3) In the line
services.AddTransient((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(userCollection, roleCollection, x.GetService<ILookupNormalizer>())));
There is the 'x.GetService()'. Is that a way to tell the constructor that the parameter needed in the constructor will be from DI? Sort of using Dependency Injection in DependecyInjection?
4) In case of yes to question 3, is it possible to do something like this?
services.AddSingletion<IMongoClient>(new MongoClient("connectionString"));
services.AddTransient<IXStore>(new XStore(x.GetService<IMongoClient>()))
The point being to achieve that the MongoClient will be a singleton (which is the recommended way)
5) What is the difference beetween :
services.AddScoped((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(x.GetRequiredService<IIdentityUserCollection<TUser>>(), x.GetRequiredService<IIdentityRoleCollection<TRole>>(), x.GetService<ILookupNormalizer>())));
And
services.AddScoped<IUserStore<TUser>, UserStore<TUser, TRole>>();
Thanks a lot for the answers :)
Edit:
New way:
services.AddSingleton<ICustomMongoClient>(x => new CustomMongoClient(dbOptions.ConnectionString));
// Add collections and stores in services for DI
services.AddTransient<IIdentityUserCollection<TUser>>(x => new IdentityUserCollection<TUser>(x.GetRequiredService<ICustomMongoClient>()));
services.AddTransient<IIdentityRoleCollection<TRole>>(x => new IdentityRoleCollection<TRole>(x.GetRequiredService<ICustomMongoClient>()));
services.AddTransient<ITenantStore<TenantEntity, TUser>>(x => new TenantStore<TenantEntity, TUser>(x.GetRequiredService<ICustomMongoClient>(), x.GetRequiredService<IIdentityUserCollection<TUser>>()));
services.AddTransient<ILicenseStore<LicenseEntity>>(x => new LicenseStore<LicenseEntity>(x.GetRequiredService<ICustomMongoClient>()));
// Identity Services
services.AddTransient((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(x.GetRequiredService<IIdentityUserCollection<TUser>>(), x.GetRequiredService<IIdentityRoleCollection<TRole>>(), x.GetService<ILookupNormalizer>())));
services.AddTransient<IRoleStore<TRole>>(x => new RoleStore<TRole>(x.GetRequiredService<IIdentityRoleCollection<TRole>>()));