HTTPDOWNLOADER for updater application block for .Net2.0
updater application block for .Net2.0已经发布了,但是我使用了一下,因为是使用后台更新的缘故,所以速度特别慢。30M的东西差不多要花费30分钟,简直无法忍受,弄了个httpdownloader,在这里共享给大家。
你需要Enterprise Libary 2006

HttpDownloader
1
using System;
2
using System.IO;
3
using System.Net;
4
using System.Threading;
5
using System.Security.Permissions;
6
using Microsoft.ApplicationBlocks.Updater;
7
using Microsoft.ApplicationBlocks.Updater.Configuration;
8
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
9
namespace x.HttpDownloader
10

{
11
/**//// <summary>
12
/// Implements a HTTP downloader for the updater application block V2.0.
13
/// </summary>
14
/// <remarks>
15
/// The <c>HttpDownloader</c> class can be used to download application updates via HTTP. It supports synchronous and asynchronous
16
/// operation as well as progress reporting. In addition, the progress reporting is not at the file level, it is at the byte level.
17
/// </remarks>
18
[ConfigurationElementType(typeof(HttpDownloaderProviderData))]
19
public sealed class HttpDownloader : IDownloader
20
{
21
/**//// <summary>
22
/// The thread to perform the download.
23
/// </summary>
24
private Thread _downloaderThread;
25
26
/**//// <summary>
27
/// Contains configuration settings for the HTTP downloader.
28
/// </summary>
29
//private HttpDownloaderProviderData _configuration;
30
31
/**//// <summary>
32
/// The configuration name for this downloader.
33
/// </summary>
34
private const string CONFIGURATION_NAME = "downloaders";
35
36
/**//// <summary>
37
/// The download provider name.
38
/// </summary>
39
private const string DOWNLOAD_PROVIDER_NAME = "HTTPDownloader";
40
41
/**//// <summary>
42
/// A synchronisation object.
43
/// </summary>
44
private readonly object LOCK = new object();
45
46
/**//// <summary>
47
/// Gets the configuration name for the HTTP downloader.
48
/// </summary>
49
public string ConfigurationName
50
{
51
get
52
{
53
return CONFIGURATION_NAME;
54
}
55
set
56
{
57
//nothing to do
58
}
59
}
60
61
/**//// <summary>
62
/// Initialises the HTTP downloader.
63
/// </summary>
64
//public void Initialize(ConfigurationView configurationView)
65
//{
66
// UpdaterConfigurationView updaterConfigurationView = (UpdaterConfigurationView) configurationView;
67
// _configuration = (HttpDownloaderProviderData) updaterConfigurationView.GetDownloadProviderData(DOWNLOAD_PROVIDER_NAME);
68
//}
69
70
/**//// <summary>
71
/// Downloads the specified task synchronously via HTTP. If <paramref name="maxWaitTime"/> is surpassed prior to the download
72
/// completing, a download error is raised.
73
/// </summary>
74
[FileIOPermission(SecurityAction.Demand)]
75
public void Download(UpdaterTask task, TimeSpan maxWaitTime)
76
{
77
try
78
{
79
OnDownloadStarted(new TaskEventArgs(task));
80
//this object is used to perform the downloading on a separate thread
81
AsyncDownloader downloader = new AsyncDownloader(task, new OnDownloadProgressEventHandler(OnDownloadProgress), new OnDownloadTotalSizeCalculationStartedEventHandler(OnDownloadTotalSizeCalculationStarted), new OnDownloadTotalSizeCalculationProgressEventHandler(OnDownloadTotalSizeCalculationProgress), new OnDownloadTotalSizeCalculationCompletedEventHandler(OnDownloadTotalSizeCalculationCompleted), new OnDownloadCompletedEventHandler(OnDownloadCompleted));
82
CreateDownloaderThread(downloader);
83
_downloaderThread.Start();
84
//DateTime endTime = DateTime.Now + maxWaitTime;
85
double endTime = Environment.TickCount + maxWaitTime.TotalMilliseconds;
86
while ((endTime > Environment.TickCount) && !downloader.IsComplete)
87
{
88
Thread.Sleep(100);
89
}
90
91
if (!downloader.IsComplete)
92
{
93
//abort the thread if it didn't complete
94
_downloaderThread.Abort();
95
throw new ApplicationUpdaterException("Download surpassed time out of " + maxWaitTime);
96
}
97
else if (downloader.Exception != null)
98
{
99
//raise the error event if the downloader thread erred out
100
OnDownloadError(new DownloadTaskErrorEventArgs(task, downloader.Exception));
101
}
102
}
103
catch (Exception e)
104
{
105
OnDownloadError(new DownloadTaskErrorEventArgs(task, e));
106
}
107
}
108
109
/**//// <summary>
110
/// Downloads the specified task asynchronously via HTTP.
111
/// </summary>
112
[FileIOPermission(SecurityAction.Demand)]
113
public void BeginDownload(UpdaterTask task)
114
{
115
try
116
{
117
OnDownloadStarted(new TaskEventArgs(task));
118
//this object is used to perform the downloading on a separate thread
119
AsyncDownloader downloader = new AsyncDownloader(task, new OnDownloadProgressEventHandler(OnDownloadProgress), new OnDownloadTotalSizeCalculationStartedEventHandler(OnDownloadTotalSizeCalculationStarted), new OnDownloadTotalSizeCalculationProgressEventHandler(OnDownloadTotalSizeCalculationProgress), new OnDownloadTotalSizeCalculationCompletedEventHandler(OnDownloadTotalSizeCalculationCompleted), new OnDownloadCompletedEventHandler(OnDownloadCompleted));
120
CreateDownloaderThread(downloader);
121
_downloaderThread.Start();
122
}
123
catch (Exception e)
124
{
125
OnDownloadError(new DownloadTaskErrorEventArgs(task, e));
126
}
127
}
128
129
/**//// <summary>
130
/// Cancels an asynchronous HTTP download operation.
131
/// </summary>
132
public bool CancelDownload(UpdaterTask task)
133
{
134
_downloaderThread.Abort();
135
return true;
136
}
137
138
/**//// <summary>
139
/// Creates the downloader thread.
140
/// </summary>
141
private void CreateDownloaderThread(AsyncDownloader downloader)
142
{
143
_downloaderThread = new Thread(new ThreadStart(downloader.Download));
144
_downloaderThread.Name = "Downloader";
145
_downloaderThread.IsBackground = true;
146
}
147
148
/**//// <summary>
149
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationStarted"/> event.
150
/// </summary>
151
public delegate void DownloadTotalSizeCalculationStartedEventHandler(object sender, TaskEventArgs e);
152
153
/**//// <summary>
154
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationCompleted"/> event.
155
/// </summary>
156
public delegate void DownloadTotalSizeCalculationProgressEventHandler(object sender, DownloadTotalSizeCalculationProgressEventArgs e);
157
158
/**//// <summary>
159
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationCompleted"/> event.
160
/// </summary>
161
public delegate void DownloadTotalSizeCalculationCompletedEventHandler(object sender, TaskEventArgs e);
162
163
/**//// <summary>
164
/// Fired when the HTTP downloader begins calculating file sizes for the files to be downloaded.
165
/// </summary>
166
/// <remarks>
167
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).
168
/// </remarks>
169
public static event DownloadTotalSizeCalculationStartedEventHandler DownloadTotalSizeCalculationStarted;
170
171
/**//// <summary>
172
/// Fired when the HTTP downloader has progress information for file size calculations.
173
/// </summary>
174
/// <remarks>
175
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).
176
/// </remarks>
177
public static event DownloadTotalSizeCalculationProgressEventHandler DownloadTotalSizeCalculationProgress;
178
179
/**//// <summary>
180
/// Fires when the HTTP downloader has finished calculating file sizes.
181
/// </summary>
182
/// <remarks>
183
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).
184
/// </remarks>
185
public static event DownloadTotalSizeCalculationCompletedEventHandler DownloadTotalSizeCalculationCompleted;
186
187
/**//// <summary>
188
/// Fired when the HTTP downloader begins downloading files.
189
/// </summary>
190
public event DownloadTaskStartedEventHandler DownloadStarted;
191
192
/**//// <summary>
193
/// Fired whenever the HTTP downloader has progress information to report about the current downloads.
194
/// </summary>
195
public event DownloadTaskProgressEventHandler DownloadProgress;
196
197
/**//// <summary>
198
/// Fired when the HTTP downloader has finished downloading.
199
/// </summary>
200
public event DownloadTaskCompletedEventHandler DownloadCompleted;
201
202
/**//// <summary>
203
/// Fired when an error occurs in the HTTP downloader whilst attempting to download updates.
204
/// </summary>
205
public event DownloadTaskErrorEventHandler DownloadError;
206
207
/**//// <summary>
208
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationStarted"/> method.
209
/// </summary>
210
internal delegate void OnDownloadTotalSizeCalculationStartedEventHandler(TaskEventArgs e);
211
212
/**//// <summary>
213
/// Fires the <see cref="DownloadTotalSizeCalculationStarted"/> method.
214
/// </summary>
215
private void OnDownloadTotalSizeCalculationStarted(TaskEventArgs e)
216
{
217
if (DownloadTotalSizeCalculationStarted != null)
218
{
219
DownloadTotalSizeCalculationStarted(this, e);
220
}
221
}
222
223
/**//// <summary>
224
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationProgress"/> method.
225
/// </summary>
226
internal delegate void OnDownloadTotalSizeCalculationProgressEventHandler(DownloadTotalSizeCalculationProgressEventArgs e);
227
228
/**//// <summary>
229
/// Fires the <see cref="DownloadTotalSizeCalculationProgress"/> method.
230
/// </summary>
231
private void OnDownloadTotalSizeCalculationProgress(DownloadTotalSizeCalculationProgressEventArgs e)
232
{
233
if (DownloadTotalSizeCalculationProgress != null)
234
{
235
DownloadTotalSizeCalculationProgress(this, e);
236
}
237
}
238
239
/**//// <summary>
240
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationCompleted"/> method.
241
/// </summary>
242
internal delegate void OnDownloadTotalSizeCalculationCompletedEventHandler(TaskEventArgs e);
243
244
/**//// <summary>
245
/// Fires the <see cref="DownloadTotalSizeCalculationCompleted"/> method.
246
/// </summary>
247
private void OnDownloadTotalSizeCalculationCompleted(TaskEventArgs e)
248
{
249
if (DownloadTotalSizeCalculationCompleted != null)
250
{
251
DownloadTotalSizeCalculationCompleted(this, e);
252
}
253
}
254
255
/**//// <summary>
256
/// Fires the <see cref="DownloadStarted"/> method.
257
/// </summary>
258
private void OnDownloadStarted(TaskEventArgs e)
259
{
260
if (DownloadStarted != null)
261
{
262
DownloadStarted(this, e);
263
}
264
}
265
266
/**//// <summary>
267
/// Used to invoke the <see cref="OnDownloadProgress"/> method.
268
/// </summary>
269
internal delegate void OnDownloadProgressEventHandler(DownloadTaskProgressEventArgs e);
270
271
/**//// <summary>
272
/// Fires the <see cref="DownloadProgress"/> method.
273
/// </summary>
274
private void OnDownloadProgress(DownloadTaskProgressEventArgs e)
275
{
276
lock (LOCK)
277
{
278
if (DownloadProgress != null)
279
{
280
DownloadProgress(this, e);
281
}
282
}
283
}
284
285
/**//// <summary>
286
/// Used to invoke the <see cref="OnDownloadCompleted"/> method.
287
/// </summary>
288
internal delegate void OnDownloadCompletedEventHandler(TaskEventArgs e);
289
290
/**//// <summary>
291
/// Fires the <see cref="DownloadCompleted"/> method.
292
/// </summary>
293
private void OnDownloadCompleted(TaskEventArgs e)
294
{
295
if (DownloadCompleted != null)
296
{
297
DownloadCompleted(this, e);
298
}
299
}
300
301
/**//// <summary>
302
/// Fires the <see cref="DownloadError"/> method.
303
/// </summary>
304
private void OnDownloadError(DownloadTaskErrorEventArgs e)
305
{
306
if (DownloadError != null)
307
{
308
DownloadError(this, e);
309
}
310
}
311
312
/**//// <summary>
313
/// Performs the actual downloading of updated files.
314
/// </summary>
315
private class AsyncDownloader
316
{
317
/**//// <summary>
318
/// The task whose files will be downloaded.
319
/// </summary>
320
private UpdaterTask _task;
321
322
/**//// <summary>
323
/// Contains configuration settings.
324
/// </summary>
325
//private HttpDownloaderProviderData _configuration;
326
327
/**//// <summary>
328
/// Stores the last time a download progress report was issued.
329
/// </summary>
330
private DateTime _lastProgressReport;
331
332
/**//// <summary>
333
/// The delegate to invoke to report download progress.
334
/// </summary>
335
private OnDownloadProgressEventHandler _progressDelegate;
336
337
/**//// <summary>
338
/// The delegate to invoke to report that file size calculations have started.
339
/// </summary>
340
private OnDownloadTotalSizeCalculationStartedEventHandler _totalSizeStarted;
341
342
/**//// <summary>
343
/// The delegate to invoke to report file size calculations progress.
344
/// </summary>
345
private OnDownloadTotalSizeCalculationProgressEventHandler _totalSizeProgress;
346
347
/**//// <summary>
348
/// The delegate to invoke to report that file size calculations have completed.
349
/// </summary>
350
private OnDownloadTotalSizeCalculationCompletedEventHandler _totalSizeCompleted;
351
352
/**//// <summary>
353
/// The delegate to invoke to report that the download has completed.
354
/// </summary>
355
private OnDownloadCompletedEventHandler _downloadCompleted;
356
357
/**//// <summary>
358
/// The buffer used whilst downloading data.
359
/// </summary>
360
private byte[] _buffer;
361
362
/**//// <summary>
363
/// Set to <c>true</c> if the download completes successfully.
364
/// </summary>
365
private bool _isComplete;
366
367
/**//// <summary>
368
/// Any exception that occurred during the download.
369
/// </summary>
370
private Exception _exception;
371
372
/**//// <summary>
373
/// Synchronisation object.
374
/// </summary>
375
private readonly object LOCK;
376
377
/**//// <summary>
378
/// Gets or sets a value indicating whether the download completed successfully.
379
/// </summary>
380
internal bool IsComplete
381
{
382
get
383
{
384
lock (LOCK)
385
{
386
return _isComplete;
387
}
388
}
389
set
390
{
391
lock (LOCK)
392
{
393
_isComplete = value;
394
}
395
}
396
}
397
398
/**//// <summary>
399
/// Gets or sets an exception that occurred during the download process.
400
/// </summary>
401
internal Exception Exception
402
{
403
get
404
{
405
lock (LOCK)
406
{
407
return _exception;
408
}
409
}
410
set
411
{
412
lock (LOCK)
413
{
414
_exception = value;
415
}
416
}
417
}
418
419
/**//// <summary>
420
/// Constructs an <c>AsyncDownloader</c> instance.
421
/// </summary>
422
internal AsyncDownloader(UpdaterTask task, OnDownloadProgressEventHandler progressDelegate, OnDownloadTotalSizeCalculationStartedEventHandler totalSizeStarted, OnDownloadTotalSizeCalculationProgressEventHandler totalSizeProgress, OnDownloadTotalSizeCalculationCompletedEventHandler totalSizeCompleted, OnDownloadCompletedEventHandler downloadCompleted)
423
{
424
LOCK = new object();
425
_task = task;
426
//_configuration = configuration;
427
_progressDelegate = progressDelegate;
428
_totalSizeStarted = totalSizeStarted;
429
_totalSizeProgress = totalSizeProgress;
430
_totalSizeCompleted = totalSizeCompleted;
431
_downloadCompleted = downloadCompleted;
432
_buffer = new byte[1024];
433
_lastProgressReport = DateTime.MinValue;
434
}
435
436
/**//// <summary>
437
/// Performs the download operation.
438
/// </summary>
439
internal void Download()
440
{
441
long totalBytes = 0;
442
long transferredBytes = 0;
443
WebProxy webProxy = WebProxy.GetDefaultProxy();
444
445
if (webProxy != null)
446
{
447
//not sure why this isn't default behaviour but it isn't. This ensures the downloader works when used from behind a proxy that requires authentication (assuming
448
//authentication information is set up in IE)
449
webProxy.Credentials = CredentialCache.DefaultCredentials;
450
}
451
452
try
453
{
454
_totalSizeStarted(new TaskEventArgs(_task));
455
456
//first determine the total content length
457
for (int i = 0; i < _task.Manifest.Files.Count; ++i)
458
{
459
FileManifest file = _task.Manifest.Files[i];
460
string uri = GetUri(file);
461
WebRequest webRequest = WebRequest.Create(uri);
462
webRequest.Proxy = webProxy;
463
webRequest.Method = "GET";
464
WebResponse webResponse = webRequest.GetResponse();
465
totalBytes += webResponse.ContentLength;
466
webResponse.Close();
467
_totalSizeProgress(new DownloadTotalSizeCalculationProgressEventArgs(_task.Manifest.Files.Count, i + 1));
468
}
469
470
_totalSizeCompleted(new TaskEventArgs(_task));
471
472
//now download each file
473
for (int i = 0; i < _task.Manifest.Files.Count; ++i)
474
{
475
FileManifest file = _task.Manifest.Files[i];
476
string uri = GetUri(file);
477
WebRequest webRequest = WebRequest.Create(uri);
478
webRequest.Proxy = webProxy;
479
WebResponse webResponse = webRequest.GetResponse();
480
string outFile = Path.Combine(_task.DownloadFilesBase, file.Source);
481
int read = 0;
482
483
//make sure the destination directory exists
484
if (!Directory.Exists(Path.GetDirectoryName(outFile)))
485
{
486
Directory.CreateDirectory(Path.GetDirectoryName(outFile));
487
}
488
489
using (Stream responseStream = webResponse.GetResponseStream())
490
using (Stream fileStream = new FileStream(outFile, FileMode.Create, FileAccess.Write))
491
{
492
while ((read = responseStream.Read(_buffer, 0, _buffer.Length)) != 0)
493
{
494
transferredBytes += read;
495
fileStream.Write(_buffer, 0, read);
496
TimeSpan timeSinceLastProgressReport = DateTime.Now - _lastProgressReport;
497
498
//if ((_configuration.DownloadProgressMaximumFrequency == 0) || (timeSinceLastProgressReport.TotalMilliseconds > _configuration.DownloadProgressMaximumFrequency))
499
//{
500
// _lastProgressReport = DateTime.Now;
501
// _progressDelegate(new DownloadTaskProgressEventArgs(totalBytes, transferredBytes, _task.Manifest.Files.Count, i, _task));
502
//}
503
}
504
505
//final progress report
506
_progressDelegate(new DownloadTaskProgressEventArgs(totalBytes, transferredBytes, _task.Manifest.Files.Count, i, _task));
507
}
508
509
webResponse.Close();
510
}
511
}
512
catch (Exception e)
513
{
514
if (!(e is ThreadAbortException))
515
{
516
Exception = e;
517
}
518
}
519
520
//fire the complete event if no error occurred
521
if (Exception == null)
522
{
523
_downloadCompleted(new TaskEventArgs(_task));
524
}
525
526
//if the thread is aborted, this won't execute because the ThreadAbortException will continue propogating
527
IsComplete = true;
528
}
529
530
/**//// <summary>
531
/// Obtains a URI for the specified file.
532
/// </summary>
533
private string GetUri(FileManifest file)
534
{
535
return string.Format("{0}{1}", _task.Manifest.Files.Base, file.Source);
536
}
537
}
538
}
539
}
540

HttpDownloaderProviderData
1
using System;
2
using System.Xml.Serialization;
3
using Microsoft.ApplicationBlocks.Updater.Configuration;
4
using Microsoft.ApplicationBlocks.Updater.Downloaders;
5
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder;
6
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
7
using System.Configuration;
8
using Microsoft.ApplicationBlocks.Updater;
9
namespace x.HttpDownloader
10

{
11
/**//// <summary>
12
/// Contains configuration for the <see cref="HttpDownloader"/>.
13
/// </summary>
14
//[XmlRoot("downloader", Namespace = ApplicationUpdaterSettings.ConfigurationNamespace)]
15
[Assembler(typeof(HttpDownloaderAssembler))]
16
public class HttpDownloaderProviderData : DownloaderProviderData
17
{
18
/**//// <summary>
19
/// See <see cref="DownloadBufferSize"/>.
20
/// </summary>
21
private int _downloadBufferSize;
22
23
/**//// <summary>
24
/// See <see cref="DownloadProgressMaximumFrequency"/>
25
/// </summary>
26
private int _downloadProgressMaximumProgress;
27
28
/**//// <summary>
29
/// The minimum value that can be assigned to <see cref="DownloadBufferSize"/>.
30
/// </summary>
31
private const int DOWNLOAD_BUFFER_SIZE_MIN = 256;
32
33
/**//// <summary>
34
/// The maximum value that can be assigned to <see cref="DownloadBufferSize"/>.
35
/// </summary>
36
private const int DOWNLOAD_BUFFER_SIZE_MAX = 10240;
37
38
/**//// <summary>
39
/// The minimum value that can be assigned to <see cref="DownloadProgressMaximumFrequency"/>.
40
/// </summary>
41
private const int DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN = 0;
42
43
/**//// <summary>
44
/// The maximum value that can be assigned to <see cref="DownloadProgressMaximumFrequency"/>.
45
/// </summary>
46
private const int DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX = 5000;
47
48
/**//// <summary>
49
/// Gets or sets the buffer size, in bytes, used whilst downloading files.
50
/// </summary>
51
/// <remarks>
52
/// The HTTP downloader reports progress each time it fills the download buffer. Therefore, larger buffer sizes will result
53
/// in fewer progress reports.
54
/// </remarks>
55
//[ConfigurationProperty(_downloadBufferSize, IsRequired = false)]
56
public int DownloadBufferSize
57
{
58
get
59
{
60
return _downloadBufferSize;
61
}
62
set
63
{
64
if ((value < DOWNLOAD_BUFFER_SIZE_MIN) || (value > DOWNLOAD_BUFFER_SIZE_MAX))
65
{
66
throw new ArgumentException(string.Format("DownloadBufferSize must be between {0} and {1}", DOWNLOAD_BUFFER_SIZE_MIN, DOWNLOAD_BUFFER_SIZE_MAX));
67
}
68
69
_downloadBufferSize = value;
70
}
71
}
72
73
/**//// <summary>
74
/// Gets or sets the maximum frequency, in milliseconds, that progress will be reported by the HTTP downloader.
75
/// </summary>
76
/// <remarks>
77
/// <para>
78
/// This property allows you to limit the number of progress reports issued by the HTTP downloader. The downloader will ensure that
79
/// the amount of time specified by this property has elapsed prior to issuing another progress report. If enough time has not elapsed
80
/// then the downloader will not issue a progress report at that time.
81
/// </para>
82
/// <para>
83
/// Setting this property to <c>0</c> ensures that the downloader always reports progress, regardless of the amount of time that has
84
/// elapsed since the last progress report.
85
/// </para>
86
/// </remarks>
87
//[XmlElement("downloadProgressMaximumFrequency")]
88
public int DownloadProgressMaximumFrequency
89
{
90
get
91
{
92
return _downloadProgressMaximumProgress;
93
}
94
set
95
{
96
if ((value < DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN) || (value > DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX))
97
{
98
throw new ArgumentException(string.Format("DownloadProgressMaximumFrequency must be between {0} and {1}", DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN, DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX));
99
}
100
101
_downloadProgressMaximumProgress = value;
102
}
103
}
104
105
/**//// <summary>
106
/// Default constructor.
107
/// </summary>
108
public HttpDownloaderProviderData()
109
{
110
DownloadBufferSize = 1024;
111
}
112
}
113
114
public class HttpDownloaderAssembler : IAssembler<Microsoft.ApplicationBlocks.Updater.IDownloader, DownloaderProviderData>
115
{
116
public IDownloader Assemble(Microsoft.Practices.ObjectBuilder.IBuilderContext context, DownloaderProviderData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
117
{
118
HttpDownloaderProviderData bitsData = (HttpDownloaderProviderData)objectConfiguration;
119
return new HttpDownloader();
120
}
121
}
122
}
123
你需要Enterprise Libary 2006
1
using System;2
using System.IO;3
using System.Net;4
using System.Threading;5
using System.Security.Permissions;6
using Microsoft.ApplicationBlocks.Updater;7
using Microsoft.ApplicationBlocks.Updater.Configuration;8
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;9
namespace x.HttpDownloader10


{11

/**//// <summary>12
/// Implements a HTTP downloader for the updater application block V2.0.13
/// </summary>14
/// <remarks>15
/// The <c>HttpDownloader</c> class can be used to download application updates via HTTP. It supports synchronous and asynchronous16
/// operation as well as progress reporting. In addition, the progress reporting is not at the file level, it is at the byte level.17
/// </remarks>18
[ConfigurationElementType(typeof(HttpDownloaderProviderData))]19
public sealed class HttpDownloader : IDownloader20

{21

/**//// <summary>22
/// The thread to perform the download.23
/// </summary>24
private Thread _downloaderThread;25

26

/**//// <summary>27
/// Contains configuration settings for the HTTP downloader.28
/// </summary>29
//private HttpDownloaderProviderData _configuration;30

31

/**//// <summary>32
/// The configuration name for this downloader.33
/// </summary>34
private const string CONFIGURATION_NAME = "downloaders";35

36

/**//// <summary>37
/// The download provider name.38
/// </summary>39
private const string DOWNLOAD_PROVIDER_NAME = "HTTPDownloader";40

41

/**//// <summary>42
/// A synchronisation object.43
/// </summary>44
private readonly object LOCK = new object();45

46

/**//// <summary>47
/// Gets the configuration name for the HTTP downloader.48
/// </summary>49
public string ConfigurationName50

{51
get52

{53
return CONFIGURATION_NAME;54
}55
set56

{57
//nothing to do58
}59
}60
61

/**//// <summary>62
/// Initialises the HTTP downloader.63
/// </summary>64
//public void Initialize(ConfigurationView configurationView)65
//{66
// UpdaterConfigurationView updaterConfigurationView = (UpdaterConfigurationView) configurationView;67
// _configuration = (HttpDownloaderProviderData) updaterConfigurationView.GetDownloadProviderData(DOWNLOAD_PROVIDER_NAME);68
//}69

70

/**//// <summary>71
/// Downloads the specified task synchronously via HTTP. If <paramref name="maxWaitTime"/> is surpassed prior to the download72
/// completing, a download error is raised.73
/// </summary>74
[FileIOPermission(SecurityAction.Demand)]75
public void Download(UpdaterTask task, TimeSpan maxWaitTime)76

{77
try78

{79
OnDownloadStarted(new TaskEventArgs(task));80
//this object is used to perform the downloading on a separate thread81
AsyncDownloader downloader = new AsyncDownloader(task, new OnDownloadProgressEventHandler(OnDownloadProgress), new OnDownloadTotalSizeCalculationStartedEventHandler(OnDownloadTotalSizeCalculationStarted), new OnDownloadTotalSizeCalculationProgressEventHandler(OnDownloadTotalSizeCalculationProgress), new OnDownloadTotalSizeCalculationCompletedEventHandler(OnDownloadTotalSizeCalculationCompleted), new OnDownloadCompletedEventHandler(OnDownloadCompleted));82
CreateDownloaderThread(downloader);83
_downloaderThread.Start();84
//DateTime endTime = DateTime.Now + maxWaitTime;85
double endTime = Environment.TickCount + maxWaitTime.TotalMilliseconds;86
while ((endTime > Environment.TickCount) && !downloader.IsComplete)87

{88
Thread.Sleep(100);89
}90

91
if (!downloader.IsComplete)92

{93
//abort the thread if it didn't complete94
_downloaderThread.Abort();95
throw new ApplicationUpdaterException("Download surpassed time out of " + maxWaitTime);96
}97
else if (downloader.Exception != null)98

{99
//raise the error event if the downloader thread erred out100
OnDownloadError(new DownloadTaskErrorEventArgs(task, downloader.Exception));101
}102
}103
catch (Exception e)104

{105
OnDownloadError(new DownloadTaskErrorEventArgs(task, e));106
}107
}108

109

/**//// <summary>110
/// Downloads the specified task asynchronously via HTTP.111
/// </summary>112
[FileIOPermission(SecurityAction.Demand)]113
public void BeginDownload(UpdaterTask task)114

{115
try116

{117
OnDownloadStarted(new TaskEventArgs(task));118
//this object is used to perform the downloading on a separate thread119
AsyncDownloader downloader = new AsyncDownloader(task, new OnDownloadProgressEventHandler(OnDownloadProgress), new OnDownloadTotalSizeCalculationStartedEventHandler(OnDownloadTotalSizeCalculationStarted), new OnDownloadTotalSizeCalculationProgressEventHandler(OnDownloadTotalSizeCalculationProgress), new OnDownloadTotalSizeCalculationCompletedEventHandler(OnDownloadTotalSizeCalculationCompleted), new OnDownloadCompletedEventHandler(OnDownloadCompleted));120
CreateDownloaderThread(downloader);121
_downloaderThread.Start();122
}123
catch (Exception e)124

{125
OnDownloadError(new DownloadTaskErrorEventArgs(task, e));126
}127
}128

129

/**//// <summary>130
/// Cancels an asynchronous HTTP download operation.131
/// </summary>132
public bool CancelDownload(UpdaterTask task)133

{134
_downloaderThread.Abort();135
return true;136
}137

138

/**//// <summary>139
/// Creates the downloader thread.140
/// </summary>141
private void CreateDownloaderThread(AsyncDownloader downloader)142

{143
_downloaderThread = new Thread(new ThreadStart(downloader.Download));144
_downloaderThread.Name = "Downloader";145
_downloaderThread.IsBackground = true;146
}147

148

/**//// <summary>149
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationStarted"/> event.150
/// </summary>151
public delegate void DownloadTotalSizeCalculationStartedEventHandler(object sender, TaskEventArgs e);152

153

/**//// <summary>154
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationCompleted"/> event.155
/// </summary>156
public delegate void DownloadTotalSizeCalculationProgressEventHandler(object sender, DownloadTotalSizeCalculationProgressEventArgs e);157

158

/**//// <summary>159
/// Delegate for handling the <see cref="DownloadTotalSizeCalculationCompleted"/> event.160
/// </summary>161
public delegate void DownloadTotalSizeCalculationCompletedEventHandler(object sender, TaskEventArgs e);162

163

/**//// <summary>164
/// Fired when the HTTP downloader begins calculating file sizes for the files to be downloaded.165
/// </summary>166
/// <remarks>167
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).168
/// </remarks>169
public static event DownloadTotalSizeCalculationStartedEventHandler DownloadTotalSizeCalculationStarted;170

171

/**//// <summary>172
/// Fired when the HTTP downloader has progress information for file size calculations.173
/// </summary>174
/// <remarks>175
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).176
/// </remarks>177
public static event DownloadTotalSizeCalculationProgressEventHandler DownloadTotalSizeCalculationProgress;178

179

/**//// <summary>180
/// Fires when the HTTP downloader has finished calculating file sizes.181
/// </summary>182
/// <remarks>183
/// This event has to be <c>static</c> because the client is unable to obtain a reference to the <c>HttpDownloader</c> instance (updater design flaw).184
/// </remarks>185
public static event DownloadTotalSizeCalculationCompletedEventHandler DownloadTotalSizeCalculationCompleted;186

187

/**//// <summary>188
/// Fired when the HTTP downloader begins downloading files.189
/// </summary>190
public event DownloadTaskStartedEventHandler DownloadStarted;191

192

/**//// <summary>193
/// Fired whenever the HTTP downloader has progress information to report about the current downloads.194
/// </summary>195
public event DownloadTaskProgressEventHandler DownloadProgress;196

197

/**//// <summary>198
/// Fired when the HTTP downloader has finished downloading.199
/// </summary>200
public event DownloadTaskCompletedEventHandler DownloadCompleted;201

202

/**//// <summary>203
/// Fired when an error occurs in the HTTP downloader whilst attempting to download updates.204
/// </summary>205
public event DownloadTaskErrorEventHandler DownloadError;206

207

/**//// <summary>208
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationStarted"/> method.209
/// </summary>210
internal delegate void OnDownloadTotalSizeCalculationStartedEventHandler(TaskEventArgs e);211

212

/**//// <summary>213
/// Fires the <see cref="DownloadTotalSizeCalculationStarted"/> method.214
/// </summary>215
private void OnDownloadTotalSizeCalculationStarted(TaskEventArgs e)216

{217
if (DownloadTotalSizeCalculationStarted != null)218

{219
DownloadTotalSizeCalculationStarted(this, e);220
}221
}222

223

/**//// <summary>224
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationProgress"/> method.225
/// </summary>226
internal delegate void OnDownloadTotalSizeCalculationProgressEventHandler(DownloadTotalSizeCalculationProgressEventArgs e);227

228

/**//// <summary>229
/// Fires the <see cref="DownloadTotalSizeCalculationProgress"/> method.230
/// </summary>231
private void OnDownloadTotalSizeCalculationProgress(DownloadTotalSizeCalculationProgressEventArgs e)232

{233
if (DownloadTotalSizeCalculationProgress != null)234

{235
DownloadTotalSizeCalculationProgress(this, e);236
}237
}238

239

/**//// <summary>240
/// Used to invoke the <see cref="OnDownloadTotalSizeCalculationCompleted"/> method.241
/// </summary>242
internal delegate void OnDownloadTotalSizeCalculationCompletedEventHandler(TaskEventArgs e);243

244

/**//// <summary>245
/// Fires the <see cref="DownloadTotalSizeCalculationCompleted"/> method.246
/// </summary>247
private void OnDownloadTotalSizeCalculationCompleted(TaskEventArgs e)248

{249
if (DownloadTotalSizeCalculationCompleted != null)250

{251
DownloadTotalSizeCalculationCompleted(this, e);252
}253
}254
255

/**//// <summary>256
/// Fires the <see cref="DownloadStarted"/> method.257
/// </summary>258
private void OnDownloadStarted(TaskEventArgs e)259

{260
if (DownloadStarted != null)261

{262
DownloadStarted(this, e);263
}264
}265
266

/**//// <summary>267
/// Used to invoke the <see cref="OnDownloadProgress"/> method.268
/// </summary>269
internal delegate void OnDownloadProgressEventHandler(DownloadTaskProgressEventArgs e);270

271

/**//// <summary>272
/// Fires the <see cref="DownloadProgress"/> method.273
/// </summary>274
private void OnDownloadProgress(DownloadTaskProgressEventArgs e)275

{276
lock (LOCK)277

{278
if (DownloadProgress != null)279

{280
DownloadProgress(this, e);281
}282
}283
}284

285

/**//// <summary>286
/// Used to invoke the <see cref="OnDownloadCompleted"/> method.287
/// </summary>288
internal delegate void OnDownloadCompletedEventHandler(TaskEventArgs e);289
290

/**//// <summary>291
/// Fires the <see cref="DownloadCompleted"/> method.292
/// </summary>293
private void OnDownloadCompleted(TaskEventArgs e)294

{295
if (DownloadCompleted != null)296

{297
DownloadCompleted(this, e);298
}299
}300

301

/**//// <summary>302
/// Fires the <see cref="DownloadError"/> method.303
/// </summary>304
private void OnDownloadError(DownloadTaskErrorEventArgs e)305

{306
if (DownloadError != null)307

{308
DownloadError(this, e);309
}310
}311

312

/**//// <summary>313
/// Performs the actual downloading of updated files.314
/// </summary>315
private class AsyncDownloader316

{317

/**//// <summary>318
/// The task whose files will be downloaded.319
/// </summary>320
private UpdaterTask _task;321

322

/**//// <summary>323
/// Contains configuration settings.324
/// </summary>325
//private HttpDownloaderProviderData _configuration;326

327

/**//// <summary>328
/// Stores the last time a download progress report was issued.329
/// </summary>330
private DateTime _lastProgressReport;331

332

/**//// <summary>333
/// The delegate to invoke to report download progress.334
/// </summary>335
private OnDownloadProgressEventHandler _progressDelegate;336

337

/**//// <summary>338
/// The delegate to invoke to report that file size calculations have started.339
/// </summary>340
private OnDownloadTotalSizeCalculationStartedEventHandler _totalSizeStarted;341

342

/**//// <summary>343
/// The delegate to invoke to report file size calculations progress.344
/// </summary>345
private OnDownloadTotalSizeCalculationProgressEventHandler _totalSizeProgress;346

347

/**//// <summary>348
/// The delegate to invoke to report that file size calculations have completed.349
/// </summary>350
private OnDownloadTotalSizeCalculationCompletedEventHandler _totalSizeCompleted;351

352

/**//// <summary>353
/// The delegate to invoke to report that the download has completed.354
/// </summary>355
private OnDownloadCompletedEventHandler _downloadCompleted;356

357

/**//// <summary>358
/// The buffer used whilst downloading data.359
/// </summary>360
private byte[] _buffer;361

362

/**//// <summary>363
/// Set to <c>true</c> if the download completes successfully.364
/// </summary>365
private bool _isComplete;366

367

/**//// <summary>368
/// Any exception that occurred during the download.369
/// </summary>370
private Exception _exception;371

372

/**//// <summary>373
/// Synchronisation object.374
/// </summary>375
private readonly object LOCK;376

377

/**//// <summary>378
/// Gets or sets a value indicating whether the download completed successfully.379
/// </summary>380
internal bool IsComplete381

{382
get383

{384
lock (LOCK)385

{386
return _isComplete;387
}388
}389
set390

{391
lock (LOCK)392

{393
_isComplete = value;394
}395
}396
}397

398

/**//// <summary>399
/// Gets or sets an exception that occurred during the download process.400
/// </summary>401
internal Exception Exception402

{403
get404

{405
lock (LOCK)406

{407
return _exception;408
}409
}410
set411

{412
lock (LOCK)413

{414
_exception = value;415
}416
}417
}418

419

/**//// <summary>420
/// Constructs an <c>AsyncDownloader</c> instance.421
/// </summary>422
internal AsyncDownloader(UpdaterTask task, OnDownloadProgressEventHandler progressDelegate, OnDownloadTotalSizeCalculationStartedEventHandler totalSizeStarted, OnDownloadTotalSizeCalculationProgressEventHandler totalSizeProgress, OnDownloadTotalSizeCalculationCompletedEventHandler totalSizeCompleted, OnDownloadCompletedEventHandler downloadCompleted)423

{424
LOCK = new object();425
_task = task;426
//_configuration = configuration;427
_progressDelegate = progressDelegate;428
_totalSizeStarted = totalSizeStarted;429
_totalSizeProgress = totalSizeProgress;430
_totalSizeCompleted = totalSizeCompleted;431
_downloadCompleted = downloadCompleted;432
_buffer = new byte[1024];433
_lastProgressReport = DateTime.MinValue;434
}435

436

/**//// <summary>437
/// Performs the download operation.438
/// </summary>439
internal void Download()440

{441
long totalBytes = 0;442
long transferredBytes = 0;443
WebProxy webProxy = WebProxy.GetDefaultProxy();444

445
if (webProxy != null)446

{447
//not sure why this isn't default behaviour but it isn't. This ensures the downloader works when used from behind a proxy that requires authentication (assuming448
//authentication information is set up in IE)449
webProxy.Credentials = CredentialCache.DefaultCredentials;450
}451

452
try453

{454
_totalSizeStarted(new TaskEventArgs(_task));455

456
//first determine the total content length457
for (int i = 0; i < _task.Manifest.Files.Count; ++i)458

{459
FileManifest file = _task.Manifest.Files[i];460
string uri = GetUri(file);461
WebRequest webRequest = WebRequest.Create(uri);462
webRequest.Proxy = webProxy;463
webRequest.Method = "GET";464
WebResponse webResponse = webRequest.GetResponse();465
totalBytes += webResponse.ContentLength;466
webResponse.Close();467
_totalSizeProgress(new DownloadTotalSizeCalculationProgressEventArgs(_task.Manifest.Files.Count, i + 1));468
}469

470
_totalSizeCompleted(new TaskEventArgs(_task));471

472
//now download each file473
for (int i = 0; i < _task.Manifest.Files.Count; ++i)474

{475
FileManifest file = _task.Manifest.Files[i];476
string uri = GetUri(file);477
WebRequest webRequest = WebRequest.Create(uri);478
webRequest.Proxy = webProxy;479
WebResponse webResponse = webRequest.GetResponse();480
string outFile = Path.Combine(_task.DownloadFilesBase, file.Source);481
int read = 0;482

483
//make sure the destination directory exists484
if (!Directory.Exists(Path.GetDirectoryName(outFile)))485

{486
Directory.CreateDirectory(Path.GetDirectoryName(outFile));487
}488

489
using (Stream responseStream = webResponse.GetResponseStream())490
using (Stream fileStream = new FileStream(outFile, FileMode.Create, FileAccess.Write))491

{492
while ((read = responseStream.Read(_buffer, 0, _buffer.Length)) != 0)493

{494
transferredBytes += read;495
fileStream.Write(_buffer, 0, read);496
TimeSpan timeSinceLastProgressReport = DateTime.Now - _lastProgressReport;497

498
//if ((_configuration.DownloadProgressMaximumFrequency == 0) || (timeSinceLastProgressReport.TotalMilliseconds > _configuration.DownloadProgressMaximumFrequency))499
//{500
// _lastProgressReport = DateTime.Now;501
// _progressDelegate(new DownloadTaskProgressEventArgs(totalBytes, transferredBytes, _task.Manifest.Files.Count, i, _task));502
//}503
}504

505
//final progress report506
_progressDelegate(new DownloadTaskProgressEventArgs(totalBytes, transferredBytes, _task.Manifest.Files.Count, i, _task));507
}508

509
webResponse.Close();510
}511
}512
catch (Exception e)513

{514
if (!(e is ThreadAbortException))515

{516
Exception = e;517
}518
}519

520
//fire the complete event if no error occurred521
if (Exception == null)522

{523
_downloadCompleted(new TaskEventArgs(_task));524
}525

526
//if the thread is aborted, this won't execute because the ThreadAbortException will continue propogating527
IsComplete = true;528
}529

530

/**//// <summary>531
/// Obtains a URI for the specified file.532
/// </summary>533
private string GetUri(FileManifest file)534

{535
return string.Format("{0}{1}", _task.Manifest.Files.Base, file.Source);536
}537
}538
}539
}540

