你需要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
