[MSDN]通过幸免下列 10 个常见 ASP.NET 缺陷使网站平稳运行

   
说实话,游戏只是自家的一个个人爱好的一边,他不会是在世的一切,不过也许在某一弹指间,在某一个可以打动到技惊四座的moment,在一个可以让我们呐喊和流泪的minute,它就是整个世界。

原文:http://www.microsoft.com/china/msdn/library/webservices/asp.net/WebAppFollies.mspx?mfr=true

   
跟所有的体育运动一样,电子竞赛的魅力是了不起的。老话说“音乐不分国界”,其实具备具有感染力的东西都是那般,电竞也不例外。再狭隘的民族主义者也不知所厝否认Faker对LOL的进献和含义,我们既然喜欢比赛,就该学会分享高品位的较量。队员的国籍所属并不可能改变比赛自己的脍炙人口程度,一味鼓吹血统论只好让LPL陷入倒退的泥坑。有人说,SKT终于是在鸟巢被三星给击倒了,他们的朝代也算是是终结了,于是理所应当的,Faker也是跌下了神坛,那毕竟是王朝的宿命,也是竞赛的魅力所在。没有人能永远一花独放,没有人能强盛,有的直接都是强者居上,新的笔录和新的神话再持续被刷新和创办,同时,那也是竞赛将一向留存和不断进化进步的原故所在。

ASP.NET 成功的里边一个原因在于它下跌了 Web
开发人士的妙法。固然你不是总结机科学博士也足以编制 ASP.NET
代码。我在工作中碰着的过多 ASP.NET 开发人士都是自学成材的,他们在编制
C# 或 Visual Basic® 往日都在编制 Microsoft® Excel®
电子表格。现在,他们在编排 Web
应用程序,总的来说,他们所做的劳作值得称扬。

   
今天要讲的东道主,是LOL界最宏伟的人,而且没有之一。近来时时听到legends
never
die那首歌,总会记念这么些在准决赛舞台上抽泣的男孩,固然他现已21了,但自身想,输掉比赛的那一刻,他自然就是个男女,无助、懊丧、悲伤、不甘那几个富有类似于伤心的心思交织在他左右,彻底粉碎了她那颗曾经最为强大的心。很三人说,三十年河东,三十年河西,曾经的李相赫打哭那么两个人,此刻只是是物换星移,主演也换了个体而已。对于观众而言,没有人乐意只见到一个朝代,人们无形中里面,激荡的就是抵抗,抗拒一个神话最好的不二法门——不过就是成立一个新的神话,因为只有一个神话终究是会令人厌倦的。

不过与力量随之而来的还有义务,即便是经验丰硕的 ASP.NET
开发人员也难免会出错。在连年的 ASP.NET
项目咨询办事中,我发现一些错误尤其简单造成缺陷不断发出。其中一些错误会影响属性。其余错误会幸免可伸缩性。有些错误还会使开发公司花费宝贵的日子来跟踪错误和意料之外的表现。

   
但对于,faker而言,他绝没有倒下。作为一个出道就终端,而且在其世界登上世界之巅的人,世界历史上也找不出好几个,所以他肯定是万幸的那么些,中国人笃信“天选之人”,认为“命由天定”,强如孟子,开篇也是“天将降大任于是人也”。如果有,那么李相赫他自然是。但大家领悟,电子竞赛是实力说话,空谈理想,一定会让祥和离开最初的轨迹。出道的第二个赛季,也就是获取最高的体面后,faker他遭遇到了惊天动地的败诉和失利,他的个体情状第几遍有了起降,随之他的军队也分崩离析,最终留下来的,唯有苦苦锲而不舍的她和他的贴心战友bengi,那么些王的女婿。接下来的故事也许我们都谙习了,卷土重来的SKT,又屡次三番两年囊括了S连串赛和大致拥有大大小小赛事的殊荣。但是,今年,他们又倒下了,但必然,二〇一九年faker的表演相对不止算职业生涯的第二春,应该只能用精妙绝伦来描写。作为已经跌落过神坛的老公,没有何样比那三回更能让她觉得轻松和最好的恬静了,他曾经经历过一次大的败诉,那两回,他只须求不断学习,以更成熟的千姿百态归来。因为如若她是faker,他就绝不会倒下。

