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