In the last entry I showed you why you should use the NetworkChange.NetworkAddressChanged API to control when to check if your application is online or not. If you didn’t read that article, go do it now – it will help you understand why online detection is hard, and why the network detection code is made the way it is.
As with all code, there are certain code patterns you can use to organize your online detection code. Using the patterns means you are more likely to write good code that works well; ignoring the patterns means you are more likely to write hard-to-maintain code that doesn’t quite work well enough. What are the good code patterns for online detection? It turns out that there are at least three. Like any good blogger, I’ve got clever names for all them:
A is for Ask the User.
B is for Before you Connect, Validate
C is for Constantly Check Results
Ask the User is good because sometimes users have information that you do not – for example, that an upstream router is back on line, or that they have entered (into another window) some token or bit of authorization. They also know that they are on an automatically-dialed connection, and that they pay by the minute, and that even if your program could connect, they really don’t want it to connect right now. (There are always stories nowadays of people who accidently turned on “international roaming” and were charged thousands of dollars of fees)
Before you Connect, Validate is simple: you check a known file on your server before any other activity. You have to check the file when your application starts and when you get a callback from NetworkAddressChanged. Do not forget that you have to check the contents of the file, not just the status code! There are several tricks to make sure that the file is truly from your server and not from a cache. First, it helps to add in a query on the URL that points to the file. The query should be different each time (a GUID, perhaps, or a random number), and the file should include the query parameter. That way you can be fairly confident that there aren’t any caches trying to help you when you really don’t want them to.
Constantly Check Results means that you can try to download a file or resource any time – but that each time you do, check the results to make sure that it’s really a file from your server. After getting a valid response that isn’t from your server, you must be in something like the “Airport Coffee Shop” case – someone is returning data as if they are your server, but it’s not. In this case, your application might start queuing up all of the network requests and then retry them when the network might be available (which, as always, you know because you get a callback from NetworkAddressChanged).
Each of these methods has advantages and disadvantages. Asking the user all the time, for example, is a big thing to ask. However, please always consider this on a setup or preferences page. Some users really do have to pay for bandwidth and will not be pleased with any application that goes onto the network without permission.
The before you connect, validate code pattern is simple, but requires that you put a known file on your server. It’s also a bit slower to detect network availability because it will also check before allowing an actual file to be transmitted. Lastly, the network might change faster than the code responds, resulting in bad data being accepted as good data.
The constantly check results pattern is more complicated to implement, and requires that you be able to validate each possible result – and that may not be possible. On the other hand, it’s recovers faster and generates less network traffic.
MSDN documentation for the NetworkChange.NetworkAddressChanged event is at http://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkchange.networkaddresschanged.aspx
I gave a talk at Mix ’09 about network detection and reachability: http://videos.visitmix.com/MIX09/T78M (also look at the slide deck—it has notes that go into more depth than the presentation). The talk is for Silverlight 3 users, but it applies to both the full framework and the Silverlight framework.