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

标签 c# .net async-await task n-tier-architecture

如果这个问题跑题了,您可以在评论中写下稍后删除:)

如果我有一个 3 层 ( *.DLL's )

  • DataAccessLayer.DLL
  • 业务逻辑层.DLL
  • UI 应用程序(WPF、WinForms,任何技术)

在我的应用程序中,我让 BusinessLogicLayer 方法返回 Task,在 UI 应用程序中,当我使用来自 BusinessLogicLayer 的方法时调用 await

我有以下误解:

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

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

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();
}

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

public Task MoveNext() => Task.Run(() => { EntryBase.MoveNext(); });

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

 private async void BtnNext_ItemClick(object sender, ClickEventArgs e)
 {
    await EntryLogic.MoveNext();
    DeserializeBuffer();
 }

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

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

What i actually do is failed and don't know why this happen

我尝试制作如下场景:

  • 将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();
          });
         }
    
  • 然后在中间层BusinessLogicLayer中调用await

    public async void MoveNext() => await EntryBase.MoveNext();

  • 然后从逻辑层调用 UI 层中的 MoveNext。我想这将使它可以等待,因为它已经在 middle-were 层中声明了等待。但实际上UI层同时执行了下一个方法。所以抛出的异常是因为关闭下一个方法(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 */
      }
    

如有任何帮助,我们将不胜感激。

最佳答案

What i need to make is get rid off await's keywords and async in UI layer.

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

您的数据访问技术未指定,但从代码来看,我猜它可能是基于 DataTable 的,这是有问题的,因为 DataTable 非常古老并且确实不支持异步。注意 wrapping method bodies with Task.Run to "make them asynchronous" is an antipattern - 这些实际上是 fake-asynchronous methods ,不是真正的异步。

如果我错了并且您的数据访问技术确实支持async,那么您应该能够使您的 DAL 方法async不使用 Task.Run。从最低 级别开始(例如,FetchDataBuffer 调用的任何方法)并将它们更改为异步等价物。然后让 async 从那里成长。请注意,“让异步增长”意味着使用 async Task,而不是 async voidasync void in the BLL is definitely an antipattern .

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

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

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

关于c# - .NET 中的 N 层架构模式中的哪一层应该填充并发和任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55161008/

相关文章:

c# - 判断一个结构体是否为没有 "Equals"的默认值;也称为结构的 ReferenceEquals

c# - 从 web api post 返回文本\纯 json 响应

c# - 使用 C# 进行多平台开发

c# - 在 C# 中将正数转换为负数

c# - 使用反射进行异步编程

c# - nuget 包安装生成的空数据上下文

c# - 同一程序集的两个副本的程序集标识可以不同吗?

c# - 在为 datagridview 分配数据源时添加行

c# - Await Task.WhenAll() 内部任务不等待

c# - 异步调用2个方法