等待作用域属性的初始化



在.net核心应用程序中,我有一个ISessionService(它只包含各种可重用的属性,比如基于当前URL的当前"公司"。

它在启动时定义如下:

services.AddScoped<ISessionService, SessionService>();

SessionService的属性是.Company。但在.Company中,会对数据库进行调用,因为它是一个属性,所以无法等待。所以目前看起来像

public ICompany Company => dbContext.GetCompany(host).Result

.Result导致应用程序在重负载下挂起。我可以把它放在SessionService的构造函数中,但这只是把.Result从属性移到构造函数中,并导致同样的问题。

有没有一种方法,也许通过初始化SessionService,以异步方式初始化,而不必执行任何同步调用,如.Result?

不要引入任何异步代码的同步阻塞。您将损害应用程序的性能和可扩展性。

您想要的东西应该通过中间件和功能的组合来完成。

您的中间件应该将该信息添加到特性集合中。

我可以看到它们是如何在代码库中使用的。

由于您有一个声明的属性,它需要一些时间才能得到结果,因此它的类型应该是Task<ICompany>:

public Task<ICompany> Company => dbContext.GetCompany(host);

话虽如此,我现在展示了一个选项,它可以以异步方式初始化类。

提供一种异步初始化方法:

public class SessionService
{
public string Company { get; private set; }
//Inject DbContext via CTOR
public Task InitializeAsync()
{
//Use DbContext, probably think about caching
Company = "Async Company";
return Task.CompletedTask;
}
}

然后创建一个中间件,该中间件调用InitializeAsync方法*:

public class InitializationMiddleware : IMiddleware
{
private readonly SessionService _sessionService;
public InitializationMiddleware(SessionService sessionService)
{
_sessionService = sessionService;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
await _sessionService.InitializeAsync();
await next(context);
}
}

将所有内容注册到ServiceCollection:

services.AddScoped<InitializationMiddleware>();
services.AddScoped<SessionService>();

最终使用中间件(可能在app.UseAuthorization();之后(:

app.UseMiddleware<InitializationMiddleware>();

*作为替代方案,您可以将SessionService本身设置为IMiddleware,并在InvokeAsync中对其进行初始化。然后您将使用app.UseMiddleware<SessionService>();

最新更新