AspNetCore中间件UserManager依赖注入

2024-01-09

我有一个多层应用程序,是我开始在 ASP.NET Core 1.1 中编写的,我仍在不断学习。我像以前在 Web API 中所做的应用程序一样组织它,我有主机服务(网络核心应用程序)、业务层和数据库之上的数据层。业务层和数据层是 net core 标准库,但是当我想添加实体框架时,我必须修改数据层以使其看起来像 net core 应用程序,所以现在我有 Startup.cs 并在那里进行配置。这使我能够配置实体框架服务并在数据层中创建迁移。但现在我有一个问题,因为我想添加 asp.net 身份。网上的每一篇教程都是关于 SPA,在一个项目中包含所有内容。 我已将身份添加到 Startup.cs 并且数据库生成良好

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = Configuration.GetConnectionString("DefaultConnection");
    services.AddEntityFramework(connectionString);
    services.AddMyIdentity();
    services.Configure<IdentityOptions>(options =>
    {
        // Password settings
        options.Password.RequireDigit = true;
        options.Password.RequiredLength = 8;
        options.Password.RequireNonAlphanumeric = false;
        options.Password.RequireUppercase = true;
        options.Password.RequireLowercase = false;

        // Lockout settings
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
        options.Lockout.MaxFailedAccessAttempts = 10;


        // User settings
        options.User.RequireUniqueEmail = true;
    });
}
public void Configure(IApplicationBuilder app)
{
    app.UseIdentity();
}

但现在我需要从一个不是控制器的类中使用 UserManager,并且我不知道如何处理依赖项注入。 为了更好地解释,我的主机服务中有一个帐户控制器

[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody]RegisterUserDto dto)
{
    var result = await Business.Commands.Accounts.Register(dto);
    return Ok(result);
}

业务层只是调用数据层

public async static Task<ResponseStatusDto> Register(RegisterUserDto dto)
{
    // some code here        
    var identityLogon = await Data.Commands.ApplicationUsers.Register(dto);
    // some code here as well

    return new ResponseStatusDto();
}

现在的问题是,如何在Data Register方法中获取UserManager呢?这是一个简单的类,它不从控制器继承,依赖注入不适用于构造函数,如此处的示例所示核心身份 https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity

public class AccountController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly IEmailSender _emailSender;
    private readonly ISmsSender _smsSender;
    private static bool _databaseChecked;
    private readonly ILogger _logger;

    public AccountController(
        UserManager<ApplicationUser> userManager,
        SignInManager<ApplicationUser> signInManager,
        IEmailSender emailSender,
        ISmsSender smsSender,
        ILoggerFactory loggerFactory)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _emailSender = emailSender;
        _smsSender = smsSender;
        _logger = loggerFactory.CreateLogger<AccountController>();
    }

    //
    // GET: /Account/Login

那么,如何将启动中配置的 UserManager 传递给中间件中某处的某个随机类?我见过这个question https://stackoverflow.com/questions/38253607/creating-a-usermanager-outside-of-built-in-dependency-injection-system,但是将 null 值传递给 UseManager 构造函数的答案不起作用,而且我认为这很好。

//根据Set的答案进行编辑

我已经删除了所有静态引用,但我仍然没有完全做到这一点。我已关注this https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services依赖注入说明,但我不确定如何实例化和调用 Add 方法。

我已经创建了一个界面

public interface IIdentityTransaction
{
    Task<IdentityResult> Add(ApplicationUser appUser, string password);
}

并实施了它

public class IdentityTransaction : IIdentityTransaction
{
    private readonly ApplicationDbContext _dbContext;

    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<IdentityRole> _roleManager;


    public IdentityTransaction(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
    {
        _roleManager = roleManager;
        _userManager = userManager;
        _dbContext = context;
    }

    public async Task<IdentityResult> Add(ApplicationUser applicationUser, string password)
    {
        return await _userManager.CreateAsync(applicationUser, password);
    }

}

然后我将它注入到 Startup.cs 中的服务集合中

services.AddScoped<IIdentityTransaction, IdentityTransaction>();

但如何从 Identity Transaction 服务调用 Add 方法?

我无法实例化它,也无法在构造函数上使用依赖注入,因为它只是循环我的问题。 @Set提到的

或将 UserManager userManager 作为参数传递给方法 从哪里传过来?

我想我已经很接近了,但我错过了一些东西。 我尝试过使用

    IIdentityTransaction it = services.GetRequiredService<IIdentityTransaction>();

但是 IServiceProvider 的服务为空,我也不知道从哪里获取它。


ASP.NET Core 中的 DI 对于使用“构造函数注入”方法的控制器和非控制器类的工作方式相同。

你的问题是Register方法是static,因此无权访问实例变量/属性。你需要

  • make Register方法非静态
  • or pass UserManager<ApplicationUser> userManager作为方法的参数

一般来说,您应该避免将静态类用于业务逻辑,因为它们无助于正确测试代码并产生代码耦合。通过互联网/SO 搜索,您会发现很多关于为什么静态不好的主题。

使用DI获取实例Data.Commands.ApplicationUsers控制器中的类。如果您的应用程序只需要此类的一个实例 - 请为其使用单例生命周期。


更新。再次,使用构造函数注入:修改您的“数据层”类,以便它可以获得实例IIdentityTransaction作为构造函数参数:

public class YourDataLayerClass : IYourDataLayerClass
{
    private IIdentityTransaction _identityTransaction;
    public YourDataLayerClass(IIdentityTransaction identityTransaction)
    {
       _identityTransaction = identityTransaction;
    }

    public void MethodWhereYouNeedToCallAdd()
    {
        _identityTransaction.Add(...);
    }
}

和想法相同IYourDataLayerClass实例:注册依赖

services.AddScoped<IYourDataLayerClass, YourDataLayerClass>();

然后依赖于它的类(在你的例子中是中间件,如果我理解正确的话)应该通过构造函数接收该实例:

public class YourMiddleware
{
    private IYourDataLayerClass _yourDataLayerClass;
    public YourMiddleware(IYourDataLayerClass yourDataLayerClass)
    {
       _yourDataLayerClass = yourDataLayerClass;
    }
    ...
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AspNetCore中间件UserManager依赖注入 的相关文章

随机推荐