Winform file download WebClient

Recently, a download gadget used by the company was upgraded, which mainly improved the following points:

1. In the local area network of some branches, the external network cannot be connected

2. After the file on the server is updated, the downloaded file is still the file before the update

3. No download progress notification

4. Can't stop download

 

Share some thoughts with you below.

In view of various complex network environments, the author decided to use different programming interfaces to download and try to increase the usability of the program.

Only the method of using WebClient is introduced here. The blog post mainly introduces ideas and key codes, and the complete demo is attached at the end of the text.

 

Access the web using a proxy

Many company employees access the Internet through proxies set up by the company. Internet access through the proxy is mainly to facilitate the company to carry out various control, of course, it can also achieve some special functions... But this will bring some problems to our program accessing the network.

In fact, the API in WebClient is already very intelligent. For example, the HttpWebRequest object we created has a Proxy property. That is, WebHttpRequest will use the found proxy by default. This is great and handles a lot of situations. However, if the default proxy needs to verify the identity of the domain user, then using WebHttpRequest to access the network may fail. At this point, look at the Proxy.Credentials property and find that it is null.

The default Credentials of the system can be obtained from the WebClient API, but it is not clear why the Proxy.Credentials property is not set to this value by default. We can set it up ourselves.

 

request.Proxy.Credentials = CredentialCache.DefaultCredentials;

 

But the actual network environment may be more complex, requiring the user to specify the proxy for networking, and at the same time specify the Credentials required for networking. It is written as follows:

 

myProxy = new WebProxy(“proxyAddress”); 

myProxy.Credentials = new NetworkCredential(ProxyUserName, ProxyUserPasswd, DomainName);

 

overcome cache

Caching is no longer everywhere. There will be caches in the CDN on the server side, and there will also be caches in the proxy layer on the client side. So the problem that often arises is: the files on the server are obviously updated, but some clients will still download the old files. Let's deal with client-side caching first.

The CachePolicy.Level property of HttpWebRequest is to set the cache policy, but its default value is BypassCache. We can change it to Reload:

request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.Reload);

 

Next is the server-side caching problem.

Now everyone seems to be using CDN, but in use, it is often found that there is a problem with the cache update on the CDN side. There is no good solution to check on the Internet, but there is a good workaround, which is to add a random string as a parameter to the request.

Random rdm = new Random();

string s = rdm.Next().ToString();

myUrl += "?" + s;

 

It should be noted that with regard to caching, you must use a strategy that matches your current use case, and you can’t do one size fits all.

 

A friendlier download process

Use scroll bar to show download progress, show real-time download speed, allow user to cancel download

 

The following is the core code for downloading. We divide it into calculating the download percentage and calculating the current download speed.

// Get the length of the downloaded file

double contentLength = DownloadManager.GetContentLength(myHttpWebClient);

byte[] buffer = new byte[BufferSize];

long downloadedLength = 0;

long currentTimeSpanDataLength = 0;         

int currentDataLength;

while ((currentDataLength = stream.Read(buffer, 0, BufferSize)) > 0 && !this._cancelDownload)

{

    fileStream.Write(buffer, 0, currentDataLength);

    downloadedLength += (long)currentDataLength;

    currentTimeSpanDataLength += (long)currentDataLength;

    int intDownloadSpeed = 0;

    if (this._downloadStopWatch.ElapsedMilliseconds > 800)

    {

        double num5 = (double)currentTimeSpanDataLength / 1024.0;

        double num6 = (double)this._downloadStopWatch.ElapsedMilliseconds / 1000.0;

        double doubleDownloadSpeed = num5 / num6;

        intDownloadSpeed = (int)Math.Round(doubleDownloadSpeed, 0);

        this._downloadStopWatch.Reset();

        this._downloadStopWatch.Start();

        currentTimeSpanDataLength = 0;

    }

 

    double doubleDownloadPersent = 0.0;

    if (contentLength > 0.0)

    {

        doubleDownloadPersent = (double)downloadedLength / contentLength;

}

}

 

在下载的过程中计算下载百分比

首先需要从http请求中获得要下载文件的长度,细节请参考本文所配demo.

double contentLength = DownloadManager.GetContentLength(myHttpWebClient);

 

每从文件流中读取一次数据,我们知道读了多少个字节(currentDataLength),累计下来就是当前已经下载了的文件长度。

downloadedLength += (long)currentDataLength;

然后做个除法就行了:

doubleDownloadPersent = (double)downloadedLength / contentLength;

 

计算实时的下载速度

对于当前的下载速度,我们计算过去的一段时间内下载下来的字节数。时间段可以使用StopWatch来获得,我选择的时间段要求大于800毫秒。

if (this._downloadStopWatch.ElapsedMilliseconds > 800)

{

    /***********************************/

    // 计算上一个时间段内的下载速度

    double num5 = (double)currentTimeSpanDataLength / 1024.0;

    double num6 = (double)this._downloadStopWatch.ElapsedMilliseconds / 1000.0;

    double doubleDownloadSpeed = num5 / num6;

    /***********************************/

intDownloadSpeed = (int)Math.Round(doubleDownloadSpeed, 0);

// 本次网速计算完成后重置时间计时器和数据计数器,开始下次的计算

    this._downloadStopWatch.Reset();

    this._downloadStopWatch.Start();

    currentTimeSpanDataLength = 0;

}

事实上每次计算下载速度的时间段长度是不顾定的,但这并不影响计算结果,我只要保证距离上次计算超过了800毫秒就行了。

 

允许用户取消下载

对于一个执行时间比较长的任务来说,不允许用户取消它是被深恶痛绝的!尤其是网速不太好的时候。所以我们需要给用户一个选择:可以痛快(而不是痛苦)的结束当前的旅程。

而这一切对我们来说又是那么的简单!

 

while ((currentDataLength = stream.Read(buffer, 0, BufferSize)) > 0 && !this._cancelDownload){}

当从数据流中读取数据时,我们检查用户是不是按下了“取消”按钮,就是这里的 this._cancelDownload 变量。如果它是 true就结束当前的下载。     

 

至此,把用户抱怨最多的几个点都搞定了。其实也没有增加多少代码,并且每个知识点看起来都是那么的细微。但很明显的提高了用户的使用体验。这也给我们带来了一些启发,完成主要功能可能只是工作中的一部分,另外的一些工作可能并不是那么明显,需要我们不断的体会,发觉…

 

Demo 下载

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326191319&siteId=291194637