/// <summary>
        /// 保存上传文件到磁盘目录(此方法在http_service_handler的Upload中在文件类型校验合法后被调用)
        /// </summary>
        /// <param name="param">上传参数配置</param>
        /// <param name="fileHash">上传文件的物理路径Hashtable</param>
        internal static void SaveToDisk(UploadParameter param, System.Collections.Hashtable fileHash)
        {
            int cur_build = 0;      // 创建文件保存路径次数            
            string _filePath = string.Empty;

            if (!Directory.Exists(param.SaveToDir))
            {
                if (!param.AutoMKDir)
                    throw new APIFW_ArgumentException(" 上传目录不存在,请手动创建目录或将AutoMKDir参数设置为True ");
                fileHash.Add(-1, Directory.CreateDirectory(param.SaveToDir).FullName);
            }

            int size = 0;
            long completed = 0;
            byte[] buffer = new byte[param.BufferSize];

            for (int i = 0; i < param.FileUploads.Length; i++)
            {
                cur_build = 0;      // 上传文件名称重命名计数
                completed = 0;      // 当前上传文件已保存大小

                AdjustUploadItemFileName(param, ref param.FileUploads[i], ref cur_build, ref _filePath);

                if (param.FileUploads[i].IsValid && param.FileUploads[i].FileName != null &&
                    param.FileUploads[i].ContentLength > 0 && param.FileUploads[i].FileName.Length > 0)
                {
                    try
                    {
                        // 开始上传
                        param.ExcuteOnUploadItemStart(param.FileUploads[i]);

                        // request.Files.Get(param.FileUploads[i].ClientKey).SaveAs(_filePath);
                        using (FileStream fs = new FileStream(_filePath, FileMode.Create, FileAccess.ReadWrite))
                        {
                            using (BinaryWriter bw = new BinaryWriter(fs))
                            {
                                using (BinaryReader br = new BinaryReader(param.FileUploads[i].InputStream))
                                {
                                    while ((size = br.Read(buffer, 0, buffer.Length)) > 0)
                                    {
                                        completed += size;
                                        bw.Write(buffer, 0, size);

                                        // 进度变化
                                        param.ExcuteOnUploadItemProgressChange(param.FileUploads[i], completed);
                                    }
                                }
                            }
                        }
                        // 上传完成
                        param.ExcuteOnUploadItemCompleted(param.FileUploads[i]);
                    }
                    catch (Exception ex)
                    {
                        // 上传出错
                        if (!param.ExcuteOnUploadItemFailedHandler(param.FileUploads[i], ex)) { throw ex; }
                    }
                }
            }
        }
        protected override void Upload(UploadParameter arg)
        {
            arg.UnBindEvent();

            // 添加 或者
            // 删除自定义允许上传文件类型
            //arg.UnOrAllowTypes.Add("chm");
            //arg.UnOrAllowTypes.Add("ini");
            //arg.UnOrAllowTypes.Add("css");

            // 重命名上传文件保存名称
            //foreach (UploadItem item in arg.FileUploads)
            //{
            //    item.FileName = Guid.NewGuid() + "." + item.FileSuffix;
            //}

            // 上传文件类型            
            arg.FileTypes.Clear();
            arg.FileTypes.Add("exe"); // 禁止上传 exe 
            arg.TypeValidMode = FileUploadTypeValidMode.UnAllowType;

            // 上传事件订阅
            arg.OnUploadItemStart += Arg_OnUploadItemStart;
            arg.OnUploadItemCompleted += Arg_OnUploadItemCompleted;
            
            arg.OnUploadItemValidFailed += Arg_OnUploadItemValidFailed;
            arg.OnUploadItemFailedHandler += Arg_OnUploadItemFailedHandler;
            arg.OnUploadItemProgressChange += Arg_OnUploadItemProgressChange;

            // 解除绑定事件委托函数列表
            // arg.UnBindEvent();
            base.Upload(arg);
        }
        /// <summary>
        /// 对已经上传的文件进行调整管理(删除。保留),当上传失败,发生异常的时候调用此方法
        /// </summary>
        /// <param name="arg">上传配置参数</param>
        /// <param name="_fileHash">已经上传的文件名hash表</param>
        internal static void DoTranstion(UploadParameter arg, Hashtable _fileHash)
        {
            if (arg.IsUseTranstion)
            {
                // 删除已经上传文件
                for (int i = 0; i < _fileHash.Count; i++)
                {
                    try
                    {
                        File.Delete(_fileHash[i].ToString());
                    }
                    catch { }
                }

                // 删除本次创建的目录
                try
                {
                    if (_fileHash.ContainsKey(-1))
                    {
                        // 防止误删(因为可能同时有多个用户上传文件,并且上传到同一个
                        // 目录中,A成功,B失败,目录是B创建的,这里就不能这样删了,尽管会提示不可以删除非空目录)
                        if (Directory.GetFiles(_fileHash[-1].ToString()).Length == 0)
                        {
                            File.Delete(_fileHash[-1].ToString());
                        }
                    }
                }
                catch { }
            }
        }
        /// <summary>
        /// 创建上传文件的配置参数对象
        /// </summary>
        /// <param name="request">HttpRequest</param>
        /// <param name="server">HttpServerUtility</param>
        /// <returns></returns>
        internal static UploadParameter BuildUploadParameter(HttpRequest request, HttpServerUtility server)
        {
            long totalSize = 0;
            List<UploadItem> uploadItems = new List<UploadItem>();

            for (int i = 0; i < request.Files.Count; i++)
            {
                if (request.Files[i].ContentLength > 0)
                {
                    totalSize += request.Files[i].ContentLength;
                    uploadItems.Add(
                        new UploadItem(
                            request.Files.AllKeys[i],
                            request.Files[i].FileName,
                            request.Files[i].ContentType,
                            request.Files[i].ContentLength,
                            request.Files[i].InputStream
                     ));
                }
            }

            // 参数配置
            UploadParameter uploadParam = new UploadParameter(uploadItems.ToArray(),
                server.MapPath("~/App_Data/Upload/" + DateTime.Now.ToString("yyyyMMddHH") + "/"), totalSize);

            // 上传事件
            uploadParam.OnUploadItemStart += UploadParam_OnUploadItemStart;
            uploadParam.OnUploadItemCompleted += upload_OnUploadItemCompleted;
            uploadParam.OnUploadItemFailedHandler += upload_OnUploadItemFailedHandler;
            uploadParam.OnUploadItemProgressChange += upload_OnUploadItemProgressChange;
            uploadParam.OnUploadItemValidFailed += UploadParam_OnUploadItemValidFailed;

            return uploadParam;
        }
        /// <summary>
        /// 验证文件类型是否无效(当文件类型与参数fileSuffix一样时,表示有效)
        /// 如果当文件类型与参数fileSuffix不一样时,通过调用 uploadParam.ExcuteOnUploadItemValidFailed来确定文件是否有效
        /// </summary>
        /// <returns></returns>
        private static bool IsinValidFileTypeWhenNotEqual(UploadParameter uploadParam, UploadItem uploadItem, string fileSuffix)
        {
            if (fileSuffix.Equals(
                uploadItem.FileSuffix, StringComparison.OrdinalIgnoreCase))
            {
                return !(uploadItem.IsValid = true);
            }

            uploadItem.IsValid = false;
            uploadItem.InValidMessages.Add(" 文件 [" + uploadItem.FileName + "] 上传类型验证无效 ");

            // 调用ExcuteOnUploadItemValidFailed进行(如果返回false,表示不允许忽略错误,禁止继续上传文件)
            return !(uploadItem.IsValid = uploadParam.ExcuteOnUploadItemValidFailed(uploadItem, FileUploadTypeValidOption.FileType));
        }
        /// <summary>
        /// 尝试对长传文件进行保存路径与文件名称调整(该方法可能会递归调用自己,但不会出现死循环
        /// 有最大次数限制,如果达到最大调整次数还没有成功,会抛出 APIFW_InvalidOperationException 异常)
        /// </summary>
        /// <param name="param">上传配置参数</param>
        /// <param name="item">当前执行上传文件对象</param>
        /// <param name="callCount">对路径进行调整的次数</param>
        /// <param name="fileNewPath">文件的上传保存路径</param>
        private static void AdjustUploadItemFileName(UploadParameter param, ref UploadItem item, ref int callCount, ref string fileNewPath)
        {
            fileNewPath = Path.Combine(param.SaveToDir, item.FileName);
            if (File.Exists(fileNewPath))
            {
                SFUEDoOption(param.FileExistDoOption, param.SaveToDir, ref item);

                if (callCount++ > FileUploadDefault.ReUploadItemNameMaxCount)
                    throw new APIFW_InvalidOperationException("上传文件名称冲突,程序尝试了[" + FileUploadDefault.ReUploadItemNameMaxCount + "]次重命名任然失败,请重新尝试");

                FileUploadUtility.AdjustUploadItemFileName(param, ref item, ref callCount, ref fileNewPath);
            }
        }
        /// <summary>
        /// 判断是否上传文件的文件类型(是否存在不存在与允许上传文件类型配置项中)
        /// </summary>
        /// <param name="uploadParam">上传参数对象</param>
        /// <returns></returns>
        private static bool IsValidExistUnAllowType(UploadParameter uploadParam)
        {
            int okQu = 0;

            // 文件类型的验证模式为 UnAllowType,如果uploadParam.UnOrAllowTypes为null或者Count为0,表示允许所有文件类型的文件上传
            if (uploadParam.TypeValidMode == httpCore.FileUploadTypeValidMode.UnAllowType)
            {
                if (uploadParam.FileTypes == null || uploadParam.FileTypes.Count == 0)
                {
                    return false;
                }
            }

            //
            // 校验方式为只允许,就遍历所有的文件,只需要找到一个文件的类型不存在于UnOrAllowTypes
            // 上传的文件类型数组中,就说明本次上传文件中包含非法的文件类型,调用ExcuteOnUploadItemValidFailed
            // -------------------------------------------------------------------------------------------//
            if (uploadParam.TypeValidMode == httpCore.FileUploadTypeValidMode.AllowType)
            {
                for (int a = 0; a < uploadParam.FileUploads.Length; a++)
                {
                    for (int b = 0; b < uploadParam.FileTypes.Count; b++)
                    {
                        // 此文件类型存在于UnOrAllowTypes中
                        // 说明它合法,break 继续下一个文件的文件类型验证
                        if (IsValidFileTypeWhenEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b]))
                        {
                            okQu++;
                            break;
                        }

                        // 循环到最后一个了。如果最后一个文件类型都不一样,那就说明这个文件类型非法
                        if (b == uploadParam.FileTypes.Count - 1)
                        {
                            if (IsinValidFileTypeWhenNotEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b]))
                            {
                                okQu = -1;
                                break;
                            }
                        }
                    }

                    // 找到了一个非法类型的上传文件,并且
                    // ExcuteOnUploadItemValidFailed方法返回False,表示不能继续上传了。
                    if (okQu == -1) { break; }
                }
                return uploadParam.FileUploads.Length == okQu;
            }


            //
            // 校验方式为不允许,就遍历所有的文件,只需要找到一个文件的类型存在于UnOrAllowTypes
            // 上传的文件类型数组中,就说明本次上传文件中包含不允许上传的文件类型,调用ExcuteOnUploadItemValidFailed
            // -------------------------------------------------------------------------------------------------------//
            for (int a = 0; a < uploadParam.FileUploads.Length; a++)
            {
                for (int b = 0; b < uploadParam.FileTypes.Count; b++)
                {
                    if (IsinValidFileTypeWhenEqual(uploadParam, uploadParam.FileUploads[a], uploadParam.FileTypes[b]))
                    {
                        okQu = -1;
                        break;
                    }
                }
                if (okQu == -1) { return false; }
            }
            return true;
        }
        /// <summary>
        /// 验证上传文件的:基础数据/验证模式与文件类型/所有文件总大小/单个文件大小 是否合法
        /// </summary>
        /// <param name="uploadParam">上传参数对象</param>
        /// <returns></returns>
        private static bool IsValidUploadBasicData(UploadParameter uploadParam)
        {
            // 基础数据必须正确
            if (uploadParam != null && uploadParam.FileUploads != null && uploadParam.FileUploads.Length > 0)
            {
                // 验证总文件大小
                if (uploadParam.AllowFileSize < uploadParam.FileTotalSize)
                {
                    throw new APIFW_ArgumentException("上传文件总大小超过了配置参数最大限制!");
                }

                // 验证单个文件大小
                foreach (UploadItem item in uploadParam.FileUploads)
                {
                    if (uploadParam.AllowSingleFileSize < item.ContentLength)
                    {
                        if (!uploadParam.ExcuteOnUploadItemValidFailed(item, FileUploadTypeValidOption.FileSize))
                        {
                            throw new APIFW_ArgumentException("上传文件[" + item.FileName + "]的大小超过了配置参数最大大小限制!");
                        }
                    }
                }

                // 验证模式为FileUploadTypeValidMode.AllowType,必须指定。UnOrAllowTypes参数
                if ((uploadParam.TypeValidMode == FileUploadTypeValidMode.AllowType))
                {
                    if (uploadParam.FileTypes == null || uploadParam.FileTypes.Count == 0)
                    {
                        throw new APIFW_ArgumentException("上传允许文件类型验证模式为 FileUploadTypeValidMode.AllowType,最少必须包含一项UnOrAllowTypes!");
                    }
                }
                return true;
            }
            throw new APIFW_ArgumentException(" 上传参数[UploadParameter]验证失败,没有任何允许上传的文件或者上传文件大小为零,请确认!");
        }
 /// <summary>
 /// 验证是否所有上传文件的文件类型,上传大小都符合
 /// 上传配置参数(都满足[即可以上传]返回true,否则返回false)
 /// </summary>
 /// <param name="uploadParam">上传参数对象</param>
 /// <returns></returns>
 internal static bool IsValid(UploadParameter uploadParam)
 {
     // 验证是上传参数数据正确性 --> 验证上传文件类型的正确性
     return !(FileUploadUtility.IsValidUploadBasicData(uploadParam))
     ? false : FileUploadUtility.IsValidExistUnAllowType(uploadParam);
 }