【问题标题】:Add Identity after ConfigureServices在 ConfigureServices 之后添加身份
【发布时间】:2019-01-06 17:03:31
【问题描述】:

我正在尝试在 ConfigureServices 方法之后添加身份。这是因为我在ConfigureServices 方法之外注册了dbContext。所以,现在我必须在配置dbContext 之后配置身份(同样,我已经在ConfigureServices 之外完成了)。我为dbContext 所做的就是创建了一个工厂并将其添加到ConfigureServices

services.AddScoped<IDbContextFactory, DbContextFactory>();

然后我使用 DI 将它注入到我的控制器的构造函数中:

    private IDbContextFactory contextFactory;
    private AppDbContext context;

    public DbTestController(IDbContextFactory _contextFactory)
    {
        contextFactory = _contextFactory;
        context = contextFactory.Create(); //Create() returns an `AppDbContext`
    }

我能够对数据库执行 CRUD 操作,但是 Identity 不起作用,它会抛出异常:

No service for type Microsoft.AspNetCore.Identity.XXX has been registered

那是因为我在 ConfigureServices 中注册身份而没有先设置 dbContext (因为它是在 ConfigureServices 方法之后设置的。

services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<AppDbContext>()
        .AddDefaultTokenProviders();

有没有办法像我设置 dbContext 一样设置身份?

编辑:DbContextFactory 包含一个返回AppDbContextCreate 方法。它从一些配置文件中读取用户对数据库提供者的选择,相应地注册提供者,然后返回AppDbContext。以下是Create 方法的代码:

public AppDbContext Create()
    {
        //Get this value from some configuration
        string providerType = _configuration.GetValue<string>("DatabaseProvider");

        //and the connection string for the database
        string connectionString = _configuration.GetConnectionString(providerType);

        var dbContextBuilder = new DbContextOptionsBuilder();

        //Add some if else blocks here to check which provider to use
        //and then call dbContextBuilder.UseABC(connectionString)
        if (providerType == "MSSQL")
            dbContextBuilder.UseSqlServer(connectionString);
        else if (providerType == "SQLite")
            dbContextBuilder.UseSqlite(connectionString);


        //Create the context
        context = new AppDbContext(dbContextBuilder);

        return context;
    }

此方法从appsettings.json 读取providerTypeconnectionString。该部分如下所示:

"DatabaseProvider": "MSSQL", //could be MySQL, SQLite etc etc
"ConnectionStrings": {
"MSSQL": "Server=(localdb)\\MSSQLLocalDB;Database=XXX_db;Trusted_Connection=True;MultipleActiveResultSets=true",
"SQLite": "Data Source=XXX_db.db"
 }

【问题讨论】:

  • 我不明白您所说的“在 ConfigureServices 方法之外注册 dbContext”是什么意思,也不明白您为什么要这样做。在我看来,当您在 ConfigureServices 中注册两者时没有问题。
  • 抱歉不清楚。我已经按照this 的帖子在 ConfigureServices 方法之外创建了我的 dbContext。由于未在 ConfigureServices 中配置 dbContext,因此还必须在 ConfigureServices 之外配置 Identity(连同 dbContext)。是的,我可以在 ConfigureServices 中配置它们,但是对于这个用例,我必须在 ConfigureServices 以外的地方配置它们。你建议我做什么?
  • 您能否显示引发异常的代码:Microsoft.AspNetCore.Identity.XXX 类型的服务未注册
  • 它在我的AccountController Login 操作中:var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, false, false);。我已经使用 DI 在构造函数中注入了_userManager & _signInManager

标签: c# asp.net-core asp.net-identity asp.net-core-2.0


【解决方案1】:

像往常一样在ConfigureServices 中注册上下文和身份,在启动时在组合根中应用所需的逻辑。

//Get this value from some configuration
string providerType = Configuration.GetValue<string>("DatabaseProvider");

//and the connection string for the database
string connectionString = Configuration.GetConnectionString(providerType);

services.AddDbContext<AppDbContext>(options => {
    if (providerType == "MSSQL")
        options.UseSqlServer(connectionString);
    else if (providerType == "SQLite")
        options.UseSqlite(connectionString);
});

services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<AppDbContext>()
        .AddDefaultTokenProviders();

你需要做的是重新设计工厂

public class DbContextFactory : IDbContextFactory {

    private readonly Func<AppDbContext> factory;

    public DbContextFactory(Func<AppDbContext> factory) {
        this.factory = factory;
    }

    public AppDbContext Create() {
        return factory();
    }
}

并相应地向工厂代表注册

services.AddScoped<IDbContextFactory, DbContextFactory>(sp => 
    new DbContextFactory(() => sp.GetRequiredService<AppDbContext>()));

【讨论】:

  • 我无法在ConfigureServices 中注册上下文,因为我希望用户选择黑白不同的数据库提供程序,并且该选择发生在我工厂的Create 方法中。它从某个配置文件中读取用户的选择,然后相应地注册提供程序(MSSQL、SQLite 等)并返回新创建的AppDbContext
  • 对不起,我在问题中包含了Create 方法的代码。如您所见,providerTypeappsettings.json 文件中获取其值。
  • 谢谢,我已经尝试过这种方法并且效果很好,但是我正在尝试以另一种方式实现它;就像我从ConfigureServices 中取出AppDbContext 一样。有没有其他的实现方式?
  • 我的意思是把身份注册部分放在ConfigureServices方法之外,就像我把DbContext注册部分放在ConfigureServices之外一样。
  • 您能解释一下为什么要以其他方式进行操作吗?这个答案是一个很好的例子,说明了如何使用这种模式并且它有效。为什么选择非标准解决方案?它只会让你的代码更难维护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2020-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多