【问题标题】:Get DbContext in async action在异步操作中获取 DbContext
【发布时间】:2021-01-29 07:30:06
【问题描述】:

我正在重写/将网站从 ASP MVC 移动到 ASP MVC Core。此应用程序有一个取决于登录用户的动态菜单。为了构建菜单,每个控制器都从一个自定义的BaseController 派生,该BaseController 设置了ViewBag 菜单项,稍后,在布局中,这些项目被检索并作为参数传递给PartialView

public BaseController:Controller
{
    public BaseController()
    {
          ...
          ViewBag.Menu=Utils.GetMenu();
          ...
    }
}

我不想使用与编写旧代码的小伙子相同的逻辑。所以我想用ViewComponent 来渲染菜单。但我对这种方法有疑问。在调用方法中,我需要查询菜单项。现在,我从服务提供者 (HttpContext.RequestServices) 获得了一个 DbContext 实例,并使用它来查询我需要的任何数据。但是Invoke函数是从Layout异步调用的,我知道将DbContext发送到async方法不是很好:

<cache expires-after="@TimeSpan.FromHours(2)" enabled="true">
       @await Component.InvokeAsync(typeof(Admin.ViewComponents.MeniuViewComponent))
</cache>

这是一个好方法吗?在 Invoke 方法(或任何其他 async 方法或操作)中获取 DbContext(在 Startup 中注册为 Scoped)并使用它是否安全?如果这不是一个好主意,我应该如何处理这种需要async方法中的db数据的情况?

【问题讨论】:

  • 看起来您没有将表示层与数据层分开。你有存储库来操作数据库数据和服务来处理一些业务逻辑吗?在视图内不进行任何类型的数据库调用是一种常见的方法。您必须准备好所有数据并将其发送到您拥有的视图中。
  • 是的,我有。但是在存储库中,我尝试从缓存中获取数据(我使用 MemoryCache),如果它未命中,我会从数据库中获取它们。无论如何,视图组件不应该提供动作样式支持吗?我不是试图从 View 中获取数据,而是尝试从 Invoke 函数中获取数据。

标签: c# asp.net-core async-await entity-framework-core asp.net-core-viewcomponent


【解决方案1】:

我的项目中有一个案例是从 asp.net 核心获取 HostedService 中的 DbContext。

我在构造函数中注入了 IServiceProvider 并构建了自己的作用域,以获取注册的 DbContext:

private readonly IServiceProvider _serviceProvider;
public BaseController(IServiceProvider provider){
  _serviceProvider = provider;
}

private void DoSth(){
  using var scope = _serviceProvider.CreateScope();
  var db = scope.ServiceProvider.GetRequiredService<YOUR_DbContext_CLASS>();

  ... //do something great stuff here with the database
}

【讨论】:

  • 您需要将scope 变量包装在using 子句中。否则您的数据库上下文将不会被处理
  • @YegorAndrosov 谢谢你的暗示,你是绝对正确的。这是一个拼写错误/复制粘贴错误,因为我将范围变量与 using 一起使用以在最后处理它
  • @DannySchneider 谢谢!所以每当我处理可以称为异步的函数时,我应该创建一个新的 dbcontext?
  • 我认为这取决于,尝试找出您的作用域生命周期以及在请求生命周期内的哪个位置需要您的数据库上下文。范围内的注册类在单个请求生命周期中被实例化一次。如果在使用之前没有处理范围,我认为@mj1313 套件的方式最好......
【解决方案2】:

我认为你可以直接在 ViewComponent 中依赖注入 DbContext

public class MenuViewComponent : ViewComponent
{
    private readonly MenuDbContext _context;

    public TopMenuViewComponent(MenuDbContext context)
    {
        _context = context;

    }

    public async Task<IViewComponentResult> InvokeAsync()
    {
        var model = _context.MenuItems.ToList();

        return View("Default", model);
    }
}

更多详情,请参考doc

【讨论】:

  • 是的,我知道我可以通过这种方式获得它。但是在这种情况下,注入的 dbcontext 在请求期间调用的所有方法中都是共享的。使用这个共享的 dbcontext 是否安全?
猜你喜欢
  • 2022-11-02
  • 2020-07-18
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
相关资源
最近更新 更多