下边是会招致 ASP.NET 生产应用程序的揭橥进程中出现问题的 10
个毛病以及可防止它们的点子。所有示例均来源于自身对真正的店铺构建真正的 Web
应用程序的切身感受,在一些境况下,我会通过介绍 ASP.NET
开发协会在付出进度中碰到的一些题目来提供相关的背景。

   
假如把faker的事迹换来任何领域,他都应当是大家的旗帜,他既谦虚又傲慢;忠于自己的老东家不放弃不扬弃;失利时候首先找自己原因,而不是一味责怪队友;他有礼数,话固然不多,但充满智慧;他着重她的每一个挑衅者,充满职业精神。像他如此的人,你要理解,也才21岁。传奇在于拼搏,至高的荣幸不是各种人都能企及的,强如UZI,pray,没有人怀疑他们的实力,去终不可能避免于无冠。拼搏,不仅是电竞精神,更是人活在海内外应有的姿态。Legends
never die,嗯,那就是传奇永不灭,那句话肯定是为faker量身定做的。

LoadControl 和输出缓存

极少有不选取用户控件的 ASP.NET
应用程序。在现身母版页在此以前,开发人士使用用户控件来提取公用内容,如页眉和页脚。尽管在
ASP.NET 2.0
中,用户控件也提供了实惠的法子来封装内容和作为以及将页面分为两个区域,这个区域的缓存能力可以独立于作为全体的页面进行支配(一种叫做段缓存的奇异输出缓存方式)。

用户控件可以行使申明的格局加载,也可以强制加载。强制加载依赖于
Page.LoadControl,它实例化用户控件并赶回控件引用。如果用户控件包涵自定义类型的积极分子(例如,公共属性),则您可以转换该引用并从你的代码访问自定义成员。
1

中的用户控件已毕名为 BackColor 的习性。以下代码加载用户控件并向
BackColor 分配一个值:

protected void Page_Load(object sender, EventArgs e)
{
// 加载用户控件并将其添加到页面中
Control control = LoadControl("~/MyUserControl.ascx");
PlaceHolder1.Controls.Add(control);
// 设置其背景色
((MyUserControl)control).BackColor = Color.Yellow;
}

上述代码实际上很简单,但却是一个等候粗心的开发人士掉进去的骗局。您能找出里面的破碎吗?

设若你猜到该问题与输出缓存有关,那么您是不错的。正如你所看到的一样,上述代码示例编译和周转都健康,不过假使尝试将以下语句(完全合法)添加到
MyUserControl.ascx 中:

<%@ OutputCache Duration="5" VaryByParam="None" %>

则当你下三遍运行该页面时,您将看到 InvalidCastException (oh joy!)
和以下错误音讯:

“无法将类型为‘System.Web.UI.PartialCachingControl’的对象转换为类型‘MyUserControl’。”

为此,此代码在未曾 OutputCache 指令时运行如常,但一旦添加了 OutputCache
指令就会出错。ASP.NET
不应有以那种艺术运行。页面(和控件)对于出口缓存应该是不可见的。那么,那意味咋样看头?

题目在于为用户控件启用输出缓存时,LoadControl
不再回来对控件实例的引用;相反,它回到对 PartialCachingControl
实例的引用,而 PartialCachingControl
可能会也恐怕不会卷入控件实例,具体取决于控件的出口是否被缓存。由此,如果开发人士调用
LoadControl
以动态加载用户控件并且为了访问控件特定的主意和性能而更换控件引用,他们必须小心进行该操作的章程,以便不管是不是具有
OutputCache 指令,代码都得以运作。


2

表达动态加载用户控件以及转换重临的控件引用的正确方法。以下是其工作原理概要:

如果 ASCX 文件缺少 OutputCache 指令,则 LoadControl 返回一个 MyUserControl 引用。Page_Load 将该引用转换为 MyUserControl 并设置控件的 BackColor 属性。

如果 ASCX 文件包括一个 OutputCache 指令并且控件的输出没有被缓存,则 LoadControl 返回一个对 PartialCachingControl 的引用,此 PartialCachingControl 的 CachedControl 属性包含对基础 MyUserControl 的引用。Page_Load 将 PartialCachingControl.CachedControl 转换为 MyUserControl 并设置该控件的 BackColor 属性。

如果 ASCX 文件包括一个 OutputCache 指令并且控件的输出被缓存,则 LoadControl 返回一个对 PartialCachingControl(其 CachedControl 属性为空)的引用。注意,Page_Load 不再继续执行操作。无法设置控件的 BackColor 属性,因为该控件的输出来源于输出缓存。换句话说,根本没有要设置属性的 MyUserControl。

不论是 .ascx 文件中是否富有 OutputCache 指令,
2
中的代码都将运行。尽管看起来复杂一点,但它会幸免烦人的失实。简单并不一而再代表不难维护。

