/// <summary>
        /// 增加当前在线用户数
        /// </summary>
        /// <param name="User"></param>
        /// <param name="Request"></param>
        /// <param name="PortalType"></param>
        public static void OnUserLogin(UserValidator User,
                                       HttpRequest Request,
                                       Site.PortalType PortalType = Site.PortalType.Portal)
        {
            lock (_OnlineUserIdAliasTable)
            {
                OThinker.H3.Tracking.UserLog log = new Tracking.UserLog(
                    Tracking.UserLogType.Login,
                    User.UserID,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    SheetUtility.GetClientIP(Request),
                    SheetUtility.GetClientPlatform(Request),
                    SheetUtility.GetClientBrowser(Request));

                if (_OnlineUserIdAliasTable.ContainsKey(User.UserID.ToLower()))
                {
                    //_OnlineUserIdAliasTable.Remove(User.UserID);
                    //_OnlineUserIdLoginTimeTable.Remove(User.UserID);
                    return;
                }
                _OnlineUserIdAliasTable.Add(User.UserID, User.UserCode);
                _OnlineUserIdLoginTimeTable.Add(User.UserID, DateTime.Now);

                log.UserCode = User.UserCode;
                log.SiteType = PortalType;

                if (OThinker.H3.Controllers.AppConfig.ConnectionMode == OThinker.H3.ConnectionStringParser.ConnectionMode.Mono)
                {
                    // 私有云模式批量写入
                    if (!_UserLogTable.ContainsKey(User.UserID.ToLower()))
                    {
                        _UserLogTable.Add(User.UserID.ToLower(), log);
                    }
                }
                else
                {
                    // 公有云模式登录即写入
                    User.Engine.UserLogWriter.Write(log);
                }
            }
        }
        /// <summary>
        /// 用户登出事件
        /// </summary>
        /// <param name="User"></param>
        /// <param name="Request"></param>
        public static void OnUserLogout(UserValidator User, HttpRequest Request)
        {
            if (User == null)
            {
                return;
            }

            // 减少当前用户数
            //lock (_UserLogTable)
            lock (_OnlineUserIdAliasTable)
            {
                //if (!_UserLogTable.ContainsKey(User.UserID.ToLower()))
                //{
                //    return;
                //}
                if (!_OnlineUserIdAliasTable.ContainsKey(User.UserID.ToLower()))
                {
                    return;
                }
                _OnlineUserIdAliasTable.Remove(User.UserID);
                _OnlineUserIdLoginTimeTable.Remove(User.UserID);

                OThinker.H3.Tracking.UserLog log = new Tracking.UserLog(
                    Tracking.UserLogType.Logout,
                    User.UserID,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    SheetUtility.GetClientIP(Request),
                    SheetUtility.GetClientPlatform(Request),
                    SheetUtility.GetClientBrowser(Request));
                if (!_UserLogTable.ContainsKey(User.UserID.ToLower()))
                {
                    _UserLogTable.Add(User.UserID.ToLower(), log);
                }
            }
        }
        /// <summary>
        /// 单个文件下载
        /// </summary>
        /// <returns></returns>
        public object Read()
        {
            OThinker.H3.Tracking.UserLog log = null;
            //安卓微信/钉钉中打开文件  弃用
            if (this.IsMobile && (IsWeChat || IsDingTalk) && IsAndroid && false)
            {
                // 记录打开日志
                log = new Tracking.UserLog(
                    Tracking.UserLogType.OpenAttachment,
                    this.UserValidator.UserID,
                    this.BizObjectSchemaCode,
                    this.BizObjectID,
                    this.BizObjectID,
                    string.Empty,
                    string.Empty,
                    null,
                    SheetUtility.GetClientIP(Request),
                    SheetUtility.GetClientPlatform(Request),
                    SheetUtility.GetClientBrowser(Request));
                this.Engine.UserLogWriter.Write(log);

                string attachmentUrl = this.GetAttachmentRedirectUrl();

                if (!string.IsNullOrEmpty(attachmentUrl))
                {
                    Response.Redirect(attachmentUrl);
                }
                return(null);
            }

            Attachment attachment = this.Engine.BizObjectManager.GetAttachment(
                UserID,
                this.BizObjectSchemaCode,
                this.BizObjectID,
                this.AttachmentID);

            if (attachment == null || attachment.Content == null || attachment.Content.Length == 0)
            {
                //AlertAndClose(this.PortalResource.GetString("ReadAttachment_AttachmentIsNull"));
                //return;
            }

            // 记录打开日志
            log = new Tracking.UserLog(
                Tracking.UserLogType.OpenAttachment,
                UserID,
                attachment.BizObjectSchemaCode,
                attachment.BizObjectId,
                attachment.BizObjectId,
                string.Empty,
                attachment.FileName,
                null,
                SheetUtility.GetClientIP(Request),
                SheetUtility.GetClientPlatform(Request),
                SheetUtility.GetClientBrowser(Request));
            this.Engine.UserLogWriter.Write(log);

            //保存文件到服务器
            string fileName = attachment.ObjectID + Path.GetExtension(attachment.FileName);
            string savePath = Path.Combine(Server.MapPath("~/TempImages"), fileName);

            using (FileStream fs = new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    bw.Write(attachment.Content);
                    bw.Close();
                }
            }

            if (this.IsMobile)
            {
                // 移动办公app打开方式,则先下载到临时文件夹,再输出文件地址
                if (this.AppLogin)
                {
                    var url    = string.Format(this.PortalRoot + "/TempImages/{0}", fileName);
                    var result = new
                    {
                        Url       = string.Format(this.PortalRoot + "/TempImages/{0}", fileName),
                        Extension = Path.GetExtension(attachment.FileName).ToLower()
                    };
                    return(Json(result, JsonRequestBehavior.AllowGet));
                }
                else
                {
                    Response.Redirect(Path.Combine(PortalUri, "TempImages/" + fileName));
                    return(null);
                }
            }

            string inLine = string.Empty;

            if (Browse_Extension.IndexOf(Path.GetExtension(attachment.FileName).ToLower()) != -1)
            {
                inLine = "inline;";
            }
            else
            {
                inLine = "attachment;";
            }

            // 输出附件
            Response.Buffer = true;
            Response.Clear();
            Response.ClearContent();
            Response.ClearHeaders();
            Response.AddHeader("Content-Disposition", inLine + "filename=" + HttpUtility.UrlEncode(attachment.FileName, System.Text.Encoding.UTF8));
            Response.AddHeader("Content-Type", attachment.ContentType);
            //Response.AddHeader("Content-Length", attachment.Content.LongLength.ToString());
            Response.TransmitFile(savePath);
            Response.End();
            System.IO.File.Delete(savePath);
            return(null);
        }