I've read a lot of articles about asynchronnous programming, but I'm not sure in one thing. I have 3rd party winrt library, written in C++ and I want to wrapp it. So now I have:
public Task LoginAsync(){
return Task.Run(winrtLibrary.Login();)
}
According Stephen Cleary and Stephen Toub blogs, it is not good solution. But when I use the method synchronously, my UI will not be responsive and will be blocked. Is it better to expose service method synchronously and in UI use Task.Run?
What Stephen Toub means by
do not use Task.Run in the implementation of the method; instead, use Task.Run to call the method
Is that you shouldn't use Task.Run
to hide CPU bound work behind async methods (Task
returning methods). If you need to wrap external code, hide it behind an interface which reflects what this code do. Any asynchronous I/O can (and should) be exposed as Task
returning methods, and CPU bound work must be exposed with the proper API. Let the consumers of your code to decide for themselves how to use that code. When you happen to by the consumer too, use Task.Run
to run your synchronous code (now wrapped and exposed via interface) where it is very clear that you are offloading CPU bound work. In UI apps, for example, you should call Task.Run
in your UI layer (and not deep down in your BL or even DA layers), where it is very clear that the UI offloads some CPU bound work.
Why do you think, that I shouldn't call Task.Run in BL? What if I have ViewModel, which references BL and BL references service layer (in my case is it wrapper).
I think that a method signature should reflect exactly what the method does. The best I can do is to redirect you back to Cleary's article:
When a developer sees two methods in an API winrtLibrary.Login() and winrtLibrary.LoginAsync(), the convention is that they represent a naturally-asynchronous operation. In other words, the developer expects that winrtLibrary.LoginAsync() is the “natural” implementation and that winrtLibrary.Login() is essentially a synchronous (blocking) equivalent of that operation. That API implies that winrtLibrary.Login will at some point have the calling thread enter a wait state as it blocks for the naturally-asynchronous operation to complete.
You can still hide synchronous code behind async method and follow Cleary's rule of thumb, if you sign your method as public Task OffloadLoginToTheThreadPool()
. But I think (and apparently Cleary, too) that the alternative of simply calling Task.Run
from the UI (or Controller) is a much better approach, and it follows the principles of Clean Code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With