Introduction
This tip provides a cheap method to download file via a URL.
Background
Most programs like to provide the auto update function so that end users can get the best user experience. In simple words, auto update can be finished only in two steps:
- Step 1: Visit the program server to check whether there is a new version available.
- Step 2: Ask user whether to update and follow the user's select.
This tip will mainly describe the workflow around those two steps above. This is my work experience. If there is any problem, you can leave a message.
Using the Code
1. Get the newest version information on the server.
In most cases, a program has a version number such as 1.20.11. It's a series of num divided by '.'. When checking whether the server's newest version is newer than the user's current version, the version number is a convenient method. In general, we consider version 1.20.22 is newer than version 1.20.11.
In my program, I use INI file to record the version information. In the program's install directory, there is a file named Update.ini. This file's content is simple:
[Update]
CurrentVersion = 1.10.12
IniPath = ftp://192.168.29.19//Version.ini
There are two data lines in it. The "CurrentVersion
" represents the program version and the "IniPath
" represents the server INI file path. We can download the Version.ini and read its version number to make a comparison in order to check whether to inform the user.
The Version.ini on server is:
[Update]
CurrentVersion = 1.11.00
ExePath = ............
The first data line represents the server's newest version num and the second list represents the download path.
How to download the file will be represent later, I will show how to compare two Version numbers:
public static int compare(String version1, String version2)
{
if (version1 == null || version1.Length == 0 || version2 == null || version2.Length == 0 )
{
return -1;
}
int index1 = 0;
int index2 = 0;
while(index1 < version1.Length && index2 < version2.Length)
{
int[] number1 = getValue(version1, index1);
int[] number2 = getValue(version2, index2);
if (number1[0] < number2[0]) return -1;
else if (number1[0] > number2[0]) return 1;
else
{
index1 = number1[1] + 1;
index2 = number2[1] + 1;
}
}
if(index1 == version1.Length && index2 == version2.Length) return 0;
if(index1 < version1.Length)
return 1;
else
return -1;
}
public static int[] getValue(string version, int index)
{
int[] value_index = new int[2];
StringBuilder sb = new StringBuilder();
while(index < version.Length && version.ElementAt(index) != '.')
{
sb.Append(version.ElementAt(index));
index++;
}
value_index[0] = Convert.ToInt32(sb.ToString(),10);
value_index[1] = index;
return value_index;
}
The code will divide the version string by the character ‘ .’. Compare each number you get from the string
.
2. Download the file from the server.
As the title mentioned, this tip will introduce download with the 'Interface
' webclient. It provides plenty of methods for downloads.
The webclient has synchronous and asynchronous method. The synchronous method will block the process. It is usually used for downloading small files which won't take so much time to download. In our case, we use synchronous method to download the INI file from the server. The code is as follows:
WebClient web = new WebClient();
try
{
string UserName = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_NAME");
string PassWord = AutoUpdate.Form1.GetStringFromFile("UpdateInfo", "ID_USER_PASSWORD");
web.Credentials = new NetworkCredential(UserName, PassWord);
web.DownloadFile(new Uri(ServerIniPath.ToString()), ItemSavePath);
}
catch (System.Exception ex)
{
throw ex;
}
We can get the newest program download path from the INI file, if we need to download it, we can use the asynchronous method.
try
{
web.DownloadFileAsync(new Uri(DownLoadAddress), ItemSavePath);
web.DownloadProgressChanged += client_DownloadProgressChanged;
web.DownloadFileCompleted += client_DownloadFileCompleted;
}
catch (System.Exception ex)
{
throw ex;
}
In the code, we can see after calling the download method, we also add two event handlers for it. These two handlers help us to know the download detail information, such as the percentage downloaded, how many bytes are downloaded and so on. The detail handler code is as follows:
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
Action<AsyncCompletedEventArgs> onCompleted = progressCompleted;
onCompleted.Invoke(e);
}
void client_DownloadFileProgresschanged(object sender, AsyncCompletedEventArgs e)
{
Action<DownloadProgressChangedEventArgs; onCompleted = progressChanging;
onCompleted.Invoke(e);
}
The method progressCompleted
and progressChanging
can be written as your demand.
3. Download exceptions.
This exception is not the one caught by try
and catch
. This is the real exception: the Internet is unavailable, user cancels the update, the server is unavailable. Because we use the asynchronous method, there will be plenty of concurrent problems. I will display how I handle some of them.
The Internet is unavailable.
This problem may happen at any time, so I have to start another thread to check Internet state by time. Once I find that the Internet is down, I will call the download process to inform user.
How to check the Internet is available is easy, we can use the method provided by "wininet.dll".
[DllImport("wininet.dll")]
public static extern bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);
The user cancels the download:
The webclient considers this case. It provides the cancel
method to stop download and the dispose
method to release the resource the download process used.
Done.
History
- 17th September, 2014: Initial version
- 18th September, 2014: Uploaded sample code