在ASP.NET Core MVC中注入ApplicationUser

8

我有一个需要使用ApplicationUser(来自ASP.NET身份验证)的类。实例应该是当前用户。

public class SomeClass
{
    public SomeClass(ApplicationUser user)
    {

目前,我正在做的是从控制器注入当前用户:

var currentUser = await _userManager.GetUserAsync(User);
var instance = new SomeClass(currentUser);

现在我想使用Microsoft提供的依赖注入。 我无法弄清楚如何将ApplicationUser添加到服务中。 它需要控制器的属性User

那么,如何通过Microsoft提供的DI注入ApplicationUser(当前用户的实例)?


2
一般来说,你应该注入依赖项,而不是数据。最好在调用每个方法时(或通过调用某些“Init(context)”显式地调用)提供所需的上下文(在您的情况下为调用用户),以便类型的使用者更加了解实际需求。DI自动在幕后注入上下文会提高你的DI技能,但未来可能导致不一致性问题。 - haim770
@haim770 谢谢。我想我只是因为不想在每个方法调用中提供它而变得懒惰了。你说的 Init(context) 可能是一个替代方案,我想知道如何强制执行它的调用。 - kazinix
正如@haim770所述,避免将运行时数据注入到组件中。有关更多详细信息,请阅读此处:https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99。 - Steven
1个回答

6
您可以在类的构造函数中注入 UserManager<ApplicationUser>IHttpContextAccessor,然后:
public class SomeClass
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IHttpContextAccessor _context;
    public SomeClass(UserManager<ApplicationUser> userManager,IHttpContextAccessor context)
    {
        _userManager = userManager;
        _context = context;
    }

    public async Task DoSomethingWithUser() {
        var user = await _userManager.GetUserAsync(_context.HttpContext.User);
        // do stuff
    }
}

如果您不想直接依赖于,但仍希望使用DI,您可以创建接口来访问您的用户:
public interface IApplicationUserAccessor {
    Task<ApplicationUser> GetUser();
}

public class ApplicationUserAccessor : IApplicationUserAccessor {
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IHttpContextAccessor _context;
    public ApplicationUserAccessor(UserManager<ApplicationUser> userManager, IHttpContextAccessor context) {
        _userManager = userManager;
        _context = context;
    }

    public Task<ApplicationUser> GetUser() {
        return _userManager.GetUserAsync(_context.HttpContext.User);
    }
}

然后将其注册到 DI 容器并注入到 SomeClass 中:

public class SomeClass
{
    private readonly IApplicationUserAccessor _userAccessor;
    public SomeClass(IApplicationUserAccessor userAccessor)
    {
        _userAcccessor = userAccessor;
    }

    public async Task DoSomethingWithUser() {
        var user = await _userAccessor.GetUser();
        // do stuff
    }
}

其他选项包括(如评论中所述)不注入任何内容,而是要求将ApplicationUser作为参数传递给需要它的方法(好的选择),并且在使用任何具有特殊Initialize(user)方法的方法之前要求初始化(不太好,因为您不能确定在使用其他方法之前是否调用了此方法)。

1
如果SomeClass在另一个程序集中声明,这将强制它依赖于Microsoft.AspNetCore.Http - haim770
@dpp 你可以避免这种情况,甚至可以注入 ApplicationUser 本身 - 但我建议不要这样做。在依赖项解析期间执行可能会引发异常的重操作并不是一个好主意。如果你想通过注入方式实现 - 可以创建一些具备 Task<ApplicationUser> GetUser() 方法的 IApplicationUserAccessor 并将其注入到你的类中。 - Evk
@dpp 我已经更新了答案,并提供了一个使用IApplicationUserAccessor的示例。 - Evk
谢谢您的建议。 - kazinix
太好了! :) IApplicationUserAccessor 是可替代的,因此我不依赖于 HttpContext - kazinix
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接