What if you’re implementing an application in .NET (C#) that is supposed to automatically update itself once a new version comes out? Well, you have multiple options, some of which cost a lot of money, while others are free but come with certain restrictions, like being only compatible with an ISS or solely running in user space like ClickOnce apps.
After searching for a solution for days, I stumbled upon AppUpdater, which is a free .NET component that “was written using the .NET Framework and enables you to make your application auto-updatable simply by dropping the component into your existing .NET applications and setting a few properties (ex. where to get updates from)“. And indeed, it’s as easy as it sounds. Drag-and-drop the component on your application’s main form, configure the AppStart.config file and start your application by using the provided AppStart.exe. Then put an updated version into the according folder on your server and the AppUpdater component will take care of the rest. (if you cannot follow, read the AppUpdater article first
Although step 5 of the walkthrough says that any Web-DAV enabled web server should suffice, I ran into trouble using an apache web server with the dav and dav-fs modules loaded. Apparently, you need an IIS, since it interprets DAV verbs a little different than its apache counterpart. While both the
CheckForFileUpdate() and the
UpdateFile() functions from the AppUpdater’s class “WebFileLoader.cs” work as expected, the client throws an exception in
GetDirectoryContents(). It seems that the apache dav module has some problems with the
displayname tags of the request string since it returns the following response (e.g. for the file appupdater.dll):
<D:response xmlns:lp1=\"DAV:\" xmlns:lp2=\"http://apache.org/dav/props/\" xmlns:g0=\"DAV:\">
<D:prop><lp1:getlastmodified>Sat, 12 Apr 2008 00:30:16 GMT</lp1:getlastmodified></D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
<D:status>HTTP/1.1 404 Not Found</D:status>
getlastmodified returns the right timestamp, but both
iscollection return a “404 Not Found” error. Now, I could’ve gotten into the DAV protocol, put my web server into debugging mode, TCP-dumped a couple of DAV requests and tried to build a proper request string, but then again there is actually no need to employ DAV for simple tasks like this. The simple HTTP protocol totally suffices in this situation. You just need to go a slightly different way:-) As initially implemented, the AppUpdater connects to the web server in the
GetDirectoryContents() function and browses the directory to find and copy all the contained files to the client. “Directory Browsing” is a DAV feature, so we’ll have to improvise here.
Let’s say I just released version 184.108.40.206 of my application (Former version was e.g. 220.127.116.11). According to step 5 of the article, I simply need to create a new folder named “18.104.22.168″ in my server’s root update directory and edit the UpdateVersion.xml file to point to this newly created dir. Instead of uploading all files from our release folder, we’ll zip them up and upload the resulting zip-file into the server’s “22.214.171.124″ folder. That way our client only needs to download one file (via HTTP) and isn’t dependent upon the “Directory Browsing” feature. After downloading the zip-file we’ll just unpack it into the temp directory that the regular AppUpdater would have stored the downloaded files in and let it do its magic from there on. It’s as simple as that, plus you only need to zip up and upload those files, which have changed between releases. The AppUpdater will copy all files, which it finds in the 126.96.36.199 but cannot find in the 188.8.131.52 folder to the latter folder. Unfortunately, this little hack doesn’t allow for auto-downloading of missing assemblies anymore (setting the AutoFileLoad option of the AppUpdater component to
true), but then again users can just download the installer and re-install the app, if they accidently deleted any of the files in the app’s root folder.
Now to get going and to enable the AppUpdater to work with your apache web server (without Web-DAV) you actually only need to modify one file. First download the the .NET Application Updater Component package, which includes the AppUpdater’s source code. Afterwards edit the file “WebFileLoader.cs”. Since the
GetDirectoryContents() function caused us so many headaches and we won’t need it anymore you can delete it entirely. Afterwards, replace the code of the function
CopyDirectory with the following (most of which is copied from the
int FileCount = 0;
HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(url);
Request.Credentials = CredentialCache.DefaultCredentials;
Response = (HttpWebResponse)Request.GetResponse();
catch (WebException e)
if (e.Response == null)
Debug.WriteLine("Error accessing Url " + url);
HttpWebResponse errorResponse = (HttpWebResponse)e.Response;
if (errorResponse.StatusCode == HttpStatusCode.NotModified)
Debug.WriteLine("Error accessing Url " + url);
Stream respStream = null;
string newPath = "";
respStream = Response.GetResponseStream();
newPath = filePath + Path.GetFileName((new Uri(url)).LocalPath);
DateTime d = System.Convert.ToDateTime(Response.GetResponseHeader("Last-Modified"));
Debug.WriteLine("APPMANAGER: Error writing to: " + filePath);
if (respStream != null)
if (Response != null)
// unzip files
Shell32.ShellClass sc = new Shell32.ShellClass();
Shell32.Folder srcFlder = sc.NameSpace(newPath);
Shell32.Folder destFlder = sc.NameSpace(filePath);
Shell32.FolderItems items = srcFlder.Items();
(Sorry for the messy code. I couldn’t get WordPress to indent it properly:-( In the last 7 lines we employ the Shell32 COM library to extract our zip file. To make this work, you need to add the correct reference. In your project, click on “Add Reference”, then on the “COM” tab in the opening dialog and then search for “Microsoft Shell Controls And Automation”. That’s the lib you want to add. Finally compile it and add the resulting .dlls to your project, although I would generally recommend adding the entire AppUpdater project to your solution and referencing it.
Before we can test our new application, we need to create a new directory on our server (let’s assume the example from above and name it 184.108.40.206). Then go through the article’s steps 1-4 and do everything as told, build your application, zip up the new files (to e.g. app.zip) and upload the zip file to the 220.127.116.11 directory on the server. Afterwards, edit the UpdateVersion.xml file as follows:
It’s very important to mention here that with the modifications you made, you now need to give the FULL PATH to your zip file within the ApplicationUrl tags, not just the directory as before.
Last but not least, fire up your client and let it automatically update itself!
That’s it! Hope it works for you.