图片 1归来页首

   
最后有的话,送给我原先的战友们,比起体育的篮球足球网球之类,LOL一定有走到尽头的那一天,人都有透支自己喜好的那一天,一个娱乐终究只可以承载一代人的回想,老玩家的无影无踪,没有新鲜血液的融入,更面临新兴娱乐的挑战,那就是她眼前的泥坑。有人说,玩lol的人少了,是因为刚起始接触那批游戏的人都老了,他们或者都有了和睦的行事和家中,有了生存中更值得爱护的事物和更值得爱的人。世界的万事事物,都是在动态发展着的,盛衰之势常有,大家不要惋惜,他将离大家而去,逐渐剥离大家的视野和生活。但作为体育的电子竞赛,其精神是绝不会倒下的。这才是legends
never die的尾声奥义,或许。

对话和出口缓存

谈到输出缓存,ASP.NET 1.1 和 ASP.NET 2.0
都存在一个神秘的题目,该问题会影响在 Windows Server™ 2003 和 IIS 6.0
上运行的服务器中的输出缓存页。我早已亲眼看到该问题在 ASP.NET
生产服务器中冒出过两回,那两回都是经过关闭输出缓冲来缓解的。后来本身驾驭到有一个比禁用输出缓存更好的解决方案。以下是本身第三回蒙受该问题时的境况。

及时的景色是那样的,某个网站(我们在此称呼 Contoso.com,它在小型 ASP.NET
Web
领域中运行公共电子商务应用程序)与自我的协会调换,抱怨他们遭逢了“跨线程”错误。使用
Contoso.com
网站的客户平常突然不见已经输入的多少,但却见到另一用户的相干数据。稍做分析即发现,跨线程这么些描述并不可信赖;“跨会话”错误越来越恰当。看起来
Contoso.com
是在对话状态中存储数据的,由于一些原因,用户会有时随机地两次三番到其他用户的对话。

本人的一个公司成员编写了一个诊断工具,用来将各类 HTTP
请求和响应的重中之主要素(包含 库克(Cook)ie
标头)记录到日志中。然后,他将该工具安装在 Contoso.com 的 Web
服务器上,并让其运作了几天。结果丰富显明。大约每 100000
个请求中会爆发一回那样的景色:ASP.NET 正确地为全新会话分配一个对话 ID
并回到 Set-Cookie 标头中的会话
ID。然后,它会在下一个紧相邻的请求中回到相同的对话 ID(即,相同的
Set-库克ie 标头),尽管该请求已经与一个实惠的对话相关联并且正确提交了
Cookie 中的会话 ID。实际上,ASP.NET
是即兴将用户从她们自己的对话中切换出去并将他们连续到其余会话。

咱俩很好奇,于是从头搜索原因。大家首先检查了 Contoso.com
的源代码,让大家倍感欣慰的是,问题不在那。接着,为了确保问题与应用程序宿主在
Web
领域无关,大家只保留一个服务器在运转,而倒闭了装有其余服务器。问题依然存在,那并不奇怪,因为大家的日志突显匹配的
Set-库克(Cook)ie 标头绝不会来自七个不等的服务器。ASP.NET
意外地生成了重新的对话 ID,那令人怀疑,因为它应用 .NET Framework
RNGCryptoServiceProvider 类生成那一个 ID,并且会话 ID 的尺寸可以保险同等的
ID 决不会转移一遍(至少在下一个万亿年内不会生成两次)。除此之外,即便RNGCryptoService(Service)Provider 错误地生成了再度的随机数字,也不可能解释 ASP.NET
为什么不堪设想地将实惠的对话 ID 替换为新的 ID(不唯一)。

凭直觉,大家决定看一下出口缓存。当 OutputCacheModule 缓存 HTTP
响应时,它必须小心不要缓存了 Set-Cookie 标头;否则,包涵新会话 ID
的缓存响应会将缓存响应的具备接收者(以及其请求生成了缓存响应的用户)连接到同一会话。大家检查了源代码;Contoso.com
在三个页面中启用了出口缓存。大家关闭了出口缓存。结果,应用程序运行数天而从未生出一个跨会话问题。此后,它运行了两年多都尚未暴发其余错误。在富有分裂应用程序和一组分歧Web 服务器的另一家商店中,大家看出完全相同的题材也破灭了。就如在
Contoso.com 一样,消除输出缓存就能解决问题。

