[英]awaitable event handler delegate for ASP.NET
I have an ASP.NET MVC/WebAPI application where the domain logic depends on events in certain circumstances to decouple concerns.我有一个 ASP.NET MVC/WebAPI 应用程序,其中域逻辑在某些情况下依赖于事件来解耦关注点。 It's becoming increasingly difficult to avoid using async methods in the event handlers, but being that this is a web application I want to avoid using
async void
as these are not top level events that we're dealing with.在事件处理程序中避免使用异步方法变得越来越困难,但由于这是一个 web 应用程序,我想避免使用
async void
,因为这些不是我们正在处理的顶级事件。 I've seen some solutions that seem overly complex for dealing with this- I'd like to keep the solution to this simple.我见过一些似乎过于复杂的解决方案来处理这个问题——我想保持这个简单的解决方案。 My solution is to ditch
EventHandler
delegates and use a Func
that returns a Task
instead, eg:我的解决方案是
EventHandler
委托并使用返回Task
的Func
,例如:
public event EventHandler<MyEventArgs> SomethingHappened;
would be refactored to:将被重构为:
public event Func<object, MyEventArgs, Task> SomethingHappened;
so in my code I can do this:所以在我的代码中我可以这样做:
if (SomethingHappened != null)
{
await SomethingHappened.Invoke(this, new MyEventArgs());
}
We're the only one consuming these projects, so using the standard convention of EventHandler
isn't absolutely necessary.我们是唯一使用这些项目的人,所以使用
EventHandler
的标准约定并不是绝对必要的。 While using this pattern implies knowledge that the handler is async, I'm not sure that's necessarily a bad thing as more and more libraries are dropping their synchronous API methods or simply not including them to begin with.虽然使用这种模式意味着知道处理程序是异步的,但我不确定这一定是一件坏事,因为越来越多的库正在放弃它们的同步 API 方法,或者根本不包括它们。 To some extent I'm surprised this isn't supported as a first class concept within .NET with async/await becoming increasingly prevalent in many libraries that are commonly used by web applications.
在某种程度上,我很惊讶这不支持作为 .NET 中的第一个 class 概念,异步/等待在 web 应用程序常用的许多库中变得越来越普遍。
This seems like an elegant solution.这似乎是一个优雅的解决方案。 I've tested this in a real application with multiple subscribers to the event, with different delays for each handler, and
Invoke()
awaits them all.我已经在具有多个事件订阅者的真实应用程序中对此进行了测试,每个处理程序具有不同的延迟,并且
Invoke()
等待它们。 Yet, it feels like a trap.然而,这感觉就像一个陷阱。 What am I missing?
我错过了什么?
Yet, it feels like a trap.
然而,这感觉就像一个陷阱。 What am I missing?
我错过了什么?
This part isn't correct:这部分不正确:
Invoke() awaits them all.
Invoke() 等待他们所有人。
Invocation of a delegate instance whose invocation list contains multiple entries proceeds by invoking each of the methods in the invocation list, synchronously, in order... If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.
调用列表中包含多个条目的委托实例的调用通过按顺序同步调用调用列表中的每个方法来进行...列表中的最后一个代表。
So, the Invoke
will invoke all the handlers, but only return the Task
from the last handler.因此,
Invoke
将调用所有处理程序,但仅从最后一个处理程序返回Task
。 The other returned tasks are ignored.其他返回的任务将被忽略。 Which is Very Bad (try throwing an exception from one of the ignored tasks).
这是非常糟糕的(尝试从被忽略的任务之一中抛出异常)。
Instead, you should call GetInvocationList
to get the list of handlers, invoke each one, and then await
them all using Task.WhenAll
:相反,您应该调用
GetInvocationList
来获取处理程序列表,调用每个处理程序,然后使用Task.WhenAll
await
它们:
var args = new MyEventArgs();
var tasks = SomethingHappened.GetInvocationList()
.Cast<Func<object, MyEventArgs, Task>>()
.Select(handler => handler(this, args))
.ToList();
await Task.WhenAll(tasks);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.