[英]Satisfying an async interface method when you can only run sync
I'm consuming an "API" (I use the term loosely) that's implemented as a COM+ object.我正在使用作为 COM+ 对象实现的“API”(我松散地使用该术语)。 As far as I'm aware, there's no support for any of the queuing functionality COM+ offers, but I know pretty much exactly nil about COM+.
据我所知,不支持 COM+ 提供的任何排队功能,但我对 COM+ 的了解几乎为零。 Take it with a grain of salt.
把它和一粒盐一起吃。 I have just one method available to me:
invoke
, and it's sync.我只有一种方法可用:
invoke
,它是同步的。
In a stroke of somewhat personal brilliance, I created a Web Api wrapper around this COM+ object, which has just one endpoint, invoking the COM+ object with the post body of the request.出于个人的聪明才智,我围绕这个 COM+ 对象创建了一个 Web Api 包装器,它只有一个端点,使用请求的 post 主体调用 COM+ 对象。 This has allowed me to make asynchronous calls to the Web Api instead (as well as remove the god-awful dependency from my apps).
这使我可以改为对 Web Api 进行异步调用(以及从我的应用程序中删除可怕的依赖项)。
Now, I'm creating a library to basically abstract all this mess, but I decided to implement a provider pattern where you can choose to either use the COM+ directly or the Web Api wrapper.现在,我正在创建一个库来基本上抽象所有这些混乱,但我决定实现一个提供者模式,您可以选择直接使用 COM+ 或 Web Api 包装器。 I have an interface, obviously, with both sync and async methods.
很明显,我有一个接口,包含同步和异步方法。 The Web Api provider is of course no problem as you can do an HTTP request either way, but I'm hitting a wall with the COM+ provider.
Web Api 提供程序当然没问题,因为您可以通过任何一种方式执行 HTTP 请求,但是我与 COM+ 提供程序遇到了障碍。 Since async is not an option there.
由于异步不是那里的选项。
So, I have three options as I see it:所以,在我看来,我有三个选择:
"Implement" the async interface method with a NotImplementedException
, which is a violation of the interface segregation principle. “实现”带有
NotImplementedException
的异步接口方法,这违反了接口隔离原则。
Do something ill-advised like use Task.Run
, which I know is not really async in this context, and basically lies to anyone programming against my library.做一些不明智的事情,例如使用
Task.Run
,我知道在这种情况下它并不是真正的异步,并且基本上是针对针对我的库进行编程的任何人。
Do something like create a sync and async version of the interface, which is better from a interface segregation standpoint, but worse from a provider pattern standpoint.做一些事情,比如创建接口的同步和异步版本,从接口隔离的角度来看更好,但从提供者模式的角度来看更糟。 If I depend on the async interface, then the COM+ provider can never be used, and if I depend on the sync interface, then I can never use the async methods of the Web Api provider.
如果我依赖于异步接口,那么 COM+ 提供程序将永远无法使用,如果我依赖同步接口,那么我将永远无法使用 Web Api 提供程序的异步方法。
Long and short, my general question is what do you do in a situation where you need to run something asynchronously, but the method you need to utilize can only be run synchronously?总而言之,我的一般问题是,在需要异步运行某些东西但需要使用的方法只能同步运行的情况下,您会怎么做? If there's no real alternative, then what is the least offensive way to satisfy an interface requirement?
如果没有真正的替代方案,那么满足接口要求的最不冒犯性的方法是什么?
EDIT编辑
I forgot to mention one more option:我忘了再提一个选项:
Task.FromResult
with the result.Task.FromResult
。 This means I'm not pulling a new thread (which could be an issue in a web application), but I'm not sure if this is really any better than Task.Run
in the sense of lying to the consumer about this actually being "async".Task.Run
更好, Task.Run
它实际上是向消费者撒谎“异步”。The solution I landed on was to use Task.FromResult
to return a Task
even though nothing async is being done.我找到的解决方案是使用
Task.FromResult
返回一个Task
即使没有进行任何异步操作。 While this is not actually async, it satisfies the interface.虽然这实际上不是异步的,但它满足接口。 I then commented the method to note that it will run sync and should be passed as a delegate to
Task.Run
in situations where the thread cannot be blocked (GUIs, for example).然后,我对该方法进行了注释,以指出它将运行同步,并且在无法阻止线程(例如 GUI)的情况下,应将其作为委托传递给
Task.Run
。 Using Task.Run
is not appropriate in every situation (web applications, for one) and is an implementation detail that should be decided upon by the consumer of the library.使用
Task.Run
并不适用于所有情况(例如 Web 应用程序),它是一个实现细节,应该由库的使用者决定。
That said, to truly implement this, you need to handle three Task
scenarios: completed, faulted, and cancelled.也就是说,要真正实现这一点,您需要处理三个
Task
场景:完成、故障和取消。 Here's the actual code to do all this:这是执行所有这些操作的实际代码:
public Task<int> DoSomethingAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<int>(cancellationToken);
}
try
{
return Task.FromResult<int>(DoSomething());
}
catch (Exception e)
{
return Task.FromException<int>(e);
}
}
First, this ensures that the operation hasn't been canceled.首先,这可确保操作未被取消。 If it has, a canceled task is returned.
如果是,则返回已取消的任务。 Then, the sync work we need to do is wrapped in a try..catch block.
然后,我们需要做的同步工作被包裹在一个 try..catch 块中。 If an exception is thrown, we'll need to return a faulted task, which includes that exception.
如果抛出异常,我们需要返回包含该异常的错误任务。 Finally, if it completes correctly, we return a completed task.
最后,如果它正确完成,我们返回一个已完成的任务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.