Microsoft 后来肯定此行为来源 OutputCacheModule
中的问题。(当您读书本文时,可能已经昭示了更新。)当 ASP.NET 与 IIS 6.0
一起利用并且启用内核情势缓存时,OutputCacheModule 有时无法从它传递给
Http.sys 的缓存响应中除去 Set-Cookie
标头。上边是促成出现错误的特定事件顺序:

最近没有访问网站(因此也没有对应的会话)的用户请求一个启用了输出缓存的页面,但是其输出当前在缓存中不可用。

该请求执行用于访问用户最新创建的会话的代码,从而导致会话 ID Cookie 在响应的 Set-Cookie 标头中返回。

OutputCacheModule 向 Http.sys 提供输出,但是无法从响应中删除 Set-Cookie 标头。

Http.sys 在后续的请求中返回缓存响应,误将其他用户连接到会话。

故事的味道又是哪些吧?会话状态和水源情势输出缓存不可能混合使用。即使你在启用输出缓存的页中使用会话状态,并且应用程序在
IIS 6.0
上运行,则您需求关闭内核方式输出缓存。您仍将受益于出口缓存,然则因为基本格局输出缓存比日常输出缓存快得多,所以缓存不会一如既往有效。有关此题材的详细音讯,请参见
support.microsoft.com/kb/917072

您可以经过在页面的 OutputCache 指令中含有 VaryByParam=”*”
属性来关闭单个页面的木本形式输出缓存,固然如此做也许造成内存需要激增。另一种更安全的章程是通过在
web.config 中包蕴下列元从来关闭所有应用程序的基本情势缓存:

<httpRuntime enableKernelOutputCache="false" />

你仍能运用注册表设置来全局性地剥夺内核方式输出缓存,即禁用所有服务器的水源形式输出缓存。有关详细音讯,请参见
support.microsoft.com/kb/820129

每一遍自己听见客户报告会话暴发了费解的题目,我都会通晓她们是否在其他页面中动用了出口缓存。即使的确使用了出口缓存,并且宿主操作系统是
Windows Server
2003,我会提议她们禁用内核方式输出缓存。问题普通就会解决。假设问题并未缓解,则错误存在于代码中。警惕!

图片 2回去页首

Forms 身份验证票证生存期

您能找出以下代码的题目吗?

FormsAuthentication.RedirectFromLoginPage(username, true);

此代码看似小问题,但未能在 ASP.NET 1.x
应用程序中运用,除非应用程序中其余地方的代码抵消了此语句的负面效果。假诺你不可能确定原因,请继续读书。

FormsAuthentication.RedirectFromLoginPage 执行几个职务。首先,当
FormsAuthenticationModule
将用户重定向到登录页时,FormsAuthentication.RedirectFromLoginPage
将用户重定向到他们本来请求的页面。其次,它揭露一个身份验证票证(平时率领在
库克(Cook)ie 中,而且在 ASP.NET 1.x 中总是辅导在 库克ie
中),这些单子允许用户在约定的一段时间内维持已透过身份验证状态。

题材就在于那么些时间段。在 ASP.NET 1.x 中,向 RedirectFromLoginPage
传递另一个为 false 的参数会生出一个临时身份验证票证,该票证默许景况下在
30 分钟过后到期。(您可以运用 web.config 的 元素中的 提姆eout
属性来更改超时期限。)不过,传递另一个为 true
的参数则会发出一个千古身份验证票证,其有效期为 50
年!那样就会暴发问题,因为只要有人窃取了该身份验证票证,他们就足以在票据的有效期内尔(Nell)y用受害者的地方访问网站。窃取身份验证票证有多种格局—
在国有无线访问点探测未加密的通信、跨网站编写脚本、以物理方法访问受害者的微机等等
— 由此,向 RedirectFromLoginPage 传递 true
比禁用你的网站的安全性好持续多少。幸运的是,此题材已经在 ASP.NET 2.0
中拿走了缓解。现在的 RedirectFromLoginPage 以同样的主意接受在 web.config
中为临时和永恒身份验证票证指定的超时。

一种缓解方案是不用在 ASP.NET 1.x 应用程序的 RedirectFromLoginPage
的第二个参数中传递
true。但是那不切实际,因为登录页的风味一般是含有一个“将本人保持为报到状态”框,用户可以选中该框以收取永久而不是临时身份验证
库克ie。另一种缓解方案是应用 Global.asax(如若您愿意的话,也得以利用
HTTP 模块)中的代码段,此代码段会在富含永久身份验证票证的 Cookie
重回浏览器往日对其举办修改。


3

