ASP.NET核心 - 依赖注入 - IdentityServer4 DbContext

时间:2017-05-23 02:21:49

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

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

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

我找到ConfigurationDbContext的唯一途径是通过在public static IServiceProvider中创建Startup.cs

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?< / p>

任何其他建议或最佳做法?

1 个答案:

答案 0 :(得分:3)

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

根据您RoleService的生命周期(根据提供的代码无法判断),如果服务已经ConfigurationDbContext,您可以将RoleService直接传递给Scoped 1}}。或者您可以通过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的示例。