哪一层应该填充 .NET 中 N 层架构模式中的并发和任务

3 .net c# task n-tier-architecture async-await

如果这个问题偏离主题,请在评论中写下稍后删除:)

如果我有 3 层(*.DLL)

  • 数据访问层.DLL
  • 业务逻辑层.DLL
  • UI 应用程序(WPF、WinForms、任何技术)

在我的应用程序中,我使 BusinessLogicLayer 方法返回任务,在 UI 应用程序中,当我使用 BusinessLogicLayer 中的方法时,我调用 wait

我有以下误解:

  • 任务或并发应支持哪一层(后端、中间、前端)
  • 如果我需要为其他开发人员制作可重用的 BusinessLogicLayer,他们也可能忘记在处理他们的下一个项目中使用 UI 应用程序层中的可等待/异步方法。如何在中间层实现可等待的方法,而不需要在每个 UI 事件(例如 Button_Click)中编写等待。
  • 如何让DataAccessLayer只包含UI层中的并发和await,而不需要使用awaitasync关键字。

我的简单代码包含以下内容:

DataAccessLayer.DLL单一方法

public void MoveNext()
{
    if (RecordCount == 0) return;
    Tables[0].Query.Criteria.Clear();
    Tables[0].Query.Sorting = $"ORDER BY {string.Join(" ASC, ", 
    Tables[0].Keys.Select(x => x.KeyID))} ASC";
    FetchDataBuffer();
}
Run Code Online (Sandbox Code Playgroud)

BusinessLogicLayer.DLL现在以简单的方式包装了数据访问方法

public Task MoveNext() => Task.Run(() => { EntryBase.MoveNext(); });
Run Code Online (Sandbox Code Playgroud)

UI 层(.NET 中的任何应用程序或前端提供商)

 private async void BtnNext_ItemClick(object sender, ClickEventArgs e)
 {
    await EntryLogic.MoveNext();
    DeserializeBuffer();
 }
Run Code Online (Sandbox Code Playgroud)

如上所示,在并发方法 ( MoveNext ) 完成之前, DeserializeBuffer方法不会执行。

我需要做的是摆脱UI层中的await关键字和async

我实际上做的是失败的,不知道为什么会发生这种情况

我尝试制作的场景如下:

  • 将DataAccessLayer的方法类型从void转换为Task

       public Task MoveNext()
       {
          return Task.Run(() => { 
          if (RecordCount == 0) return;
          Tables[0].Query.Criteria.Clear();
          Tables[0].Query.Sorting = $"ORDER BY {string.Join(" ASC, ", 
          Tables[0].Keys.Select(x => x.KeyID))} ASC";
          FetchDataBuffer();
          });
         }
    
    Run Code Online (Sandbox Code Playgroud)
  • 然后在Middle-weer层BusinessLogicLayer中调用await

    公共异步无效MoveNext()=>等待EntryBase.MoveNext();

  • 之后从逻辑层调用UI层中的MoveNext。我想这将使其成为可等待的,因为它已经在中间层声明了等待。但实际上UI层同时执行了next方法。因此抛出的异常是因为下一个方法(DeserializeBuffer)取决于上一个方法(EntryLogic.MoveNext)

      private async void BtnNext_ItemClick(object sender, ClickEventArgs e)
      {
        EntryLogic.MoveNext();
        DeserializeBuffer();  // exception thrown   
         /* because EntryLogic.MoveNext 
         is still executing and not awaited */
      }
    
    Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激。

Ste*_*ary 5

我需要做的是摆脱UI层中的await关键字和async。

这是完全错误的。UI层是唯一async必须使用的await 地方。它们确实必须在该层中使用。

您的数据访问技术未指定,但从代码来看,我猜测它可能是DataTable基于 的,这是有问题的,因为DataTable它非常旧并且不支持async. 请注意,用“使它们异步”包装方法体Task.Run是一种反模式- 这些实际上是假异步方法,而不是真正的异步方法。

如果我错了并且您的数据访问技术确实支持async,那么您应该能够async在不使用Task.Run. 从最低级别开始(例如,无论FetchDataBuffer调用什么方法)并将它们更改为异步等效项。然后让我们async从那里成长。请注意,“让异步增长”意味着使用async Task,而不是async voidasync void在 BLL 中绝对是一种反模式

但如果我是对的并且您的 DAL 使用的是DataTable,那么您需要决定是否切换到更新的数据访问技术。如果这不是您现在可以做的事情,那么我建议保留现有的 DAL 和 BLL 代码,只将async/添加await到 UI 层:

private async void BtnNext_ItemClick(object sender, ClickEventArgs e)
{
  await Task.Run(() => EntryLogic.MoveNext());
  DeserializeBuffer();
}
Run Code Online (Sandbox Code Playgroud)

这不是反模式,因为我们用来Task.Run调用一个方法 - 将其移出 UI 线程。这并不理想,因为我们仍然使用了超出必要数量的线程,但理想的解决方案需要真正的异步数据访问。通过这种妥协,您的 DAL 和 BLL 仍然处于阻塞状态,因此它们在桌面 UI 应用程序之外的使用受到限制。