包罗一个那样的代码段。假诺此代码段位于 Global.asax 中,它会修改传出永久
Forms 身份验证 库克ie 的 Expires 属性,以使 库克(Cook)ie 在 24
小时后过期。通过修改注释为“新的逾期日期”的行,您可以将过期设置为你喜欢的任何日期。

您可能会觉得意外,Application_EndRequest 方法调用本地 Helper 方法
(Get库克(Cook)ieFromResponse) 来检查身份验证 Cookie 的流传响应。Helper
方法是缓解 ASP.NET 1.1 中另一个荒唐的格局,借使您使用
Http库克ieCollection 的字符串索引生成器来检查不存在的
库克ie,此错误会造成虚假 库克ie 添加到响应中。使用整数索引生成器作为
Get库克ieFromResponse 可以解决该问题。

图片 3回来页首

视图状态:无声的性能杀手

从某种意义上说,视图状态是平昔最了不起的事务。毕竟,视图状态使得页面和控件能够在回发之间维持状态。由此,您不用像在观念的
ASP
中那么编写代码,以防患在单击按钮时文本框中的文本消失,或在回发后再行查询数据库和另行绑定
DataGrid。

只是视图状态也有通病:当它增加得过大时,它便成为一个无声的属性杀手。某些控件(例如文本框)会依据视图状态作出相应判断。其余控件(越发是
DataGrid 和 GridView)则依据突显的音信量确定视图状态。假使 GridView 显示200 或 300 行数据,我会望而生畏。即使 ASP.NET 2.0 视图状态大概是 ASP.NET
1 x 视图状态的一半轻重,一个不佳的 GridView 也可以简单地将浏览器和 Web
服务器之间的连天的灵光带宽收缩 50% 或越多。

你能够透过将 EnableViewState 设置为 false
来关闭单个控件的视图状态,但一些控件(更加是
DataGrid)在不可能动用视图状态时会失去某些意义。控制视图状态的更佳解决方案是将其保存在服务器上。在
ASP.NET 1.x 中,您可以重写页面的 LoadPageStateFromPersistenceMedium 和
SavePageStateToPersistenceMedium 方法并按你喜欢的点子处理视图状态。
4

中的代码显示的重写可防患视图状态保留在隐藏字段中,而将其保存在对话状态中。当与默许会话状态进度模型一起利用时(即,会话状态存储在内存中的
ASP.NET
帮衬进度中时),在对话状态中贮存视图状态更是有效。相反,假诺会话状态存储在数据库中,则唯有测试才能显得在对话状态中保存视图状态会增强或者下落性能。

在 ASP.NET 2.0 中动用相同的点子,然而 ASP.NET 2.0
可以提供更简短的法门将视图状态保留在对话状态中。首先,定义一个自定义页适配器,其
GetStatePersister 方法再次来到 .NET Framework SessionPageStatePersister
类的一个实例:

public class SessionPageStateAdapter :
System.Web.UI.Adapters.PageAdapter
{
public override PageStatePersister GetStatePersister ()
{
return new SessionPageStatePersister(this.Page);
}
}

然后,通过将 App.browsers 文件按以下措施放入应用程序的 App_Browsers
文件夹,将自定义页适配器注册为默许页适配器:

<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.Page"
adapterType="SessionPageStateAdapter" />
</controlAdapters>
</browser>
</browsers>

(您可以将文件命名为您喜爱的其余名称,只要它的伸张名为 .browsers
即可。)此后,ASP.NET 将加载页适配器并选取重回的
SessionPageStatePersister 以保留所有页面状态,包罗视图状态。

应用自定义页适配器的一个欠缺是它全局性地作用于应用程序中的每一页。假如您更乐于将内部部分页面的视图状态保留在对话状态中而不保留其余页面的视图状态,请使用
4

中展现的措施。其余,假诺用户在同一会话中开创七个浏览器窗口,您使用该办法或者会碰着题目。

图片 4回来页首

SQL Server 会话状态:另一个属性杀手

ASP.NET 使得在数据库中蕴藏会话状态变得不难:只需切换 web.config
中的开关,会话状态就会轻松地运动到后端数据库。对于在 Web
领域中运作的应用程序来说,那是一项关键意义,因为它同意该领域中的每个服务器共享会话状态的一个公共库。添加的数据库活动下降了单个请求的习性,不过可伸缩性的增高弥补了性能的损失。

那看起来都还不错,但是你略微考虑一下下列几点,情形就会迥然不一致:

即使在使用会话状态的应用程序中,大多数页也不使用会话状态。

