Внедрение зависимости asp.net core 2.1 - PullRequest
0 голосов
/ 28 февраля 2019

В приложении 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?Что-то вроде использования Dependency Injection в 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>>()));

1 Ответ

0 голосов
/ 28 февраля 2019
  1. Прежде всего userCollection и roleCollection создаются только один раз.Обе эти локальные переменные не будут собираться мусором по следующей причине.Они захватываются делегатами, созданными с помощью лямбд (x => userCollection и x => roleCollection), и делегаты добавляются в коллекцию служб, которая определенно является корнем GC .

  2. Да, есть.Первая строка компилируется, а вторая нет.Вы можете передать построенный объект только на AddSingleton.Единственная разница между services.AddSingleton(x => new object) и services.AddSingleton(new object) заключается в том, что объект создается, прямо сейчас (new object) или при первом запросе к указанному типу службы (x => new object).

  3. Да.

  4. Если вы исправите вторую строку
    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>()

  5. В основном оба примера одинаковы.При использовании первого примера вы вручную разрешаете все параметры конструктора, используя контейнер DI.При втором использовании контейнер DI автоматически разрешает все параметры конструктора.Поэтому предпочтите второй подход в этом случае, потому что это меньше кода.Рекомендуется использовать первый подход только в том случае, если вам нужно создавать экземпляры объектов самостоятельно, используя new или предоставляя им некоторые другие службы, а не контейнером DI.

...