Ajax异步导出方案


可能一些技术细节涉及到架构实现方案,不过,不影响本意的表达。

跨页面传值(按查询的导出方案)

场景:页面类型:查询条件,查询,导出。

查询条件比较多,且查询内容也可能比较多,如果使用URL传值的话,可能存在URL超长截断的可能。

原理:

1.  问题:在回调(Ajax或timer)里执行 document.location 或 window.open 方法,浏览器会阻止下载(有提示)。要解决,如何把条件 Post 到服务器端,再执行 window.location 方法而不报阻止 。

2. 导出时,先使用 Ajax 把查询Model 传递到服务器,保存在Session 里。

3. 执行 window.location 跳转。

4. 跳转页面检查Session 里的查询Model,如果不存在,则进行阻塞等待,等待最大时间 3秒。 如果超时,则抛出错误,如果3秒内得到 Ajax 传递回来的查询Model,则继续执行。

实现方案:

1. 客户端传值,先调用 jv.saveSession , 再弹出页面传递参数 : QueryKey。

jv.saveSession("ParkingInfo", $(".divQuery:last", jv.boxdy()).GetDivJson("List_"));

jv.PopList({

url: "~/ReportWeb/Parking/ParkingInfo.aspx?QueryKey=ParkingInfo",

entity: "Notices"

}, null);

2. 服务器端接收(只能接收一次)

var qModel = LifeSession.OnceGetQuery(Request.QueryString["QueryKey"], new ParkingBiz.ParkingQuery());

if (qModel == null)

{

Response.Write("接收参数时失败,请重试,或联系系统管理员。");

Response.End();

}

 

当然 LifeSession

View Code
    public class LifeSession : IDisposable
    {
        List<string> keys = new List<string>();
        public object this[string SessionKey]
        {
            get
            {
                return HttpContext.Current.Session[SessionKey];
            }
            set
            {
                GodError.Check(value == null, () => "数据接收异常");
                keys.Add(SessionKey);
                HttpContext.Current.Session[SessionKey] = value;
            }
        }
        public void Dispose()
        {
            keys.All(o =>
            {
                HttpContext.Current.Session.Remove(o);
                return true;
            });
        }

        public static T OnceGetQuery<T>(string Key, T NewModel)
            where T : class
        {
            if (Key.HasValue() == false)
            {
                throw new GodError("接收Session值的 Key 值不能为空");
            }

            XmlDictionary<string, string> dict = null;

            //10 sec
            for (int i = 0; i < 100; i++)
            {
                if (HttpContext.Current.Session[Key] != null)
                {
                    dict = HttpContext.Current.Session[Key] as XmlDictionary<string, string>;

                    if (dict == null)
                    {
                        var err = "数据接收异常 :" + HttpContext.Current.Session[Key].GetType().FullName;
                        LogInfo.To(InfoEnum.Error, MySessionKey.UserName.Get(), err);
                        throw new GodError(err);
                    }

                    HttpContext.Current.Session.Remove(Key);
                    break;
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
            if (dict == null) return null;
            var retVal = dict.DictionaryToModel(NewModel);
            GodError.Check(retVal == null, () => "Session项数据 : " + Key + "转换失败, 数据:" + dict.ToJson() + ",转换目标类型:" + typeof(T).FullName);
            return retVal;
        }
    }

js:

View Code
    jv.saveSession = function (sessionKey, jsonData) {
        if (!sessionKey) { alert("请输入 SessionKey "); return false; }
        if (!jsonData) { alert("请输入 JsonData "); return false; }

        $.post(jv.Root + "Master/Home/SaveSession/" + sessionKey + ".aspx", jsonData, function (res) {
            if (res.msg) { alert(res.msg) };
        });
        return true;
    };

 

执行流程

点击导出后,其流程图是这样的:

1. Client   ----------------------------------------------IIS加工并赋Session---->     保存Session

2. Client   ----------------------IIS加工并赋Session-----> 取Session

其中: 1和2 到达服务器时间不确定,上图只说明其中一种特例出错的情况.

出现的问题

当Session超时后,再执行导出,取不到 Session , 调试发现:  当Session 超时后, 保存 Session 时, Session 的 IsNewSession 是 true .但这不重要. 重要的是,它们是两个线程,当第2 个线程早到的时候,先执行了Session 的赋值,也就是说已过了IIS赋Session的时间,再也取不到 1号线程赋的Session, 这两个线程之间不能共享值.

解决方法

因为要清空数据,所以可以换用 全局静态变量  public static Dictionary<string,StringDict>  App {get;set;} 来保存 Session 值。 其Key 是 SessionId 和 原SessionKey 在 OnceGetQuery 时,清除该Key值,即可。

改造后的代码:

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult SaveSession(string uid, FormCollection query)
        {
            if (uid.HasValue())
            {
                LifeSession.App[Session.SessionID + "_" + uid.Trim()] = query.ToStringDict();
            }
            return new JsonMsg();
        }
    public class LifeSession : IDisposable
    {
        public static Dictionary<string, StringDict> App { get; set; }

        static LifeSession()
        {
            App = new Dictionary<string, StringDict>();
        }


        List<string> keys = new List<string>();
        public object this[string SessionKey]
        {
            get
            {
                return HttpContext.Current.Session[SessionKey];
            }
            set
            {
                GodError.Check(value == null, () => "数据接收异常");
                keys.Add(SessionKey);
                HttpContext.Current.Session[SessionKey] = value;
            }
        }
        public void Dispose()
        {
            keys.All(o =>
            {
                HttpContext.Current.Session.Remove(o);
                return true;
            });
        }

        public static T OnceGetQuery<T>(string Key, T NewModel)
            where T : class
        {
            if (Key.HasValue() == false)
            {
                throw new GodError("接收Session值的 Key 值不能为空");
            }

            XmlDictionary<string, string> dict = null;

            Key = HttpContext.Current.Session.SessionID + "_" + Key;

            //10 sec
            for (int i = 0; i < 100; i++)
            {
                if (App.ContainsKey(Key))
                {
                    dict = App[Key] as StringDict;

                    if (dict == null)
                    {
                        var err = "数据接收异常 :" + App[Key].GetType().FullName;
                        LogInfo.To(InfoEnum.Error, MySessionKey.UserName.Get(), err);
                        throw new GodError(err);
                    }

                    App.Remove(Key);
                    break;
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
            if (dict == null) return null;
            var retVal = dict.DictionaryToModel(NewModel);
            GodError.Check(retVal == null, () => "Session项数据 : " + Key + "转换失败, 数据:" + dict.ToJson() + ",转换目标类型:" + typeof(T).FullName);
            return retVal;
        }
    }

 

完毕。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM