【发布时间】:2020-01-07 17:51:37
【问题描述】:
我需要在 ASP.NET Core 的作用域级别初始化一个注入类 - 初始化涉及异步方法调用。您不会在构造函数中执行此操作,也不会在属性访问器中执行此操作。
在 asp.net 核心应用程序中的一个常见 DI 用途是获取当前用户。我通过创建IUserContext 抽象并在作用域级别注入它来实现这一点:
public sealed class AspNetUserContext : IUserContext
{
private readonly UserManager<User> userManager;
private readonly IHttpContextAccessor accessor;
private User currentUser;
public AspNetUserContext(IHttpContextAccessor a, UserManager<User> userManager) {
accessor = a;
if (userManager == null)
throw new ArgumentNullException("userManager");
this.userManager = userManager;
}
public string Name => accessor.HttpContext.User?.Identity?.Name;
public int Id => accessor.CurrentUserId();
public User CurrentUser {
get {
if (currentUser == null) {
currentUser = this.UserManager.FindByIdAsync(Id.ToString()).ConfigureAwait(false).GetAwaiter().GetResult();
}
return currentUser;
}
}
}
我正在努力找出如何正确初始化 CurrentUser 属性。
由于不再有任何方法可以同步地从UserManager 类中获取用户,因此在初始化CurrentUser 时从属性getter 中运行异步方法,或者从构造函数中运行异步方法(没有使用 ASP.NET Core 的 UserManager 类上的任何同步方法)。
我觉得这样做的正确方法是在每个请求中以某种方式在注入的实例上运行一个初始化方法,因为它是作用域的(可能使用操作过滤器/中间件/控制器基类(或者可能在依赖注入中) AddScoped 方法本身就是工厂方法?)
这似乎是一个很常见的问题,我想知道其他人是如何解决这个问题的。
【问题讨论】:
-
当前用户是
Context上的一个属性 -> 如果您使用的是.Net core auth/approach,这是我推荐的。如果您使用 cookie 或令牌身份验证,则会自动设置 -
是的,您可以看到我使用 HttpContext 来获取用户的名称。但是,上下文中不存在完整的用户对象(您只能以这种方式检索声明或用户名)。您只能通过调用 UserManger.FindByIdAsync 或直接使用 EFCore 来获取完整的用户对象。
-
如果需要加载用户,则加载用户。它不是一个可注入的依赖项......我会提供用户主体对象足够灵活,能够包含您应该需要的任何东西 - 如果您需要超越这个,那么也许有更高层次的设计问题
-
我想通过依赖注入加载用户,以便进行单元测试。因为 UserManager 不再有同步方法来加载它,所以它提出了一个问题。您是将用户加载到注入服务的构造函数中,还是作为属性加载?或者你会从动作过滤器或中间件初始化它吗?那是我的问题。
-
你会模拟用户管理器和/或将你的程序分成更小的部分。此外,任何异步方法都可以同步运行。
标签: c# asp.net-core dependency-injection