默认情况下,ASP.NET 会话状态管理器对每个请求中的会话数据存储执行两个访问(一个读取访问和一个写入访问),而不管请求的页是否使用会话状态。

换句话说,当您使用 SQL Server™
会话状态选项时,您在各种请求中都要付出代价(七个数据库访问)—
甚至在与会话状态无关的页面的呼吁中。那会直接对一切网站的吞吐量造成负面影响。

 

图片 5

图 5 消除不要求的对话状态数据库访问

 

那么你应该怎么做吧?很粗略:禁用不使用会话状态的页中的会话状态。那样做总是一个好法子,不过当会话状态存储在数据库中时,该措施尤其紧要。图
5 彰显怎么禁用会话状态。假若页面根本不行使会话状态,请在其 Page
指令中带有 EnableSessionState=”false”,如下所示:

<%@ Page EnableSessionState="false" ... %>

该指令阻止会话状态管理器在各种请求中读取和写入会话状态数据库。要是页面从会话状态中读取数据,但却不写入数据(即,不改动用户会话的情节),则将
EnableSessionState 设置为 ReadOnly,如下所示:

<%@ Page EnableSessionState="ReadOnly" ... %>

末尾,即使页面必要对会话状态举行读/写访问,则省略 EnableSessionState
属性或将其安装为 true:

<%@ Page EnableSessionState="true" ... %>

经过以那种方法决定会话状态,可以有限支撑 ASP.NET
只在真的需求时才访问会话状态数据库。消除不必要的数据库访问是构建高性能应用程序的首先步。

顺手说一下,EnableSessionState 属性是堂而皇之的。该属性自 ASP.NET 1.0
以来就已经展开了认证,不过本人迄今仍很少看到开发人士利用该属性。也许是因为它对于内存中的默许会话状态模型并不至极生死攸关。不过它对于
SQL Server 模型却很重大。

图片 6回到页首

未缓存的角色

以下语句平常出现于 ASP.NET 2.0 应用程序的 web.config 文件以及介绍
ASP.NET 2.0 角色管理器的以身作则中:

<roleManager enabled="true" />

但正如以上所示,该语句实在会对性能发生强烈的负面影响。您知道干什么吗?

默许情形下,ASP.NET 2.0
角色管理器不会缓存角色数据。相反,它会在历次要求规定用户属于哪个角色(若是有)时参考角色数据存储。那代表如若用户通过了身份验证,任何利用角色数据的页(例如,使用启用了安全减弱设置的网站图的页,以及选拔web.config 中基于角色的 URL
指令展开走访受到限制的页)将导致角色管理器查询角色数据存储。假如角色存储在数据库中,那么对于每个请求要求拜访八个数据库的动静,您可以轻松地清除访问八个数据库。解决方案是布署角色管理器以在
库克(Cook)ie 中缓存角色数据:

<roleManager enabled="true" cacheRolesInCookie="true" />

你可以利用其余<roleManager> 属性控制角色 Cookie 的表征 —
例如,库克ie
应保持有效的期限(以及角色管理器因而回到角色数据库的功用)。角色 Cookie
默许景况下是透过签字和加密的,由此安全风险纵然不为零,但也享有缓解。

图片 7重临页首

陈设文件属性体系化

ASP.NET 2.0
配置文件服务为维持每个用户的事态(例如个性化首选项和言语首选项)的题目提供了一个现成的缓解方案。要接纳安排文件服务,您可以定义一个
XML 配置文件,其中蕴涵要封存的意味单个用户的特性。然后,ASP.NET
编译一个富含相同属性的类,并透过抬高到页的布局文件属性提供对类实例的强类型访问。

安插文件灵活性很强,它竟然同意将自定义数据类型用作配置文件属性。不过,其中却存在一个问题,我亲眼看到该问题导致开发人士出差错。
6

包涵一个名为 Posts 的简约类,以及将 Posts
用作陈设文件属性的布署文件定义。但是,该类和该配置文件在运转时会发生出人意料的一颦一笑。您能找出其中的案由呢?

题材在于 Posts 包涵一个名为 _count
的村办字段,该字段必须举行系列化和反系列化,才能完全封冻和重新冻结类实例。然则
_count 却尚未经过序列化和反系列化,因为它是私有的,而且默认意况下
ASP.NET 配置文件管理器使用 XML
连串化对自定义类型举办种类化和反体系化。XML
系列化程序将忽略非公共成员。因而,会对 Posts
的实例举办种类化和反种类化,不过每回反种类化类实例时,_count 都会重设为
0。

