gpt4 book ai didi

c# - 如何在涉及异步调用的 ASP.NET Core 中初始化作用域注入(inject)类

转载 作者:行者123 更新时间:2023-12-03 14:32:42 25 4
gpt4 key购买 nike

我需要在 ASP.NET Core 的作用域级别初始化一个注入(inject)类 - 初始化涉及异步方法调用。您不会在构造函数中执行此操作,也不会在属性访问器中执行此操作。

asp.net 核心应用程序中的一个常见 DI 用途是获取当前用户。我通过创建 IUserContext 来实现这一点抽象并在作用域级别注入(inject)它:

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属性(property)。

由于不再有任何方法可以从 UserManager 获取用户。同步类,我不习惯在初始化 CurrentUser 时从属性 getter 中运行异步方法,也不是来自构造函数(在 ASP.NET Core 的 UserManager 类上不再有任何同步方法)。

我觉得这样做的正确方法是每次请求以某种方式在注入(inject)的实例上运行一个初始化方法,因为它是作用域的(可能使用操作过滤器/中间件/ Controller 基类(或者可能在依​​赖注入(inject) AddScoped方法本身作为工厂方法?)

这似乎是一个很常见的问题,我想知道其他人是如何解决这个问题的。

最佳答案

在这种情况下,您将需要放弃该属性并使用异步方法。

这也意味着为用户使用异步延迟初始化

/// <summary>
/// Provides support for asynchronous lazy initialization.
/// </summary>
/// <typeparam name="T"></typeparam>
public class LazyAsync<T> : Lazy<Task<T>> {
/// <summary>
/// Initializes a new instance of the LazyAsync`1 class. When lazy initialization
/// occurs, the specified initialization function is used.
/// </summary>
/// <param name="valueFactory">The delegate that is invoked to produce the lazily initialized Task when it is needed.</param>
public LazyAsync(Func<Task<T>> valueFactory) :
base(() => Task.Run(valueFactory)) { }
}

现在可以重构上下文以使用延迟初始化,
public sealed class AspNetUserContext : IUserContext {
private readonly UserManager<User> userManager;
private readonly IHttpContextAccessor accessor;
private readonly LazyAsync<User> currentUser;

public AspNetUserContext(IHttpContextAccessor accessor, UserManager<User> userManager) {
this.accessor = accessor;

if (userManager == null)
throw new ArgumentNullException(nameof(userManager));

this.userManager = userManager;

currentUser = new LazyAsync<User>(() => this.userManager.FindByIdAsync(Id.ToString()));
}

public string Name => accessor.HttpContext.User?.Identity?.Name;
public int Id => accessor.CurrentUserId();

public Task<User> GetCurrentUser() {
return currentUser.Value;
}
}

并在需要的地方使用
User user = await context.GetCurrentUser();

现在是房产 可以仍然像这样使用
public Task<User> CurrentUser => currentUser.Value;

因为 getter 是一种方法,但在我个人看来,这不是一个非常直观的设计。
User user = await context.CurrentUser;

如果过早访问,可能会产生不良结果。

我之所以提到它,是因为示例中显示的原始上下文的设计。

关于c# - 如何在涉及异步调用的 ASP.NET Core 中初始化作用域注入(inject)类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59633626/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com