【问题标题】:ASP.NET Core - Dependency Injection - IdentityServer4 DbContextASP.NET Core - 依赖注入 - IdentityServer4 DbContext
【发布时间】:2017-05-23 14:32:18
【问题描述】:

我一直在努力寻找最好/首选的方法是让我的RoleService 获得ConfigurationDbContext (IdentityServer4)。

我真的很想解耦,以便我的 RoleService 可以测试。

我发现访问ConfigurationDbContext 的唯一方法是在Startup.cs 中创建public static IServiceProvider

public class Startup
{
    private readonly IHostingEnvironment _environment;

    // THIS IS THE PROPERTY I USED
    public static IServiceProvider ServiceProvider { get; private set; }

    public ConfigurationDbContext GetConfigurationDbContext()
    {
        return null;
    }

    public Startup(ILoggerFactory loggerFactory, IHostingEnvironment environment)
    {
        loggerFactory.AddConsole(LogLevel.Debug);
        _environment = environment;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var connectionString = DbSettings.IdentityServerConnectionString;
        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        // configure identity server with in-memory stores, keys, clients and scopes
        var identityServerConfig = services.AddIdentityServer()
            .AddConfigurationStore(builder =>
                builder.UseSqlServer(connectionString, options =>
                    options.MigrationsAssembly(migrationsAssembly)))
            .AddOperationalStore(builder =>
                builder.UseSqlServer(connectionString, options =>
                    options.MigrationsAssembly(migrationsAssembly)))
            .AddSigningCredential(new X509Certificate2(Path.Combine(_environment.ContentRootPath, "certs", "IdentityServer4Auth.pfx"), "test"));

        identityServerConfig.Services.AddTransient<IResourceOwnerPasswordValidator, ActiveDirectoryPasswordValidator>();
        identityServerConfig.Services.AddTransient<IProfileService, CustomProfileService>();
        services.AddDbContext<ConfigurationDbContext>(options => options.UseSqlServer(connectionString));
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ServiceProvider = app.ApplicationServices;
        // other code emitted
    }
}

然后在 RoleService.cs:

中使用此代码
public class RoleService : IRoleService
{
    public async Task<ApiResource[]> GetApiResourcesByIds(int[] ids)
    {
        ApiResource[] result;

        using (var serviceScope = Startup.ServiceProvider.GetService<IServiceScopeFactory>().CreateScope())
        {
            var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
            result =
                context.ApiResources.Where(x => ids.Contains(x.Id))
                .Include(x => x.Scopes)
                .Include(x => x.UserClaims)
                .ToArray();

            return result;
        }
    }
}

这是在RoleService.cs 中获得依赖的最佳方式吗?

有没有办法抽象serviceScope(因为它在using语句中,可能是IDisposable,我真的不知道是否有办法抽象获得context

还有其他建议或最佳做法吗?

【问题讨论】:

    标签: c# asp.net-core .net-core entity-framework-core identityserver4


    【解决方案1】:

    您可以通过创建一个将所需依赖项作为构造函数参数的构造函数来将依赖项传递给RoleService

    根据您的RoleService 的生命周期(根据提供的代码无法判断),如果服务已经是Scoped,您可以将ConfigurationDbContext 直接传递给RoleService。或者您可以通过 IServiceScopeFactory 在您的服务中手动创建一个范围。

    类似:

    private readonly IServiceScopeFactory _scopeFactory;
    
    public RoleService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }
    
    public async Task<ApiResource[]> GetApiResourcesByIds(int[] ids)
    {
        using (var scope = _scopeFactory.CreateScope())
        {
            var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        }
    }
    

    由于您的方法与 DbContext 紧密耦合(这不一定是坏事),您最终可能会创建一个内存中的 ConfigurationDbContext。 您使用的 IdentityServer4.EntityFramework 存储库有一些用于测试 here 的示例。

    【讨论】:

    • 我对依赖注入在这里应该如何工作感到困惑。如果我必须从让我们说一个控制器手动创建我的角色服务的实例,我不必将变量传递给构造函数吗?还是我们假设在某一时刻,一切都会相互影响?
    • 您不应该手动创建实例,这就是 DI 为您所做的。控制反转(您不想知道创建的实例类型)。因此,如果您需要控制器中的实例,请在控制器的构造函数中注入 RoleService
    • 太好了,那部分很清楚。我假设如果我想为 RoleService 编写一些测试,他们将需要手动创建它,是吗?
    • 是的,因为那是您要测试 RoleService 而不是 IRoleService 的时候
    • 在测试 RoleService 时,直接进行,而不是通过控制器。
    猜你喜欢
    • 2021-10-23
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 2019-02-22
    相关资源
    最近更新 更多