|Posted on February 5, 2013 at 1:20 PM|
I have spent a time working on a business multiplatform app which shares almost all its code between two "plaforms": Command line app (Net 4.0) and Windows Phone 7.
Last decision we took was to add Windows 8 to the list of supported platforms, and obviously the doubts arised early when I took a look to the new async I/O methods offered by WindowsRT API. So, this post is an attempt to help others in the same situation I was to don't make same mistakes I made.
Let's go ...
¿What's the big change on WindowsRT async APIs?
Well, one of the attempts made by Microsoft with WindowsRT is to fix a long standing problem of Windows applications: the unresponsive UI effect. It usually happens due to bad programming practices used by developers. So to avoid this problem in WinRT the I/O APIs has been designed such that any method taking longer than 50 milliseconds has been declared as an async method. Indeed, if you try to transform those async methods in sync methods and your UI thread spends too many time waiting the I/O operation to finish, the operation is cancelled by the OS.
With this in mind let's see the two ways I see for porting to WinRT a synchronous module that has to be called from the UI thread.
First option, the one I like to call "Brute Force", is to change the code of your synchronous module to make it asynchronous. Despite async/await is a wonderful mechanism that makes easy asynchronous programming, when you have several layers in your module things can turn complicated and dirty when all your methods use async/await keywords. In fact, synchronous programming always will be easier than asynchronous one, no matter how easy is the asynchronous mechanism you are using. So, most sensible strategy should be use it only when it is needed not everywhere.
Looking at the figure you could have guessed this option is the tough one. However, it is the one usually used on a first attempt by newcomers to WinRT. ¿Why? Well, the first problem when you port your code to a WnRT project comes at compilation time, you get errors because your I/O calls to WinRT API are no longer available. Their replacements are asynchronous ones. So in order to harness them you start to add awaits to your code and its related async keyworks. Next you add more asyncs to the methods which call previous ones. At the end of the day you find you have modified your entire module putting those new keywords everywhere. It is just in that moment when you think to yourself: "Who's the xxxxxx at Microsoft who thought async/await mechanism was brilliant?". Stand and breathe maybe he was right and you are doing something wrong, don't you think?
Second option has two steps, first to create a synchronous I/O service to communicate with the WinRT API. It will convert asynchronous I/O operations in synchronous one. At this point your application will compile properly. Problems indeed will come at runtime when your UI thread attempts to execute the I/O methods you transformed in synchronous with the .Wait() method, It will throw an exception. So, in order to solve it we will add the second step, this is the THE TRICK : we will make a kind of Agent Service for your synchronous module which will allow the UI to communicate with your module asynchronously removing the need of making asynchronous almost all the methods of your module. With only this two changes you have ported your module to WinRT. Obviously, you have to be sure that you programmed it to be thread-safe to avoid problems.
Next you can see a little sample of the kind code you will need to include for your Agent Service and for your I/O Service:
Summarizing, my interpretation of WindowsRT intent is that if expects you left the UI thread free of I/O responsibilities (non blocked waiting for I/O) and put this dirty work on a different thread. My understanding says me I'm not violating any WinRT rule with this approach, in fact I think it is more natural than the first one because it uses Async only where it is needed not everywhere. Even though after discuss it with other partners I cannot state that I'm 100% secure that it will pass Microsoft Store control, just because I still have not published any app.
So I will be pleased to hear your comments validating or rejecting what I state. Specially if you are someone with deep knowledge on WinRT and its restrictions (MVPS, Microsoft Store publishers ...).
If I'm right then this is a point to take into consideration by developers working on database libraries and other I/O related operations for WinRT. By the moment I have seen some APIs offered for WinRT versions of those kind components and surprisingly I found they were only asynchronous. They didn't offer the alternate synchronous version of their methods. The reason maybe is they follow what Microsoft has done for their APIs. However, if they would offer a synchronous version of their methods we won't need to develop a Synchronous I/O service for their APIs when we port or share code with other platforms that were programmed without async/await mechanism.
"Microsoft feels that when a developer is given the choice of a synchronous and an asynchronous API, developers will choose the simplicity of a synchronous API. The result usually works fine on the developer system, but is terrible when used in the wild." Miguel de Icaza
The reason why Microsoft doesn't offer the synchronous version of its I/O methods is they don't expect developers use them properly, so in that way they want reeducate developers to adopt the new paradigm and avoid erros of the past. In fact, despite it is possible to convert an asynchronous method to synchronous they by default don't offer the synchronous one. They don't take risks delegating on developers the responsibility of using a different thread for I/O operations.
What I propose to other I/O library developers is that they offer synchronous versions of their methods. Why?, because in that way they help to their customer. Currently, only offering asynchronous methods they only help to Microsoft to spread the new paradigm but at the prize of force its customers to write code for wrapping each of the synchronous method we use from their APIs or use an async on every method of your app.
A clarification I would like to make is that I'm neither saying async/await mechanism is bad nor that restrictions and rules for WinRT are a bad idea. In fact, I think they are necessary if we want to move forward the user experience in our apps. The focus of this post is to stand out that when a technology or mechanism is good for solve a problem it doesn't mean it has to be used everywhere. Just because in other contexts its use is useless.and adds complexxity without need.
Well, now is your turn ;), please write comments I will be more than happy to hear your thoughts. Do you think second option will pass the Windows Store control? Do you think third-party I/O APIs should ease our life offering both versions of their methods, synchronous and asynchronous.
See you soon!