ASP.NET常被忽视的一些细节
前段时间碰到一个问题:为什么在ASP.NET程序中定时器有时候会不工作?
这个问题看起来很奇怪,代码好像也没错,但就是结果与预期不一致。
其实这里是ASP.NET应用程序中一个容易被忽略的经节。
后来想想,类似这样的细节问题何止这一个,我今天就把我能想到的容易被忽视的细节问题都写出来,希望大家小心这些问题。
想到我以前的博客中也零散的说过了一些,所以这篇博客中也把它们列出来了,
不过,对于以前谈过的内容,这里将只会简略地说明。
HttpContext.Current并非无处不在
这个问题是我上个月的博客中提到的问题,
原文链接:http://www.cnblogs.com/fish-li/archive/2013/04/06/3002940.html
在以下情形中访问HttpContext.Current将会返回null
1. 定时器的回调。
2. Cache的移除通知。
3. APM模式下异步完成回调。
4. 主动创建线程或者将任务交给线程池来执行。
所以,在写类库时,请注意这个问题。
Application_Start的异常与IIS经典模式
在IIS6或者II7的经典模式下运行ASP.NET程序时,如果Application_Start事件中抛出了未捕获异常,
那么 这个异常将显示一次。
关于这个问题的更多细节介绍请点击:http://www.cnblogs.com/fish-li/archive/2013/03/24/2979780.html
QueryString,Form允许重复的KEY
我们经常见到的集合,例如:Hashtable, Dictionary,它们都要求KEY是唯一的,然而,
HttpRequest的QueryString,Form集合实例却 允许KEY重复,当遇到KEY重复时,通过索引器访问集合时,
会将KEY对应的所有元素值用逗号拼接起来。
为什么会这样,因为这二个集合的类型是NameValueCollection,类似的,Headers集合也是这样。
由于这个特殊性与我们常见的情形不一致,所以我们需要注意这个差别,当然了,有些时候我们还可以利用这个行为实现一些特殊的需求,
关于这个细节的更多介绍请参考:http://www.cnblogs.com/fish-li/archive/2011/12/06/2278463.html ,
在这篇博客中,还介绍了HttpRequest的二个索引器也是值得我们注意的。
ashx的重用问题
很多ASP.NET的开发人员都应该创建过ashx文件,例如下面这个:
public class Handler1 : IHttpHandler {
public bool IsReusable {
get {
return false;
}
}
我想不少人会对IsReusable这个属性感到好奇,于是去查一下IHttpHandler的定义,找到这个解释,
// 摘要:
// 获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。
//
// 返回结果:
// 如果 System.Web.IHttpHandler 实例可再次使用,则为 true;否则为 false。
bool IsReusable { get; }
看到可以重用,有些对性能关注的人可能会将它修改为返回true,其实改成什么都一样,因为它不起作用。
不起作用的原因在这篇博客中有说明:http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html
当前登录用户信息有时获取不到
在ASP.NET中,提供了以下方法让我们获取当前用户的信息,例如:
if( HttpContext.Current != null ) {
// 检查当前用户是否已为一个已登录用户
bool isAuthenticated = HttpContext.Current.Request.IsAuthenticated;
// 获取当前请求的用户名
string userName = HttpContext.Current.User.Identity.Name;
}
不过,这段代码放在不同的地方,效果却截然不同。
最近就遇到一个问题:有人问我为什么总是取不当前用户的用户名。
网站采用的是Windows身份认证,因此,所有的请求都是经过IIS认证过的,
理论上说,变量isAuthenticated应该返回true,而userName应该是当前请求的用户名(Windows登录名),然而呢,在调试时,
isAuthenticated的值是false, 后面的代码直接抛出一个空引用异常,因为User对象为null,太奇怪了,是吗?
当出现这种情况时,我们应该检查代码在哪里被调用的。
结果在我的追问下,发现代码是在一个HttpModule中调用的,且发生在订阅HttpApplication的BeginRequest事件中。
找到这里,原因也就找到了,此时(在这个阶段)还没有经过ASP.NET的身份认证检查,
User对象对象根本就没有构造出来,现在去访问,当然取不到结果。
凭良心说,这个还真算不上ASP.NET留给我们的坑,只怪一些人对管线事件不了解。
Timer可能会不起作用
有时候我们会遇到一些诸如执行定时任务的需求,于是有些人可能会想到用定时器来实现,
在.net framework中,有二个Timer类型可以用于ASP.NET环境中,不过,Timer有可能会不起作用,
具体表现情况也会让你难以描述:不知道在什么时候定时器就停止工作了。
这个问题很奇怪:当你在调试模式下,定时器是一直能正常工作的,但当你把网站部署起来,
运行时间久一些,便会发现定时器没有正常工作。
为什么会这样呢?
答案是:当网站在一段时间没有请求后,进程会被IIS回收(释放)。
所以,在ASP.NET程序不适合执行【长久性】的定时任务,除非你能接受定时器会停止工作。
类似的问题还有:在ASP.NET程序中将某个方法做为回调方法传给Win32程序,发现回调没有响应。
正是由于这个原因,建议将长久性的定时任务或者接收Win32回调的程序用Windows Service的程序来实现
Session与复杂数据类型
Session有三种工作模式,拿ASPX页面来说,EnableSessionState指令有三个可选值:true, false, ReadOnly
EnableSessionState="false",这个容易理解:不使用Session。
EnableSessionState="ReadOnly",从字面上来说,就是Session是只读的。
只读的控件不允许用户修改,然而Session的只读模式是说:你可以改,但我不保存你的修改。
这样理解没有问题吧。
EnableSessionState="true",表示Session支持可读可写。
当你更新了Session的内容之后,当前会话的所有Session数据将会被重新保存。
进程内Session容易丢失,且不支持多台Web服务器共享数据,因此选择这种保存方法的人不多,
大多数人会选择状态服务或者SQL Server来保存,那么这里就有一个问题需要关注了:
当Session模式是EnableSessionState="true"时,如果你访问了一个复杂对象(不是系统值类型也不是字符串),
不管你有没有修改它,Session的保存操作都会执行。
对于进程外Session,保存操作意味着需要执行序列化,还可以会有网络传输的开销,它们会影响性能。
如果上面的描述不容易理解的话,请看下面的示例代码:
string sessionValue = Session["s2"] as string;
if( sessionValue == null ) {
Session["s2"] = "Fish Li";
sessionValue = Session["s2"] as string;
}
当这个页面首次运行时,Session被修改了,因此会有保存的操作发生。但是后面的访问就不会有保存的动作。
再看另一段代码:
// TestData是一个自定义类型。
TestData sessionValue = Session["s1"] as TestData;
if( sessionValue == null ) {
Session["s1"] = new TestData { IntValue = 5, StrValue = "Fish Li" };
sessionValue = Session["s1"] as TestData;
}
此时每次执行这段代码时,都会有保存操作发生(只要是EnableSessionState="true")。
我再重申一遍:这个问题只有当EnableSessionState="true",且访问复杂对象(不是系统值类型也不是字符串)才会发生。
对于进程内Session来说,这个问题的影响不大,但是对于进程外Session来说,会对性能产生一些影响,
到底有多大的影响,要根据Session的数据量以及用户的并发度来决定。
列出这个问题只是想告诉大家:如果你确实需要使用Session,请尽量在Session中保存【不可变】的简单数据,
尤其是不要保持Session的默认设置(EnableSessionState="true")。
检验这个问题的方法是:实现一个自定义的SessionStateStoreProviderBase派生类,然后调试观察。
SessionStateItemCollection的二个索引器也会给你一个答案。
DateTime的JSON序列化
在SP.NET3.5中,微软为ASP.NET为设计了一个JSON序列化的工具类,
System.Web.Script.Serialization.JavaScriptSerializer,这个类的使用很广泛,而且比WCF的那个JSON序列化类的兼容性要好。
不过,这个类有一个问题,在序列化DataTime类型时,它生成的结果会让所有人感觉别扭,
其实序列化的结果表现形式还个小问题,在前端写个转换函数就能解决,
然而,如果你需要 用序列化和反序列化的方法来做对象的持久化,就会遇到问题,例如下面的代码:
DateTime dt1 = DateTime.Now;
JavaScriptSerializer jss = new JavaScriptSerializer(); string json = jss.Serialize(dt1);
DateTime dt2 = jss.Deserialize<DateTime>(json); context.Response.Write(dt1 == dt2);
浏览器显示的结果会让人感到很意外,竟然是:False
出现这个原因与JavaScript的时间格式有关,它使用了UTC时间,
不过,这个理由让人感到难以接受,毕竟其它的反序列化都能还原对象,例如二进制序列化和XML都能正确的还原对象。
没办法,这里只能算是个坑了,所以,如果你要做对象的持久化操作,尽量不要选择JSON序列化。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
如果,您希望更容易地发现我的新博客,不妨点击一下右下角的【关注 Fish Li】。
因为,我的写作热情也离不开您的肯定支持。
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是Fish Li 。
ASP.NET常被忽视的一些细节的更多相关文章
- .NET框架设计—常被忽视的C#设计技巧
.NET框架设计—常被忽视的C#设计技巧 阅读目录: 1.开篇介绍 2.尽量使用Lambda匿名函数调用代替反射调用(走进声明式设计) 3.被忽视的特性(Attribute)设计方式 4.扩展方法让你 ...
- .NET框架设计(常被忽视的框架设计技巧)
阅读目录: 1.开篇介绍 2.元数据缓存池模式(在运行时构造元数据缓存池) 2.1.元数据设计模式(抽象出对数据的描述数据) 2.2.借助Dynamic来改变IOC.AOP动态绑定的问题 2.3.元数 ...
- .NET框架设计—常被忽视的框架设计技巧
阅读目录: 1.开篇介绍 2.元数据缓存池模式(在运行时构造元数据缓存池) 2.1.元数据设计模式(抽象出对数据的描述数据) 2.2.借助Dynamic来改变IOC.AOP动态绑定的问题 2.3.元数 ...
- 不该被忽视的CoreJava细节(一)
一.系列文章导言 <不该被忽视的CoreJava细节>系列文章将会持续更新.我希望自己通过这一系列文章的写作,能与读者一起进步,逐步完善对Java体系结构的了解. 二.本期关注点 几乎翻看 ...
- 大坑!常被忽视又不得不注意的小细节——%I64,%lld与cout(转载)
原地址:http://blog.csdn.net/thunders01/article/details/38879553 刚刚被坑完,OI一年了才知道%I64和%lld有区别(做题会不会太少),lon ...
- .NET框架设计(常被忽视的C#设计技巧)
阅读目录: 1.开篇介绍 2.尽量使用Lambda匿名函数调用代替反射调用(走进声明式设计) 3.被忽视的特性(Attribute)设计方式 4.扩展方法让你的对象如虎添翼(要学会使用扩展方法的设计思 ...
- ASP.NET常见面试题及答案(130题)
1.C#中 property 与 attribute(抽像类)的区别,他们各有什么用处,这种机制的好处在哪里?答:property和attribute汉语都称之为属性.不过property是指类向外提 ...
- 微软推荐的130道ASP.NET常见面试题及答案
1. 简述 private. protected. public. internal 修饰符的访问权限. 答 . private : 私有成员, 在类的内部才可以访问. protected : 保护成 ...
- 【转载】 .NET框架设计—常被忽视的C#设计技巧
阅读目录: 1.开篇介绍 2.尽量使用Lambda匿名函数调用代替反射调用(走进声明式设计) 3.被忽视的特性(Attribute)设计方式 4.扩展方法让你的对象如虎添翼(要学会使用扩展方法的设计思 ...
随机推荐
- AOP编程
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- 使用jQuery的attr方法来修改onclick值
这篇文章主要介绍了通过jQuery的attr修改onclick值的解决方法 ,需要的朋友可以参考下 var js = "alert('B:' + this.id); return false ...
- zookeeer 集群和伪集群模式
环境变量设置: # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # U ...
- 只启动一个zookeeper配置 server1只需要配置一个
[root@wx03 conf]# cat zoo.cfg # The number of milliseconds of each tick tickTime=2000 # The number o ...
- Android中通过耳机按键控制音乐播放的实现
今天在研究Android中实现Android 4.2.2源码中的Music应用的源码,关于通过耳机按键控制音乐播放的实现,有点好奇,就仔细分析了一下源码, 主要由 MediaButtonIntentR ...
- Eclipse用法和技巧二十七:定义自己的快速联想词
某天在调试代码的时候,虽然是android的project还是习惯的输入syso,然后在ALT+/一下.旁边的同事就问了一下,这个log打印输出的tag是什么.接着又问了为什么syso能够智能联想出这 ...
- Wireshark安装、简单使用、过滤器简介
1.简介 Wireshark是一款非常著名的网络嗅探器,它的前身是Ethereal.Wireshark是一款免费的软件,只需要从官网下根据不同的系统(window,linux等)下载其对应的安装文件即 ...
- Ajax技术——带进度条的文件上传
1.概述 在实际的Web应该开发或网站开发过程中,经常需要实现文件上传的功能.在文件上传过程中,经常需要用户进行长时间的等待,为了让用户及时了解上传进度,可以在上传文件的同时,显示文件的上传进度条.运 ...
- 不用SWIG,Go使用C++代码的方式
将C++代码用C作一次封装,就可以让Go调用了. 这是一个C++头文件: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #ifndef CGO_CPPGO_C ...
- 开源数据库连接池之Tomcat内置连接池
本篇介绍几种开源数据库连接池,同时重点讲述如何使用Tomcat服务器内置的数据库连接池. 之前的博客已经重点讲述了使用数据库连接池的好处,即是将多次创建连接转变为一次创建而使用长连接模式.这样能减少数 ...