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

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

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

查询条件比较多,且查询内容也可能比较多,如果使用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

12fe1df2bd45112938880ae1627dba88.png

529acd3f5ee83eb46adb01d4d6582a8c.pngView Code

public class LifeSession : IDisposable

{

List keys = new List();

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(string Key, T NewModel)

where T : class

{

if (Key.HasValue() == false)

{

throw new GodError("接收Session值的 Key 值不能为空");

}

XmlDictionary dict = null;

//10 sec

for (int i = 0; i < 100; i++)

{

if (HttpContext.Current.Session[Key] != null)

{

dict = HttpContext.Current.Session[Key] as XmlDictionary;

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:

12fe1df2bd45112938880ae1627dba88.png

529acd3f5ee83eb46adb01d4d6582a8c.pngView 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  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 App { get; set; }

static LifeSession()

{

App = new Dictionary();

}

List keys = new List();

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(string Key, T NewModel)

where T : class

{

if (Key.HasValue() == false)

{

throw new GodError("接收Session值的 Key 值不能为空");

}

XmlDictionary 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;

}

}

完毕。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