1
using System;2
using System.Xml.Serialization;3
using Microsoft.ApplicationBlocks.Updater.Configuration;4
using Microsoft.ApplicationBlocks.Updater.Downloaders;5
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder;6
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;7
using System.Configuration;8
using Microsoft.ApplicationBlocks.Updater;9
namespace x.HttpDownloader10


{11

/**//// <summary>12
/// Contains configuration for the <see cref="HttpDownloader"/>.13
/// </summary>14
//[XmlRoot("downloader", Namespace = ApplicationUpdaterSettings.ConfigurationNamespace)]15
[Assembler(typeof(HttpDownloaderAssembler))]16
public class HttpDownloaderProviderData : DownloaderProviderData17

{18

/**//// <summary>19
/// See <see cref="DownloadBufferSize"/>.20
/// </summary>21
private int _downloadBufferSize;22

23

/**//// <summary>24
/// See <see cref="DownloadProgressMaximumFrequency"/>25
/// </summary>26
private int _downloadProgressMaximumProgress;27

28

/**//// <summary>29
/// The minimum value that can be assigned to <see cref="DownloadBufferSize"/>.30
/// </summary>31
private const int DOWNLOAD_BUFFER_SIZE_MIN = 256;32

33

/**//// <summary>34
/// The maximum value that can be assigned to <see cref="DownloadBufferSize"/>.35
/// </summary>36
private const int DOWNLOAD_BUFFER_SIZE_MAX = 10240;37

38

/**//// <summary>39
/// The minimum value that can be assigned to <see cref="DownloadProgressMaximumFrequency"/>.40
/// </summary>41
private const int DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN = 0;42
43

/**//// <summary>44
/// The maximum value that can be assigned to <see cref="DownloadProgressMaximumFrequency"/>.45
/// </summary>46
private const int DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX = 5000;47

48

/**//// <summary>49
/// Gets or sets the buffer size, in bytes, used whilst downloading files.50
/// </summary>51
/// <remarks>52
/// The HTTP downloader reports progress each time it fills the download buffer. Therefore, larger buffer sizes will result53
/// in fewer progress reports.54
/// </remarks>55
//[ConfigurationProperty(_downloadBufferSize, IsRequired = false)]56
public int DownloadBufferSize57

{58
get59

{60
return _downloadBufferSize;61
}62
set63

{64
if ((value < DOWNLOAD_BUFFER_SIZE_MIN) || (value > DOWNLOAD_BUFFER_SIZE_MAX))65

{66
throw new ArgumentException(string.Format("DownloadBufferSize must be between {0} and {1}", DOWNLOAD_BUFFER_SIZE_MIN, DOWNLOAD_BUFFER_SIZE_MAX));67
}68

69
_downloadBufferSize = value;70
}71
}72

73

/**//// <summary>74
/// Gets or sets the maximum frequency, in milliseconds, that progress will be reported by the HTTP downloader.75
/// </summary>76
/// <remarks>77
/// <para>78
/// This property allows you to limit the number of progress reports issued by the HTTP downloader. The downloader will ensure that79
/// the amount of time specified by this property has elapsed prior to issuing another progress report. If enough time has not elapsed80
/// then the downloader will not issue a progress report at that time.81
/// </para>82
/// <para>83
/// Setting this property to <c>0</c> ensures that the downloader always reports progress, regardless of the amount of time that has84
/// elapsed since the last progress report.85
/// </para>86
/// </remarks>87
//[XmlElement("downloadProgressMaximumFrequency")]88
public int DownloadProgressMaximumFrequency89

{90
get91

{92
return _downloadProgressMaximumProgress;93
}94
set95

{96
if ((value < DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN) || (value > DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX))97

{98
throw new ArgumentException(string.Format("DownloadProgressMaximumFrequency must be between {0} and {1}", DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MIN, DOWNLOAD_PROGRESS_MAXIMUM_FREQUENCY_MAX));99
}100

101
_downloadProgressMaximumProgress = value;102
}103
}104

105

/**//// <summary>106
/// Default constructor.107
/// </summary>108
public HttpDownloaderProviderData()109

{110
DownloadBufferSize = 1024;111
}112
}113

114
public class HttpDownloaderAssembler : IAssembler<Microsoft.ApplicationBlocks.Updater.IDownloader, DownloaderProviderData>115

{116
public IDownloader Assemble(Microsoft.Practices.ObjectBuilder.IBuilderContext context, DownloaderProviderData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)117

{118
HttpDownloaderProviderData bitsData = (HttpDownloaderProviderData)objectConfiguration;119
return new HttpDownloader();120
}121
}122
}123


浙公网安备 33010602011771号