using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.ComponentModel;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using System.Collections.Specialized;
namespace ProjectBase.Data.Update
{
///
/// 下载错误事件数据
///
public class DownloadErrorEventArgs : EventArgs
{
public Exception Error { get; set; }
public Manifest Manifest { get; set; }
}
///
/// 下载进度事件数据
///
public class DownloadProgressEventArgs : ProgressChangedEventArgs
{
public DownloadProgressEventArgs(int progressPercentage, object userState)
: base(progressPercentage,userState)
{ }
///
/// 当前下载的文件名
///
public string FileName { get; set; }
///
/// 获取收到的字节数。
///
public long BytesReceived { get; set; }
///
/// 获取 System.Net.WebClient 数据下载操作中的字节总数。
///
public long TotalBytesToReceive { get; set; }
}
///
/// 下载完成事件数据
///
public class DownloadCompleteEventArgs : AsyncCompletedEventArgs
{
public DownloadCompleteEventArgs(Exception error, bool cancelled, object userState)
: base(error, cancelled, userState)
{
}
public Manifest Manifest { get; set; }
}
///
/// 服务器文件下载类
///
public class DownloadClass : Component
{
#region 变量定义
private WebClient webClient = new WebClient();
private Manifest manifest;
private int fileCount = 0; // 文件数量
private long fileSize = 0; // 每个文件大小
private bool cancel = false;
private string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../temp");
private HybridDictionary userStateToLifetime = new HybridDictionary();
private object defaultTaskId = new object();
private delegate void WorkerEventHandler(AsyncOperation asyncOp);
private System.ComponentModel.Container components = null;
private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private AsyncOperation current;
#endregion
#region 事件
///
/// 下载进度
///
public event EventHandler DownloadProgressChanged;
///
/// 下载完成事件
///
public event EventHandler DownloadCompleted;
///
/// 下载错误触发的事件
///
public event EventHandler DownloadError;
#endregion
#region 构造及析构
public DownloadClass(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public DownloadClass()
{
InitializeComponent();
InitializeDelegates();
}
///
/// 初始化代理
///
protected virtual void InitializeDelegates()
{
onProgressReportDelegate = new SendOrPostCallback(ReportProgress);
onCompletedDelegate = new SendOrPostCallback(DoDownloadCompleted);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#endregion
///
/// 触发下载进度事件
///
///
protected virtual void OnDownloadProgressChanged(DownloadProgressEventArgs e)
{
if (DownloadProgressChanged != null)
{
DownloadProgressChanged(this, e);
}
}
///
/// 触发下载完成事件
///
///
protected virtual void OnDownloadCompleted(DownloadCompleteEventArgs e)
{
if (DownloadCompleted != null)
{
DownloadCompleted(this, e);
}
}
///
/// 触发下载错误事件
///
///
protected virtual void OnDownloadError(DownloadErrorEventArgs e)
{
if (DownloadError != null)
{
DownloadError(this, e);
}
}
///
/// 下载文字保存的临时目录
///
public string TempPath
{
get
{
return tempPath;
}
set
{
tempPath = value;
}
}
///
/// 同步下载
///
/// 文件下载清单
public void Download(Manifest manifest)
{
Init(manifest);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
webClient.DownloadFile(uri, clientFileName);
}
}
///
/// 异步下载
///
/// 文件下载清单
public void DownloadAsync(Manifest manifest)
{
Init(manifest);
DownloadAsync(manifest,defaultTaskId);
}
///
/// 异步下载并指定任务Id
///
/// 文件下载清单
/// 任务Id
public void DownloadAsync(Manifest manifest,object taskId)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException("参数taskId必须是唯一的", "taskId");
}
userStateToLifetime[taskId] = asyncOp;
}
WorkerEventHandler workerDelegate = new WorkerEventHandler(DownloadWorker);
workerDelegate.BeginInvoke(asyncOp, null, null);
}
private void Init(Manifest mainfest)
{
this.manifest = mainfest;
webClient.BaseAddress = manifest.ManifestFiles.BaseUrl;
webClient.Credentials = new NetworkCredential(mainfest.FtpName, mainfest.FtpPsswd);
webClient.Encoding = Encoding.UTF8;
}
///
/// 异步下载方法
///
///
private void DownloadWorker(AsyncOperation asyncOp)
{
current = asyncOp;
if (!TaskCanceled(asyncOp.UserSuppliedState))
{
try
{
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
foreach (var file in manifest.ManifestFiles.Files)
{
string serverFileName = Path.Combine(manifest.ManifestFiles.BaseUrl, file.Source);
string clientFileName = Path.Combine(tempPath, file.Source);
Uri uri = new Uri(serverFileName);
if (!Directory.Exists(Path.GetDirectoryName(clientFileName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(clientFileName));
}
WebRequest sizeRequest = WebRequest.Create(serverFileName);
sizeRequest.Credentials = new NetworkCredential(manifest.FtpName, manifest.FtpPsswd); ;
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
fileSize += (int)sizeRequest.GetResponse().ContentLength;
while (webClient.IsBusy)
{
//阻塞异步下载
}
if (!cancel)
{
webClient.DownloadFileAsync(uri, clientFileName, file.Source);
}
}
}
catch (Exception ex)
{
DownloadErrorEventArgs e = new DownloadErrorEventArgs();
e.Error = ex;
e.Manifest = manifest;
OnDownloadError(e);
}
}
}
///
/// 异步完成方法
///
/// 异常数据
/// 是否取消
///
private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
{
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
DownloadCompleteEventArgs e = new DownloadCompleteEventArgs(exception, canceled, asyncOp.UserSuppliedState);
e.Manifest = manifest;
asyncOp.PostOperationCompleted(onCompletedDelegate, e);
current = null;
}
///
/// 异步下载进度事件(仅对于单个文件)
///
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadProgressEventArgs args = new DownloadProgressEventArgs((int)((double)e.BytesReceived / (double)fileSize * 100), e.UserState);
args.BytesReceived += e.BytesReceived;
args.FileName = e.UserState.ToString();
args.TotalBytesToReceive = fileSize;
if (current != null)
{
current.Post(onProgressReportDelegate, args);
}
}
///
/// 异步下载完成事件(仅对于单个文件)
///
///
///
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
fileCount++;
if (fileCount == manifest.ManifestFiles.Files.Length)
{
this.CompletionMethod(e.Error, TaskCanceled(current.UserSuppliedState), current);
}
}
///
/// 取消异步下载
///
public void CancelAsync()
{
CancelAsync(defaultTaskId);
}
///
/// 取消异步下载
///
public void CancelAsync(object taskId)
{
webClient.CancelAsync();
cancel = true;
current = null;
AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation;
if (asyncOp != null)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(taskId);
}
}
}
private bool TaskCanceled(object taskId)
{
return cancel || (userStateToLifetime[taskId] == null);
}
private void DoDownloadCompleted(object operationState)
{
DownloadCompleteEventArgs e = operationState as DownloadCompleteEventArgs;
OnDownloadCompleted(e);
}
private void ReportProgress(object state)
{
DownloadProgressEventArgs e = state as DownloadProgressEventArgs;
OnDownloadProgressChanged(e);
}
}
}