一种缓解方案是使 _count
成为国有字段而非私有字段。另一种缓解方案是使用集体读/写属性封装
_count。最佳解决方案是将 Posts 标记为可连串化(使用
SerializableAttribute),并将安顿文件管理器配置为利用 .NET Framework
二进制连串化程序对类实例举办种类化和反种类化。该解决方案可以保持类本身的规划。与
XML
系列化程序分裂的是,二进制序列化程序连串化字段,而随便是不是能够访问。
7

展现 Posts 类的修复版本并鼓起浮现了改变的附带配置文件定义。

您应该牢记的一点是,倘使你使用自定义数据类型作为配置文件属性,并且该数据类型具有必须种类化才能一心连串化类型实例的非公共数据成员,则在性质评释中行使
serializeAs=”Binary”
属性并保管项目我是可体系化的。否则,将不能开展总体的种类化,并且您还将浪费时间来尝试确定安顿文件无法工作的缘由。

图片 8归来页首

线程池饱和

在执行数据库查询并伺机 15
秒或更长日子来得到重临的询问结果时,我不时对看到的莫过于的 ASP.NET
页数感到十分惊奇。(我也拭目以待了 15
分钟才看出查询结果!)有时,延迟是由于再次回到的数据量很大而造成的不可避免的无法结果;而有时,延迟则是由于数据库的筹划倒霉导致的。但无论是是什么样来头,长日子的数据库查询或其他类型的长日子
I/O 操作在 ASP.NET 应用程序中都会造成吞吐量的下挫。

有关那几个题目本身之前曾经详尽地描述过,所以在此就不再作过多的求证了。我只说一点就够了,ASP.NET
着重于个其他线程池处理请求,假诺拥有线程都被占据来等待数据库查询、Web
服务调用或其他 I/O
操作完毕,则在某个操作完毕而且释放出一个线程从前,其他请求都不可能不排队等候。当呼吁排队时,性能会急剧下跌。借使队列已满,则
ASP.NET 会使随后的乞请战败并出现 HTTP 503 错误。那种气象不是我们期待在
Web 生产服务器的生产应用程序上所乐见的。

解决方案非异步页面莫属,那是 ASP.NET 2.0
中极品却鲜为人知的作用之一。对异步页面的伸手从一个线程上开首,不过当它初始一个
I/O 操作时,它将再次来到该线程以及 ASP.NET 的 IAsyncResult
接口。操作已毕后,请求通过 IAsyncResult 文告 ASP.NET,ASP.NET
从池中领取另一个线程并做到对请求的处理。值得注意的是,当 I/O
操作暴发时,没有占用线程池线程。那样能够经过阻止其余页面(不执行较长的
I/O 操作的页面)的呼吁在队列中等待,从而显然地增进吞吐量。

你可以在 MSDN®Magazine 的 2005 年 10
月刊
中读书有关异步页面的有所音讯。I/O
绑定而不是电脑绑定且要求很长日子实施的其余页面很有可能变成异步页面。

当自己将有关异步页面的信息报告开发人士时,他们平日回答“那真是太棒了,可是本人的应用程序中并不必要它们。”对此我回答说:“你们的别样页面必要查询数据库吗?它们调用
Web 服务呢?您是不是业已检查 ASP.NET
性能计数器中有关排队请求和平均等待时间的统计新闻?即便你的应用程序至今运行如常,不过随着您的客户规模的加强,应用程序的载荷可能会大增。”

实在,绝大部分事实上的 ASP.NET 应用程序都急需异步页面。请牢记这或多或少!

图片 9归来页首

模拟和 ACL 授权

以下是一个不难易行的安排指令,可是每当在 web.config
中观看它时都让自己气象一新:

<identity impersonate="true" />

此命令在 ASP.NET
应用程序中启用客户端模拟。它将代表客户端的拜访令牌附加四处理请求的线程,以便操作系统执行的安全性检查针对的是客户端身份而不是支援进度身份。ASP.NET
应用程序很少必要效法;我的经验告诉自己,开发人员常常都是出于错误的原故而启用模拟的。以下是原因所在。

开发人员平日在 ASP.NET
应用程序中启用模拟,以便可以运用文件系统权限来限制对页面的拜访。若是 Bob没有翻动 Salaries.aspx
的权限,则开发人士将会启用模拟,以便可以由此将访问控制列表 (ACL)
设置为拒绝 鲍勃 的读取权限,阻止 鲍勃 查看
Salaries.aspx。可是存在以下隐患:对于 ACL 授权来说,模拟是不要求的。在
ASP.NET 应用程序中启用 Windows 身份验证时,ASP.NET 会自动为呼吁的每个
.aspx 页面检查 ACL
并拒绝没有读取文件权限的调用者的伸手。就算禁用了效仿,它仍会那样操作。

