【问题标题】:How to wait for the response of event handler in C#?如何在 C# 中等待事件处理程序的响应?
【发布时间】:2021-01-23 09:55:32
【问题描述】:

我有一个分为多层的应用程序 (A1)。有些层用于用户交互,有些用于与不同的数据库交互,有些包含业务逻辑。我们有另一个第三方应用程序 (A2) 向 (A1) 发送请求,A1 需要响应该请求。下面是A1的架构。

T3(此层接收来自 A2 应用程序的请求)

T2(业务逻辑)

T1(用户界面)

T2 包含所有的业务逻辑。我面临的问题是当我收到来自 A2 应用程序的请求时。我需要根据 T2 中出现的一些业务逻辑来响应请求。我可以从 T2 订阅的 T3 调用事件,但我必须从事件处理程序中获取数据,如下所示;

T3:

public Response CanStore(string materialType){
    //Invoke event and wait to get response from T2
    return response.;

}

T2:订阅了T3的事件

 public async void canStore(object sender, EventArgs e){
     //Perform some logic and response result to T3
}

有可能吗?

【问题讨论】:

  • 当您说“层”时,这些逻辑层是指这些逻辑层(即同一运行进程中的程序集)还是使用 HTTP 或 gRPC 之类的单独服务?
  • 是的。运行过程是一样的
  • 那么为什么 T3 -> T2 使用事件呢?为什么不直接调用方法并获得响应?
  • @Fildor 如果是这样,您可以从应用程序接收事件直接调用业务逻辑,这就是我的方式。我不知道你为什么要反过来
  • “因为 T3 没有 T2 的参考。” ...为什么不呢?什么是 T3?它的目的是什么?它是某种 API(也许可以替代在 T1 中使用用户界面?)?这似乎很可能,正如您所说,它可以接收来自其他应用程序的请求。如果是这样,那么引用业务逻辑层将是有意义的。为什么 T2 需要引用 T3 呢?这似乎是错误的方式。 T3是否也有其他用途?如果是这样,那么考虑将组件拆分为 2 个(或更多)具有特定用途的组件。

标签: c# event-handling


【解决方案1】:

在我看来,你的架构是错误的

如果 T2 有业务逻辑,并且 T1 是一个用户界面,可能需要访问业务逻辑,而 T3 是一个从外部方接收消息的应用程序,需要访问业务逻辑,那么 T1 和 T3 都需要对 T2 的引用。

那么这只是将业务逻辑依赖注入到 T3 中的简单一点!

public class T3Service
{
    private readonly IT2BusinessLogic businessLogic;

    public T3Service(IT2BusinessLogic businessLogic)
    {
        this.businessLogic = businessLogic;
    }

    public Response CanStore(string materialType)
    {
        var t2Response = businessLogic.CanStore(materialType);
        // Do what you like to build response to external service
        return response;

    }
}

【讨论】:

  • 你是对的。起初,我与制作这个架构的人争论。但不知何故还有其他限制,因为这是一个非常庞大的应用程序,包含大约 20-30 层。
  • @umer 那么你问了一个关于复杂问题的过于简单的问题。我只能根据你提供的信息来回答。
  • @umer 举起并放弃亮红旗,现在。这听起来像是你在一个整体破碎的设计周围踮着脚和修补补丁。再这样下去只会让事情变得更糟。
  • 好的。我同意你们所有人的看法,但有没有可能等待事件处理程序响应。
  • @umer 可能是的,但如果你不能将响应与请求联系起来,那就没什么用了。
【解决方案2】:

除了架构问题并假设您可以修改 T3 和 T2,您可以使用一些自定义 EventType 来解决滥用 EventArgs 的问题。不是我最喜欢的,但可以解决你的问题。

让 T2 操作 EventArg 以在其中存储所需的结果。 完成 Eventhandler 后,调用站点 T3 可以从 eventArg 中获取结果。

类似

public Response CanStore(string materialType){
    //Invoke event and wait to get response from T2
    myEvent.Invoke?(sender, myCustomEventArgs);
    await myCustomEvent.Completion.Task;

    return myCustomEvent.ResponseFromSubscriber;
}

myCustomEvent 使用两个属性扩展您当前的事件,

MyCustomEventArgs: MyCurrentEventArgs
{
    // makes your Event "awaitable";
    TaskCompletionSource<bool> Completion{ get; } = new TaskCompletionSource<bool>; 
    Response ResponseFromSubscriber{ get; set; } // As you need 
}

和订阅者

public async void canStore(object sender, EventArgs e){
    //Perform some logic and response result to T3
    if(e is MyCustomEventArgs myCustomEventArgs)
    {
        myCustomEventArgs.ResponseFromSubscriber = new Reponse(); // Your whatever 
        myCustomEventArgs.Completion.SetResult(true); // Triggers the Task completion for your awaiting EventInvoker
    }
}

【讨论】:

  • 使用这种方法有什么危害吗?
  • public Response CanStore(string materialType){ 你不能在这里使用await ...
  • 我刚刚注意到异步事件处理程序,并通过这条路线展示了如何使其适应异步环境。根本没有必要,也不是线程安全的。甚至没有保存到多个订阅者都在搞乱 EventArgs。只是一个独立于良好架构的“让它现在工作”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
相关资源
最近更新 更多