ASP.NET关于Session_End触发与否的问题
项目背景:
要求开发一个篆文识别网站,由于之前做好了WinForm的,把系统直接移植到WebForm上就好。工作比较简单,但确实遇到不少问题。
核心问题是:
篆文识别涉及到用户对原始图片的预处理(例如二值化、去除纹理等等),Win应用可以直接new Bitmap把过渡图都放在内存里,再用PictureBox控件显示出来即可。而Web应用里的图像显示控件是Image,只能通过设置ImageUrl来改变正在显示的图片。也就是说,要想显示图片,必须先把它存储为物理文件。
关键问题:
1.怎么获取原图,就是怎么把Image显示的图像转化为我们可以操作的Bitmap对象?
2.怎么把处理结果保存为物理文件(*.png)?
3.怎么把用户留下的临时文件清空?(前面两个都好办,这个才是关键)
解决方案:
1.两行代码轻松搞定
//获取当前图片
string path = Server.MapPath(imgShow.ImageUrl);
Bitmap img = new Bitmap(path);
2.同上
//保存临时文件
string newPath = Server.MapPath("temp/tmp.png");
img.Save(newPath);
//设置ImageUrl
imgShow.ImageUrl = "~/temp/tmp.png";
//释放资源
img.Dispose();
3.最简单的思路就是:
<1>用SessionID来作为临时文件名(区分不同用户),建立用户与临时文件的联系
<2>当用户注销时,把该用户留下的所有临时文件删掉(删除所有文件名含当前sid的文件)
详细步骤:
<1>没什么好说的,文件名 = Session.SessionID + "_abc.png" 即可
<2>问题来了,如何catch用户注销这个动作,并在这之前执行我们的代码来清理临时文件
我们找到了Global.aspx里的Session_End方法,这个理论上能够满足我们的需求(注意Session_End与Session_OnEnd的区别,这里不再详述)
我们要做的就是在Session_End方法体里面添上clearTmpFiles()处理,它可能是这样子的:
//删除本次会话产生的临时文件 //文件路径
List<string> paths = new List<string>();
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_b.png"));//二值化文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_d.png"));//纹理消除文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_search.png"));//搜索结果文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p1.png"));//图像分割文件1
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p2.png"));//图像分割文件2
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p3.png"));//图像分割文件3
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p4.png"));//图像分割文件4
//删除
foreach(string path in pathes)
File.Delete(path);
现在我们把上面的处理添进Session_End里面了,测试一下...
发现我们失败了,临时文件还在...为什么呢,可能是因为Session_End方法没有执行(该事件没有被触发)
于是疯狂地百度、Google,无果。很多人都遇到了这个问题,但好像所有人都没有解决,其中stackoverflow上面的说法就比较玄乎了,看似靠谱,经实测根本没这回事儿,链接是这个:http://stackoverflow.com/questions/4813462
。。。
不甘心的想了很久,最终找到了原因:
不是因为Session_End没有被触发,而是里面的代码有错误,Session的运行机制决定了这里面的错误不会被开发者发现(对运行时的错误不会有任何提示,也别想用什么Response.Write来尝试调试,因为根本不会有任何反应...导致的结果就是:所有人都以为Session_End没有被触发...)
Web应用的生命周期是这样的:Application_Start -> Session_Start -> Session_End -> Application_End
这就是事件被触发的顺序,A事件occur -> 执行对应方法
Session_End方法执行时遵循的原则是【一旦遇到错误,立即返回】,这就是为什么所有人都以为它没有被触发的原因(完全感受不到嘛T_T)
那么什么情况算是错误?
在Session_End里面调用Server.MapPath()就算错误,没有为什么,这是龟腚,要用它,就必须遵守它
搞清楚问题是什么就好办了,对症下药:
a.当用户连接时(Session_Start)把临时文件路径paths存在Session对象里面
b.当用户注销时候(Session_End)把paths从Session里面取出来,循环删除就好
就像这样:
void Session_Start(object sender, EventArgs e)
{
// 在新会话启动时运行的代码 //存储path
//文件路径
List<string> paths = new List<string>();
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_b.png"));//二值化文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_d.png"));//纹理消除文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_search.png"));//搜索结果文件
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p1.png"));//图像分割文件1
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p2.png"));//图像分割文件2
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p3.png"));//图像分割文件3
paths.Add(Server.MapPath("temp/" + Session.SessionID + "_p4.png"));//图像分割文件4
Session.Add("paths", paths);
} void Session_End(object sender, EventArgs e)
{
// 在会话结束时运行的代码。
// 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为
// InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer
// 或 SQLServer,则不会引发该事件。 //删除本次会话产生的临时文件
//文件路径
List<string> pathes = (List<string>)Session["paths"];
//删除
foreach(string path in pathes)
File.Delete(path);
}
测试代码:
Session.Abandon();//注销Session
//放在Button的Click里面,点一点立竿见影
经过测试没有问题
总结:
如果你的Session_End“没有被触发”,请往下看:
1.检查配置文件Web.config,如果里面没有下面的内容,就把下面的代码添进去
<sessionState mode="InProc" timeout="1"></sessionState>
//说明:<sessionState>是<system.web>的子元素,其中timeout属性表示Session的过期时间,单位是分钟,上面的意思是用户一分钟在页面无任何操作则Session失效
2.检查你的方法体里面有没有出现Server的相关调用(如Server.MapPath("xxx");),如果有,请看上面的解决方法
3.你的操作是不是只能写在Session_End里面?善后操作能不能通过用户注销或者关闭浏览器时弹出确认框点击确定来触发?如果Session_End还是不能正常工作,不妨试试这种方式
P.S.为什么不用上面提到的确认框的方式来解决这个问题?
因为浏览器兼容问题,主流的浏览器有IE、FF、GC...很难对所有浏览器考虑全面,本机用的是GC,很多JS代码都不能达到预期效果
另外,用确认框来善后需要考虑:浏览器兼容性问题、异常退出问题(用任务管理器暴力关掉、Alt + F4、任务栏右键关闭...)
用Session_End善后的优点是:无论用户是正常注销还是异常退出,其sid失效的时候都会触发Session_End,因为Session是保存在Server的,不会出现意外
ASP.NET关于Session_End触发与否的问题的更多相关文章
- ASP.NET页面回车键触发Button按钮事件问题
首先了解一下Button.UseSubmitBehavior属性. 获取或设置一个布尔值,该值指示 Button 控件使用客户端浏览器的提交机制还是 ASP.NET 回发机制. 如果该控件使用了客户端 ...
- 深入理解asp.net SessionState
web Form 网页是基于HTTP的,它们没有状态, 这意味着它们不知道所有的请求是否来自同一台客户端计算机,网页是受到了破坏,以及是否得到了刷新,这样就可能造成信息的丢失. 于是, 状态管理就成了 ...
- Asp.Net复习篇之Asp.Net生命周期与Asp.Net页的生命周期
Asp.Net生命周期与Asp.Net页的生命周期是一个比较重要的话题,有时可能似乎知道一些,但又说不出个所以然,而且时常把这两个概念混淆.现在也是该好好理清思路,把这两个概念搞懂. Asp.Net生 ...
- [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)
ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...
- ASP.NET 生命周期(原文翻译)
在网上看到这篇文章,老外写的,里面很多图片挺精致,顺带翻译过来给大家分享下,英语太次好多地方都翻不过来 ASP.NET application and page life cycle Download ...
- ASP.NET给Table动态添加删除行,并且得到控件的值
ASP.NET给Table动态添加控件并且得到控件的值 由于跟老师做一个小的项目,可是我自己又不太懂js,所以一直为动态建立表格并且能动态的取值和赋值感到苦恼.起初在网上找到了一些js资源,解决了动态 ...
- 服务器调用JS
服务器控件调用JS一.两类JS的触发设计1.提交之前的JS -- 加js的事件例:<script language="javascript"> // 构造函数 func ...
- Repeater实例应用
在实际开发过程中,涉及到数据绑定,分页,以及一对多展示数据时,遇到这样的需求我们怎么解决呢?下面以帖子展示来逐一说明. 帖子主要由两部分组成,第一部分是发帖人的原创内容部分,第二部分是用户评论部分,这 ...
- 点击datalist中Button按钮出现“回发或回调参数无效......”
遇到问题: 回发或回调参数无效.在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page ...
随机推荐
- Ubuntu安装libevent
背景: 版本: libevent 2.1.6beta linux下: 按照github官方做法: $ sudo apt-get install openssl $ mkdir build && ...
- collections之命名元组
#python中没有为我们提供可命名的tuple的类,这个类需要我们自己来定义,下面我们就自己来定义一个类,然后namedtuple就是可以通过名称来get#tuple中的元素,python中的tup ...
- swift - 画图 - 画矩形,虚线,圆和半圆
import UIKit class JYJYBouncedCouponsViewCellBgView: UIView { //一定要在这里设置 背景色, 不要再draw里面设置, override ...
- MVC4升级到MVC5未能加载文件或程序集System.Web.WebPages.Razor, Version=3.0.0.0
首先,我并没有升级他,头一天还是好好的,用的都是2.0.0.0版本的,今天来打开就出现了这个错误: 未能加载文件或程序集“System.Web.WebPages.Razor, Version=3.0. ...
- 关于session报错问题。
刚开始一直报500错误,页面不提示,也没想着去查看日志文件.好几天了,一看日志,发现是这个问题.问了一下,是session的问题. 2017/07/25 16:57:49 [error] 2300#0 ...
- 【z】Storm - the world's best IDE framework for .NET
http://www.codeproject.com/Articles/42799/Storm-the-world-s-best-IDE-framework-for-NET Storm - the w ...
- js 判断字符串是否包含某字符串,String对象中查找子字符,indexOf
var Cts = "bblText"; if(Cts.indexOf("Text") > 0 ) { alert('Cts中包含Text字符 ...
- zabbix分布式系统监视
http://blog.chinaunix.net/uid-25266990-id-3380929.html
- 如何配置JDK?
有很多人,java都下载好,却因不会配置JDK,而无法编程.今天巩固就来教大家配置JDK. 第一步:将下载好的java放在D盘(最好不要占用C盘). 第二步:右击我的电脑,选择"属性 ...
- 2018.09.21 codeforces1051D. Bicolorings(线性dp)
传送门 sb线性DP. f[i][j][0/1/2/3]f[i][j][0/1/2/3]f[i][j][0/1/2/3]表示前i列j个连通块且第i列状态为00/01/10/11时的方案总数. 这个显然 ...