在asp.net核心2.1 MVC应用程序中,我有以下代码来自掘金的Github,还有我自己做的一些附加工作:
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;
}
所以您可以看到它正在使用依赖项注入,但是我在问自己一些问题:
1)userCollection和roleCollection是“本地”变量,然后传递到DI中。但是,如何管理这些对象的生命周期呢?我的意思是说,它们永远不会因为在DI中使用而被丢弃吗?还是他们每次都在创造?
2)之间是否有区别
services.AddTransient<ILicenseStore<LicenseEntity>>(x => new LicenseStore<LicenseEntity>(dbOptions.DbType, dbOptions.ConnectionString));
和
services.AddTransient<ILicenseStore<LicenseEntity>>(new LicenseStore<LicenseEntity>(dbOptions.DbType, dbOptions.ConnectionString));
3)在行中
services.AddTransient((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(userCollection, roleCollection, x.GetService<ILookupNormalizer>())));
有一个'x.GetService()'。这是一种告诉构造函数该构造函数所需参数将来自DI的方法吗?在DependecyInjection中使用依赖注入的某种方式?
4)如果对问题3回答“是”,可以这样做吗?
services.AddSingletion<IMongoClient>(new MongoClient("connectionString"));
services.AddTransient<IXStore>(new XStore(x.GetService<IMongoClient>()))
要实现MongoClient将是单例(这是推荐的方式)
5)之间有什么区别:
services.AddScoped((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(x.GetRequiredService<IIdentityUserCollection<TUser>>(), x.GetRequiredService<IIdentityRoleCollection<TRole>>(), x.GetService<ILookupNormalizer>())));
和
services.AddScoped<IUserStore<TUser>, UserStore<TUser, TRole>>();
非常感谢您的回答:)
编辑:
新方法:
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>>()));
答案 0 :(得分:2)
首先userCollection
和roleCollection
仅实例化一次。由于以下原因,这两个局部变量都不会被垃圾回收。它们是由用lambda(x => userCollection
和x => roleCollection
)创建的委托捕获的,并且这些委托被添加到服务集合中,该集合肯定是GC root。
是的。第一行会编译,而第二行则不会。您只能将构造对象传递给AddSingleton
。 services.AddSingleton(x => new object)
和services.AddSingleton(new object)
之间的唯一区别是立即实例化对象(new object
)或在首次请求指定服务类型(x => new object
)时实例化。 p>
是。
如果您修复第二行
services.AddSingletion<IMongoClient>(new MongoClient("connectionString"));
services.AddTransient<IXStore>(x => new XStore(x.GetService<IMongoClient>()))
那么答案是是。实际上, DI 容器会为您完成此操作,并为每个构造函数参数调用GetService
。因此,以下代码等效于您的代码
services.AddSingletion<IMongoClient>(new MongoClient("connectionString"));
services.AddTransient<IXStore, XStore>()
基本上,两个示例都相同。使用第一个示例时,您将使用DI
容器手动解析所有构造函数参数。当您使用第二个容器时,DI
容器会自动为您解析所有构造函数参数。因此,在这种情况下,最好使用第二种方法,因为它的代码更少。仅当您需要自己使用new
或为它们提供一些其他服务而不是DI
容器来实例化对象时,才考虑使用第一种方法。