Today I decided I would add a ‘check for update’ option to my Eyes Relax application. This is quite useful feature, especially when you host your application on many hosting servers (like download.com and others). In this case it can be difficult for the user to check if there is a newer version of your software available, because:
- the user does not remember where he downloaded the application from
- there is an older version on the hosting server, so the user is not aware that there is a newer version of your app available
- simple, but very common reason: the user is too lazy to look for the new version :P; and because it’s easier to simply select the ‘update’ option in your application, it may work for lazy users
Beside those reasons this is a nice, small feature we can practice our c# programming skills on :). At least for me, because I’ve spent last two years mainly developing server modules in Python. Two major subjects are:
- HTTP file downloading
- simple XML parsing (
XmlTextReader
)
Let’s start.
General idea
First we need a way to provide our application with the information about the newest version. So what we do is put a little xml file anywhere on Internet (well, preferably on your homepage). In this xml file we store the number of the newest version of our app. While checking for update we download this xml, parse it and compare the version of running application with the version from the xml file.
Downloading the xml file
This is very easy – we just provide the XmlTextReader
with the URL of our XML file. The XmlTextReader
will download the file for us. What’s even better, it uses the .NET 2.0 internal solutions that detect the IE proxy settings (I’ve double-checked this and it really works :)), so this will work even when the user connects through a proxy.
Parsing the xml
As mentioned above, we will use XmlTextReader
(just remember to use System.Xml
). First take a look at our litte xml contaning the information about the newest version:
<?xml version="1.0" encoding="utf-8"?> <ourfancyapp> <version>1.2.3.4444</version> <url>http://some.domain/our_app_homepage/</url> </ourfancyapp>
As you probably noticed we store the version information in the same string format as c# Application.ProductVersion
. I’ve chosen this format because it will be easier to parse and compare the version numbers, as you will see later.
Ok, let use XmlTextReader
to parse the xml:
// in newVersion variable we will store the // version info from xml file Version newVersion = null; // and in this variable we will put the url we // would like to open so that the user can // download the new version // it can be a homepage or a direct // link to zip/exe file string url = ""; XmlTextReader reader; try { // provide the XmlTextReader with the URL of // our xml document string xmlURL = "http://domain/app_version.xml"; reader = new XmlTextReader(xmlURL); // simply (and easily) skip the junk at the beginning reader.MoveToContent(); // internal - as the XmlTextReader moves only // forward, we save current xml element name // in elementName variable. When we parse a // text node, we refer to elementName to check // what was the node name string elementName = ""; // we check if the xml starts with a proper // "ourfancyapp" element node if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "ourfancyapp")) { while (reader.Read()) { // when we find an element node, // we remember its name if (reader.NodeType == XmlNodeType.Element) elementName = reader.Name; else { // for text nodes... if ((reader.NodeType == XmlNodeType.Text) && (reader.HasValue)) { // we check what the name of the node was switch (elementName) { case "version": // thats why we keep the version info // in xxx.xxx.xxx.xxx format // the Version class does the // parsing for us newVersion = new Version(reader.Value); break; case "url": url = reader.Value; break; } } } } } } catch (Exception) { } finally { if (reader != null) reader.Close(); }
That’s how we parse our XML. Now we check if the newVersion
and url
are not empty. If they’re not, it means we successfuly downloaded and parsed the xml file and now we can…
…compare the versions
The Application.ProductVersion
is just a string, and it’s usually not sensible to compare strings containig numbers. Luckily in the .NET executing assembly there is a variable, which happens to be the same type as our newVersion
. It makes the comparing a lot easier 🙂 :
// get the running version Version curVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; // compare the versions if (curVersion.CompareTo(newVersion) < 0) { // ask the user if he would like // to download the new version string title = "New version detected."; string question = "Download the new version?"; if (DialogResult.Yes == MessageBox.Show(this, question, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question)) { // navigate the default web // browser to our app // homepage (the url // comes from the xml content) System.Diagnostics.Process.Start(url); } }
If the user answers ‘Yes’, we navigate the default browser to the URL we have from the downloaded xml file. I didn’t hardcode this URL in the code, because when we for example move our homepage, we would be in trouble. And in our solution we can simply change the url in the xml file and the users would be automatically directed to the new homepage.
Well, that’s all. As you see this was a pretty simple task. Hope you found it useful.
Enjoy,
mech
P.S. I wrote two more tutorials regarding this topic:
- How to download and install a new version of your C# application
- How to create a simple MSI installer using WiX
They both show how to implement ‘check for updates’ in a more mature way. You can also download the sample project
Excellent example! Very clean and easy to understand. Thanks!
Thanks for the sample. Easy to follow. i have one question: Say i want to update the version number in that XML file automatically when i make an update. How can i have the project plug the latest version into the file for me? Is it possible?
Hi Joe,
That’s an interesting topic you mentioned. To make it short: you can write you own (very simple) tool and attach it to the post-build event.
In Visual Studio you can use project build events to run your own console tool (f.e. publish.exe “$(TargetPath)”). This tool should open the compiled executable (the path is passed as a command line argument) and determine its version (you can use http://www.codeproject.com/KB/files/VersionApp.aspx as a starting point). At the end the tool should create a new xml containing the current version number (and optionally upload both the executable and the xml to your web server). Hope this helps.
One more thing to mention: I don’t think that every version of the application that compiles without errors should be published, it should be tested first 🙂 So it’s a good idea to create a new project configuration (called Publish and based on the Release configuration) and attach the tool I mentioned only in this config build events. In every day compiling you should use Debug/Release configurations and when you want to release the new version you should use Publish.
Thanks for the response mech. i haven’t quite got the hang of Publishing yet, as the application is small and in-house only. It would only be published to a network share. But you’re absolutely right, compiles != works. Since it’s still a small enough app, i do the testing myself in the VS environment. i suppose as it grows i’ll need to take your advice on a second build config. i’ll check into that link and see what i come up with.
Thanks again!
Question – how to do the actual update? If your patcher is launched from within the main app, how do you overwrite the files during run time? Also, for projects with multiple files (an exe, .config, and dlls) would you have a version.xml for all of them, or would you keep them all in one file?
Hi
I’ve assumed the simplest scenario here – our program just checks for the new version and allows user to download the installer for it. This solves the problem of multiple files.
Of course it would be easier if the application updated itself automatically. If you would like to do this I see two solutions:
1) Download the installer to the temporary directory. Execute the installer using Process.Start and immediately call Application.Current.Shutdown to end the running program. The installer should install the new version and re-launch our application. I wrote a simple tutorial about creating MSI installers.
2) If you don’t want to use the installer you can program the process yourself:
– check if the new version is available
– copy the current executable to a temporary location, execute it (Process.Start) and terminate the current process. While executing the app from the temporary location you should pass some parameters indicating it should perform an auto update.
– the new process downloads the new version, replaces the application files (while they are not locked now), executes the new version using Process.Start and terminates
– the new version should perform a cleanup removing the temporary executable created at the beginning.
I found your site on technorati and read a few of your other posts. Keep up the good work. I just added your RSS feed to my Google News Reader. Looking forward to reading more from you down the road!
Hi guys,
I’d like to thank you all (Erwin, Joe, Carson and Alex) for your feedback. In fact for the last 2 moths I have a real mess at work with a lot of over hours and because of it I have both – a lot of ideas what I’d like to write about and almost no time to actually write it. All your feedback (being honest I wasn’t expecting any for the first few months) gives me the feeling that writing these articles actually makes sense, cos there are people that find it useful. And your feedback of course gives the motivation to continue the work. So again, thanks to all of you.
I hope I’ll write another article in till the end of August. Some of the comments (Carson’s in fact) shows that the solution I presented is a very basic one and I fully agree with him. I’d like to explain how to implement ‘Check for update’ in a more advanced way and how to create MSI installers (that we’ll need) using WiX.
Regards,
mech
Your blog is interesting!
Keep up the good work!
Could you fix one thing? In the begining the variable name is newVersion and later is newVer.
Thank you Kerie, somehow I overlooked this bug. It’s fixed now.
Great blog post! This really helped me out, thanks!
mech this was very helpful. Thanks.
Thanks so much! Your thread was very helpful.
Hi Mech,
This is a wonderful idea! I’d like to implement it base on your samples. Thanks for sharing it!
I’ll give a credit to ya 😉
Regards,
Nullstring
Very good topic, excellent and easy to understand, thak you for this help .
Regards,
Great. I am surely giving you some deserved credit.
Thanks for the good article! Keep posting!
Awesome post, Worked perfect! It makes thing so much easier when you can find a strait forward answer to a question. and it doesn’t get any more strait forward than this!
Thanks again!
Wonderful! Thanks for the help, this was exactly what I was looking for! (well, this and your more detailed download post as well)
Please keep the posting up! I look forward to reading from your blog in the future.
Great article. 🙂
I noticed though that you never used a finally block to close the reader in case of an exception occurring.
John,
Thank you for pointing this out, you are absolutely right – the reader should be closed in both cases – when everything is OK and when an exception occurred during parsing. And try…finally is of course the way to do it. I’ve modified the example to follow your good-practice advice 🙂
Very nice example. Clean and straight to the point.
Great stuff..! 🙂
I implemented this in my own application and ran into a small inconvenience. My users are usually connected to their office on Cisco VPN which blocks most web addresses, including the URL where my XML is located. XmlTextReader.MoveToContent will return an exception fairly quickly if there is no network connection at all, but if the user is on VPN it takes about 60 seconds before it errors out.
So instead of giving XmlTextReader the URL of the XML file, I created an HttpWebRequest with a modest timeout value then used the GetResponseStream with the XmlTextReader.
# string xmlURL = “http://domain/app_version.xml”;
# HttpWebRequest hwRequest = (HttpWebRequest)WebRequest.Create(xmlURL);
# hwRequest.Timeout = 5000;
# HttpWebResponse hwResponse = null;
# XmlTextReader reader = null;
# try
# {
# hwResponse = (HttpWebResponse)hwRequest.GetResponse();
# reader = new XmlTextReader(hwResponse.GetResponseStream());
# reader.MoveToContent();
# …
# }
# finally
# {
# if (reader != null) reader.Close();
# if (hwResponse != null) hwResponse.Close();
# }
Are there any pitfalls with this method that I might be overlooking?
Dave
This is really interesting!!! Just what i was looking for 😀
I was really keen on using ClickOnce but this is much much more easy and neat! I just have to host the XML file somewhere 😀
Thanx a lot 🙂 🙂
Hello,
@OverTech: Yes, indeed, HttpWebRequest gives you more tcp/ip control than XmlTextReader does. I’ve checked your code snippet and it seems fine to be, well done 🙂
@Ranhiru: You should host two files: the XML and your installer for the new version, so users can download it. Luckily there are some free web hosting services that allow you to do so.
I used this code along with a downloader request code, and now the application checks the XML, and if there is an update, will ask if its OK to download it. it will then download it and install the Update. I am planning on adding a “update from USB drive” option that will check the drive for the XML file, and if the version is a newer one, install the update package from the USB drive.
Thanks for the nice article. I found it when I try to make VS publishing and CheckForUpdate work together. Do you have any thought on that?
By the way, on parsing out the version info from the xml file, it would be much easier using XPath. e.g.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlUrl);
Version version = new Version(xmlDoc.SelectSingleNode(“/ourfancyapp/version”).InnerText);
string url = xmlDoc.SelectSingleNode(“/ourfancyapp/url”).InnerText;
Well, I did some test and it works great.
Let me include it on my project.
I get a error here:
finally
{
if (reader != null) reader.Close();
}
It says “Error use of unsigned local variable “reader”
Steve,
Your C# compiler seems to be more strict 🙂 Please try initializing the variable before the try…finally block like this:
XmlTextReader reader = null;
Hi Mech,
Yours was an Excellent Article. Thank you so much.
Hey,
thanks for the tut. I tried this, but only i get it´s an exception. It means, that there is an unexpected xml-declaration. It must be the fist node of the xml – doc. I don´t know what to do.
Hi ,
Excellent article.
One note tho:
Should be
pls can i know how to cet version number of my older application and the new application so that it could be able to download the new application and install it. i dont know much about how to deal with version numbers.
Mech,
First of all, thank you so much for the tutorial. It will make my apps much more manageable.
I have one question:
The place where I store my updated files is secured with an htaccess password. Is there a was to incorporate that securability in this tutorial?
Matthew, I’m not sure if you are protecting the xml file containing the newest version information or the installer itself. Anyway, you should pass the credentials to the reader. In case of the xml file, here is the example: http://msdn.microsoft.com/en-us/library/47as68k4%28v=vs.71%29.aspx. And here is the basic authentication for the WebRequest (used to dowload the installer: http://www.ie-soft.de/blog/PermaLink,guid,11609e8d-e0fc-41f4-83a2-6e8ea46339f6.aspx). Those topic are not covered by this tutorial in order to keep it simple. Securing the installer or version info with basic auth isn’t a common thing. The downside is that you have to hardcode the credentials in your app. And when someone is using a proxy, he can intercept the request and response, so it’s not secure.
Wow just what I was looking for. I did get one build error in C#VS 2010 though.
finally
{
if (reader != null) reader.Close();
}
Returns an error that reader doesn’t exist in the current context.
To fix I just changed:
XmlTextReader reader;
to:
XmlTextReader reader = null;
How to incrementally update files? For exampe, I need to update some text files. I know there is a new version available. How do I manage only the new content on the server and update my local files?
Thanks. 🙂
First off, hey thanks Mech, really handy stuff here mate good job 😉
So this works really well… But what if someone was to use this process for more than one application using the same XML file?
Using this:
1.2.3.4444
http://some.domain/our_app_homepage/
Works great, but what if we don’t want to make a new XML file every time we make a app, we rather keep one XML file and store all app updates on it like this:
1.2.3.4444
http://some.domain/our_app_homepage/
1.2.3.4444
http://some.domain/our_app_homepage/
But doing this, it wont work with the above source as its not going into the XML files specific Name: ourfancyapp
If we use this:
1.2.3.4444
http://some.domain/our_app_homepage/
1.2.3.4444
http://some.domain/our_app_homepage/
It also doesn’t work… Anyway you can give an example so it supports more than one app?
Also, i thought in xml, the correct declaration approach is :
not “utf-8” both should technically work fine but the recommended markup is “UTF-8”?
Could you please give an example and add support of more than one app?