部分时候须要验证模拟的客体。不过你经常能够用完美的规划来防止它。例如,假定
Salaries.aspx
在数据库中询问唯有管理人员才能领略的工薪新闻。通过模拟,您可以接纳数据库权限拒绝非管理人士查询薪酬数据的能力。或者你可以不考虑模拟,并且经过为
Salaries.aspx 设置 ACL
以使非管理人士不有所读取权限,从而限制对薪俸数据的拜会。后一种方法提供的属性更佳,因为它完全防止了模拟。它也解除了不要求的数据库访问。为啥查询数据库仅出于安全原因被驳回?

顺手说一下,我已经帮衬对一个传统的 ASP
应用程序进行故障排除,该应用程序由于内存占用不受限制而定期重新起动。一个未曾经历的开发人士将目标SELECT 语句转换成了 SELECT
*,而从不设想要查询的表包蕴图像,这个图像很大还要数量很多。问题由于未检测到内存泄漏而恶化。(我的托管代码领域!)多年来运转正常的应用程序开始突然止住工作,因为原先重临一两千字节数据的
SELECT
语句现在却回到了几兆字节。若是再增加不丰富的版本控制,开发协会的生存将不得不“亢奋起来”—
那里所谓的“亢奋”,就犹如当你在夜幕要睡觉时,还不得不看着您的男女玩让人胸口痛的足球游戏一样。

答辩上,传统的内存泄漏不会发出在一齐由托管代码组成的 ASP.NET
应用程序中。但是内存使用量不足会通过强制垃圾收集更频仍地发生而影响属性。尽管是在
ASP.NET 应用程序中,也要当心 SELECT *!

图片 10回去页首

决不完全信任它 — 请设置数据库的部署文件!

作为一名顾问,我不时被问询怎么应用程序没有按预想执行。方今,有人打听我的团队为啥ASP.NET 应用程序只完毕请求文档所需吞吐量(每秒的请求数)的大体
1/100。大家原先所发现的题材是我们在无法正常运行的 Web
应用程序中发现的问题特有的 — 和我们所有人应该认真对照的教训。

咱俩运行 SQL Server Profiler
并监视此应用程序和后端的数据库之间的互相景况。在一个更可是的案例中,仅仅只是一个按钮单击,就造成数据库发生了
1,500
三个谬误。您不可能那么构建高性能的应用程序。卓绝的系统布局总是从完美的数据库设计开头。不管您的代码的频率有多高,即使它被编辑不佳的数据库所拖累,就会不起功用。

倒霉的数额访问体系布局平时来自上面的一个或六个地点:

拙劣的数据库设计(通常由开发人员设计,而不是数据库管理员)。

DataSets 和 DataAdapters 的使用 — 尤其是 DataAdapter.Update,它适用于 Windows 窗体应用程序和其他胖客户端,但是对于 Web 应用程序来说通常不理想。

具有拙劣编制计算程序、以及执行相对简单的操作需消耗很多 CPU 周期的设计糟糕的数据访问层 (DAL)。

总得先确定问题才能对其举办拍卖。确定数据访问问题的章程是运作 SQL Server
Profiler
或雷同的工具以查看后台正在举办的操作。检查应用程序和数据库之间的通信之后,性能调整才到位。尝试一下
— 您或许会对你的觉察震惊。

图片 11归来页首

结论

后天您曾经明白在生成 ASP.NET
生产应用程序进程中或许遇到的部分题目及其解决方案了。下一步是密切查阅您自己的代码并尝试防止自己在此概述的局地题目。ASP.NET
可能下跌了 Web
开发人士的奥妙,不过你的应用程序完全有理由灵活、稳定和高效。请认真考虑,防止出现新手易犯的一无所能。


8

提供了一个概括检查列表,您可以选拔它来防止本文中讲述的老毛病。您可以创设一个像样的金昌缺陷检查列表。例如:

您是否已经对包含敏感数据的配置节进行加密?

您是否正在检查并验证在数据库操作中使用的输入,是否使用了 HTML编码输入作为输出?

您的虚拟目录中是否包含具有不受保护的扩展名的文件?

若果你器重网站、承载网站的服务器以及它们所看重的后端资源的完整性,则这几个题目丰裕重大。