【问题标题】:asp.net core 2.1 dependency injectionasp.net core 2.1 依赖注入
【发布时间】:2019-02-28 15:23:39
【问题描述】:

在一个 asp.net core 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>>()));

【问题讨论】:

    标签: asp.net-core dependency-injection


    【解决方案1】:
    1. 首先userCollection 和roleCollection 只被实例化一次。由于以下原因,这两个局部变量都不会被垃圾收集。它们被使用 lambdas(x =&gt; userCollection 和 x =&gt; roleCollection)创建的委托捕获,并且委托被添加到服务集合中,这绝对是一个 GC root。

    2. 是的,有。第一行编译,后一行不编译。您只能将构造对象传递给AddSingleton。 services.AddSingleton(x =&gt; new object) 和 services.AddSingleton(new object) 之间的唯一区别是对象被实例化的时间、现在 (new object) 或在第一次请求指定服务类型时 (x =&gt; new object)。

    3. 是的。

    4. 如果你修复第二行
      services.AddSingletion&lt;IMongoClient&gt;(new MongoClient("connectionString"));services.AddTransient&lt;IXStore&gt;(x =&gt; new XStore(x.GetService&lt;IMongoClient&gt;()))
      那么答案是是的。事实上,DI 容器会为您执行此操作,为每个构造函数参数调用 GetService。所以下面的代码等价于你的
      services.AddSingletion&lt;IMongoClient&gt;(new MongoClient("connectionString")); services.AddTransient&lt;IXStore, XStore&gt;()

    5. 基本上这两个例子是相同的。当您使用第一个示例时,您使用 DI 容器手动解析所有构造函数参数。当您使用第二个时,DI 容器会自动为您解析所有构造函数参数。所以在这种情况下更喜欢第二种方法,因为它的代码更少。仅当您需要使用new 自己实例化对象或为它们提供一些其他服务而不是通过DI 容器时,才考虑使用第一种方法。

    【讨论】:

    • 首先感谢您的回复,这对我有很大帮助:)
    • 首先感谢您的回复,这对我有很大帮助:) 回到第 1 点:如果我错了,请纠正我,但 userCollection 和 roleCollection 是 GC root 的事实不是一个好的想法(或至少没有必要)。那么更好的解决方案是使用 DI 来解决集合问题?你认为更好的解决方案是什么? (由于 5 分钟规则,第二条评论,抱歉)
    • 我有一些时间来重新考虑它的完成方式。我用一种新的方式编辑了我的问题,请问您对此有何看法?谢谢
    • @S.Martignier 看起来还可以,但是我需要更多地了解类的性质等等才能说更准确的东西,所以我将根据我所看到的情况发表我的看法.我相信所有Stores 都拥有Scoped 生命周期会更好,因为对它们的访问通常是事务性的,因此您希望每个请求都拥有相同的Store 实例。您可以通过调用services.AddTransient&lt;IType, Type&gt;() 将其写得更短。而且只能在泛型中使用预定义类型,AddTransient&lt;IUser&lt;T&gt;, User&lt;T&gt;&gt; 是错误的,因为没有T 这样的类型,(IUser, User) 很好
    • 感谢您的回答 :) TUser 和 TRole 看起来确实是通用的,但它们不是,这是因为这些服务调用在一个扩展方法中,看起来像:public static IServiceCollection AddIdentityMongoDbProvider&lt;TUser, TRole&gt;(this IServiceCollection services, Action&lt;IdentityOptions&gt; setupIdentityAction, Action&lt;MongoIdentityOptions&gt; setupDatabaseAction) where TUser : UserEntity where TRole : RoleEntity 我可以问你最后一个吗事情(问题帖子中的问题5)?
    猜你喜欢
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 2019-02-22
    相关资源
    最近更新 更多