项目背景:

要求开发一个篆文识别网站,由于之前做好了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触发与否的问题的更多相关文章

  1. ASP.NET页面回车键触发Button按钮事件问题

    首先了解一下Button.UseSubmitBehavior属性. 获取或设置一个布尔值,该值指示 Button 控件使用客户端浏览器的提交机制还是 ASP.NET 回发机制. 如果该控件使用了客户端 ...

  2. 深入理解asp.net SessionState

    web Form 网页是基于HTTP的,它们没有状态, 这意味着它们不知道所有的请求是否来自同一台客户端计算机,网页是受到了破坏,以及是否得到了刷新,这样就可能造成信息的丢失. 于是, 状态管理就成了 ...

  3. Asp.Net复习篇之Asp.Net生命周期与Asp.Net页的生命周期

    Asp.Net生命周期与Asp.Net页的生命周期是一个比较重要的话题,有时可能似乎知道一些,但又说不出个所以然,而且时常把这两个概念混淆.现在也是该好好理清思路,把这两个概念搞懂. Asp.Net生 ...

  4. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)

    ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...

  5. ASP.NET 生命周期(原文翻译)

    在网上看到这篇文章,老外写的,里面很多图片挺精致,顺带翻译过来给大家分享下,英语太次好多地方都翻不过来 ASP.NET application and page life cycle Download ...

  6. ASP.NET给Table动态添加删除行,并且得到控件的值

    ASP.NET给Table动态添加控件并且得到控件的值 由于跟老师做一个小的项目,可是我自己又不太懂js,所以一直为动态建立表格并且能动态的取值和赋值感到苦恼.起初在网上找到了一些js资源,解决了动态 ...

  7. 服务器调用JS

    服务器控件调用JS一.两类JS的触发设计1.提交之前的JS -- 加js的事件例:<script language="javascript"> // 构造函数 func ...

  8. Repeater实例应用

    在实际开发过程中,涉及到数据绑定,分页,以及一对多展示数据时,遇到这样的需求我们怎么解决呢?下面以帖子展示来逐一说明. 帖子主要由两部分组成,第一部分是发帖人的原创内容部分,第二部分是用户评论部分,这 ...

  9. 点击datalist中Button按钮出现“回发或回调参数无效......”

        遇到问题: 回发或回调参数无效.在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page ...

随机推荐

  1. <script language = "javascript">, <script type = "text/javascript">和<script language = "application/javascript">(转)

          application/javascript是服务器端处理js文件的mime类型,text/javascript是浏览器处理js的mime类型,后者兼容性更好(虽然application/ ...

  2. html标签对应的英文原文(转载)

    标签  对应英文 说明 <!--> / 注释 <!DOCTYPE> document type 文档类型 <a> anchor 超链接 <abbr> a ...

  3. hdoj1257(DP-LIS/贪心)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1257 方法1--贪心: 定义一个数组f[30005],由于题目没给数据量大小,故为了保险,开到最大(高 ...

  4. np.random.seed()

    124.np.random.seed()的作用 陈容喜 关注 2018.01.11 21:36 字数 3 阅读 4460评论 0喜欢 6 今天看到一段代码时遇到了np.random.seed(),搞不 ...

  5. ECMAScript6新特性之String API

    填充到指定长度,默认使用空格填充. 一 左填充 var arr = []; for(var i=0;i<20;i++){ var str = (i+'').padStart(2,'0'); ar ...

  6. python的错误类型和异常处理

    # isinstance() # 判断实例a是否属于类b # issubclass() # 判断类a是否为类b的派生类 # 异常处理 try: pass #Exception是错误类型,能catch到 ...

  7. yaf框架安装配置

    YAF中文文档:http://www.laruence.com/manual/index.html 1 YAF框架是用C开发的,属于PHP的扩展框架: 2 YAF的性能相对于源生PHP,性能只降低不到 ...

  8. Linux 添加硬盘

    一.简介 本文介绍为Linux 添加硬盘的基本方法,同时适用于为虚拟机添加硬盘的情况.   二.添加小于2T的硬盘 1)分区 fdisk /dev/hda 2)建立文件系统 3)设置开机自动挂载磁盘 ...

  9. code1213 解的个数 扩展欧几里得

    很不错的题,加深了我对exgcd的理解 (以前我认为做题就是搜索.dp...原来数学也很重要) 理解了几个小时,终于明白了.但我什么都不打算写. 看代码吧: #include<iostream& ...

  10. Java NIO系列教程(十一) Java NIO 与 IO

    Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...