通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行(转载)

news/2024/5/20 2:47:44/文章来源:https://blog.csdn.net/weixin_34248118/article/details/90118484

LoadControl 和输出缓存LoadControl 和输出缓存
会话和输出缓存会话和输出缓存
Forms 身份验证票证生存期Forms 身份验证票证生存期
视图状态:无声的性能杀手视图状态:无声的性能杀手
SQL Server 会话状态:另一个性能杀手SQL Server 会话状态:另一个性能杀手
未缓存的角色未缓存的角色
配置文件属性序列化配置文件属性序列化
线程池饱和线程池饱和
模拟和 ACL 授权模拟和 ACL 授权
不要完全信赖它  请设置数据库的配置文件!不要完全信赖它 — 请设置数据库的配置文件!
结论

ASP.NET 成功的其中一个原因在于它降低了 Web 开发人员的门槛。即便您不是计算机科学博士也可以编写 ASP.NET 代码。我在工作中遇到的许多 ASP.NET 开发人员都是自学成材的,他们在编写 C# 或 Visual Basic® 之前都在编写 Microsoft® Excel® 电子表格。现在,他们在编写 Web 应用程序,总的来说,他们所做的工作值得表扬。

但是与能力随之而来的还有责任,即使是经验丰富的 ASP.NET 开发人员也难免会出错。在多年的 ASP.NET 项目咨询工作中,我发现某些错误特别容易导致缺陷不断发生。其中某些错误会影响性能。其他错误会抑制可伸缩性。有些错误还会使开发团队耗费宝贵的时间来跟踪错误和意外的行为。

下面是会导致 ASP.NET 生产应用程序的发布过程中出现问题的 10 个缺陷以及可避免它们的方法。所有示例均来自我对真实的公司构建真实的 Web 应用程序的亲身体验,在某些情况下,我会通过介绍 ASP.NET 开发团队在开发过程中遇到的一些问题来提供相关的背景。

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中的代码都将运行。虽然看起来复杂一点,但它会避免烦人的错误。简单并不总是代表易于维护。

会话和输出缓存

谈到输出缓存,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 请求和响应的关键要素(包括 Cookie 标头)记录到日志中。然后,他将该工具安装在 Contoso.com 的 Web 服务器上,并让其运行了几天。结果非常明显。大概每 100000 个请求中会发生一次这样的情况:ASP.NET 正确地为全新会话分配一个会话 ID 并返回 Set-Cookie 标头中的会话 ID。然后,它会在下一个紧相邻的请求中返回相同的会话 ID(即,相同的 Set-Cookie 标头),即使该请求已经与一个有效的会话相关联并且正确提交了 Cookie 中的会话 ID。实际上,ASP.NET 是随机将用户从他们自己的会话中切换出去并将他们连接到其他会话。

我们很惊讶,于是开始寻找原因。我们首先检查了 Contoso.com 的源代码,让我们感到欣慰的是,问题不在那。接着,为了确保问题与应用程序宿主在 Web 领域无关,我们只保留一个服务器在运行,而关闭了所有其他服务器。问题仍然存在,这并不意外,因为我们的日志显示匹配的 Set-Cookie 标头绝不会来自两个不同的服务器。ASP.NET 意外地生成了重复的会话 ID,这令人难以置信,因为它使用 .NET Framework RNGCryptoServiceProvider 类生成这些 ID,并且会话 ID 的长度足以确保相同的 ID 决不会生成两次(至少在下一个万亿年内不会生成两次)。除此之外,即使 RNGCryptoServiceProvider 错误地生成了重复的随机数字,也无法解释 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,我会建议他们禁用内核模式输出缓存。问题通常就会迎刃而解。如果问题没有解决,则错误存在于代码中。警惕!

Forms 身份验证票证生存期

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

FormsAuthentication.RedirectFromLoginPage(username, true);

此代码看似没有问题,但决不能在 ASP.NET 1.x 应用程序中使用,除非应用程序中其他位置的代码抵消了此语句的负面作用。如果您不能确定原因,请继续阅读。

FormsAuthentication.RedirectFromLoginPage 执行两个任务。首先,当 FormsAuthenticationModule 将用户重定向到登录页时,FormsAuthentication.RedirectFromLoginPage 将用户重定向到他们原来请求的页面。其次,它发布一个身份验证票证(通常携带在 Cookie 中,而且在 ASP.NET 1.x 中总是携带在 Cookie 中),这个票证允许用户在预定的一段时间内保持已经过身份验证状态。

问题就在于这个时间段。在 ASP.NET 1.x 中,向 RedirectFromLoginPage 传递另一个为 false 的参数会发出一个临时身份验证票证,该票证默认情况下在 30 分钟之后到期。(您可以使用 web.config 的 元素中的 Timeout 属性来更改超时期限。)然而,传递另一个为 true 的参数则会发出一个永久身份验证票证,其有效期为 50 年!这样就会发生问题,因为如果有人窃取了该身份验证票证,他们就可以在票证的有效期内使用受害者的身份访问网站。窃取身份验证票证有多种方法 — 在公共无线访问点探测未加密的通信、跨网站编写脚本、以物理方式访问受害者的计算机等等 — 因此,向 RedirectFromLoginPage 传递 true 比禁用您的网站的安全性好不了多少。幸运的是,此问题已经在 ASP.NET 2.0 中得到了解决。现在的 RedirectFromLoginPage 以相同的方式接受在 web.config 中为临时和永久身份验证票证指定的超时。

一种解决方案是决不在 ASP.NET 1.x 应用程序的 RedirectFromLoginPage 的第二个参数中传递 true。但是这不切实际,因为登录页的特点通常是包含一个“将我保持为登录状态”框,用户可以选中该框以收到永久而不是临时身份验证 Cookie。另一种解决方案是使用 Global.asax(如果您愿意的话,也可以使用 HTTP 模块)中的代码段,此代码段会在包含永久身份验证票证的 Cookie 返回浏览器之前对其进行修改。

图 3 包含一个这样的代码段。如果此代码段位于 Global.asax 中,它会修改传出永久 Forms 身份验证 Cookie 的 Expires 属性,以使 Cookie 在 24 小时后过期。通过修改注释为“新的过期日期”的行,您可以将超时设置为您喜欢的任何日期。

您可能会觉得奇怪,Application_EndRequest 方法调用本地 Helper 方法 (GetCookieFromResponse) 来检查身份验证 Cookie 的传出响应。Helper 方法是解决 ASP.NET 1.1 中另一个错误的方法,如果您使用 HttpCookieCollection 的字符串索引生成器来检查不存在的 Cookie,此错误会导致虚假 Cookie 添加到响应中。使用整数索引生成器作为 GetCookieFromResponse 可以解决该问题。

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

从某种意义上说,视图状态是有史以来最伟大的事情。毕竟,视图状态使得页面和控件能够在回发之间保持状态。因此,您不必像在传统的 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 中显示的方法。另外,如果用户在同一会话中创建多个浏览器窗口,您使用该方法可能会遇到问题。

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

ASP.NET 使得在数据库中存储会话状态变得简单:只需切换 web.config 中的开关,会话状态就会轻松地移动到后端数据库。对于在 Web 领域中运行的应用程序来说,这是一项重要功能,因为它允许该领域中的每个服务器共享会话状态的一个公共库。添加的数据库活动降低了单个请求的性能,但是可伸缩性的提高弥补了性能的损失。

这看起来都还不错,但是您略微考虑一下下列几点,情况就会有所不同:

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

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

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

a

图 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 模型却很重要。

未缓存的角色

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

<roleManager enabled="true" />

但正如以上所示,该语句确实会对性能产生明显的负面影响。您知道为什么吗?

默认情况下,ASP.NET 2.0 角色管理器不会缓存角色数据。相反,它会在每次需要确定用户属于哪个角色(如果有)时参考角色数据存储。这意味着一旦用户经过了身份验证,任何利用角色数据的页(例如,使用启用了安全裁减设置的网站图的页,以及使用 web.config 中基于角色的 URL 指令进行访问受到限制的页)将导致角色管理器查询角色数据存储。如果角色存储在数据库中,那么对于每个请求需要访问多个数据库的情况,您可以轻松地免除访问多个数据库。解决方案是配置角色管理器以在 Cookie 中缓存角色数据:

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

您可以使用其他<roleManager> 属性控制角色 Cookie 的特征 — 例如,Cookie 应保持有效的期限(以及角色管理器因此返回角色数据库的频率)。角色 Cookie 默认情况下是经过签名和加密的,因此安全风险虽然不为零,但也有所缓解。

配置文件属性序列化

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" 属性并确保类型本身是可序列化的。否则,将无法进行完整的序列化,并且您还将浪费时间来尝试确定配置文件无法工作的原因。

线程池饱和

在执行数据库查询并等待 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 应用程序都需要异步页面。请切记这一点!

 

模拟和 ACL 授权

以下是一个简单的配置指令,但是每当在 web.config 中看到它时都让我眼前一亮:

<identity impersonate="true" />

此指令在 ASP.NET 应用程序中启用客户端模拟。它将代表客户端的访问令牌附加到处理请求的线程,以便操作系统执行的安全性检查针对的是客户端身份而不是辅助进程身份。ASP.NET 应用程序很少需要模拟;我的经验告诉我,开发人员通常都是由于错误的原因而启用模拟的。以下是原因所在。

开发人员经常在 ASP.NET 应用程序中启用模拟,以便可以使用文件系统权限来限制对页面的访问。如果 Bob 没有查看 Salaries.aspx 的权限,则开发人员将会启用模拟,以便可以通过将访问控制列表 (ACL) 设置为拒绝 Bob 的读取权限,阻止 Bob 查看 Salaries.aspx。但是存在以下隐患:对于 ACL 授权来说,模拟是不必要的。在 ASP.NET 应用程序中启用 Windows 身份验证时,ASP.NET 会自动为请求的每个 .aspx 页面检查 ACL 并拒绝没有读取文件权限的调用者的请求。即使禁用了模拟,它仍会这样操作。

有的时候需要证明模拟的合理性。但是您通常可以用良好的设计来避免它。例如,假定 Salaries.aspx 在数据库中查询只有管理人员才能知道的工资信息。通过模拟,您可以使用数据库权限拒绝非管理人员查询工资数据的能力。或者您可以不考虑模拟,并且通过为 Salaries.aspx 设置 ACL 以使非管理人员不具有读取权限,从而限制对工资数据的访问。后一种方法提供的性能更佳,因为它完全避免了模拟。它也消除了不必要的数据库访问。为什么查询数据库仅由于安全原因被拒绝?

顺便说一下,我曾经帮助对一个传统的 ASP 应用程序进行故障排除,该应用程序由于内存占用不受限制而定期重新启动。一个没有经验的开发人员将目标 SELECT 语句转换成了 SELECT *,而没有考虑要查询的表包含图像,这些图像很大而且数目很多。问题由于未检测到内存泄漏而恶化。(我的托管代码领域!)多年来运行正常的应用程序开始突然停止工作,因为以前返回一两千字节数据的 SELECT 语句现在却返回了几兆字节。如果再加上不充分的版本控制,开发团队的生活将不得不“亢奋起来”— 这里所谓的“亢奋”,就如同当您在晚上要睡觉时,还不得不看着您的孩子玩令人厌烦的足球游戏一样。

理论上,传统的内存泄漏不会发生在完全由托管代码组成的 ASP.NET 应用程序中。但是内存使用量不足会通过强制垃圾收集更频繁地发生而影响性能。即使是在 ASP.NET 应用程序中,也要警惕 SELECT *!

 

不要完全信赖它 — 请设置数据库的配置文件!

作为一名顾问,我经常被询问为何应用程序没有按预期执行。最近,有人询问我的团队为何 ASP.NET 应用程序只完成请求文档所需吞吐量(每秒的请求数)的大约 1/100。我们以前所发现的问题是我们在不能正常运行的 Web 应用程序中发现的问题特有的 — 和我们所有人应该认真对待的教训。

我们运行 SQL Server Profiler 并监视此应用程序和后端的数据库之间的交互情况。在一个更极端的案例中,仅仅只是一个按钮单击,就导致数据库发生了 1,500 多个错误。您不能那样构建高性能的应用程序。良好的体系结构总是从良好的数据库设计开始。不管您的代码的效率有多高,如果它被编写不佳的数据库所拖累,就会不起作用。

糟糕的数据访问体系结构通常源于下面的一个或多个方面:

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

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

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

必须先确定问题才能对其进行处理。确定数据访问问题的方式是运行 SQL Server Profiler 或等效的工具以查看后台正在执行的操作。检查应用程序和数据库之间的通信之后,性能调整才完成。尝试一下 — 您可能会对您的发现大吃一惊。




本文转自高海东博客园博客,原文链接:http://www.cnblogs.com/ghd258/archive/2006/07/15/451386.html,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_798939.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做一个网站需要多少花费?

我是今年清明节&#xff08;4.5&#xff09;之后开始做自己的网站&#xff0c;这周&#xff08;6.20号左右&#xff09;网站正式上线。由于在上班&#xff0c;利用下班时间和周末&#xff0c;陆陆续续做了3个月&#xff0c;勉强做了个能打开&#xff0c;有内容&#xff08;对&a…

搭建自己的ebook网站

2019独角兽企业重金招聘Python工程师标准>>> 搭建自己的电子书网站 下载代码方式&#xff1a; githubgitee项目介绍 项目使用spring-boot开发&#xff0c;使用maven主要分为manager&#xff0c;common&#xff0c;client模块。 manager 管理模块 参考 client 客户端…

注册网站域名多少钱_网站注册域名要知道什么?注意什么?

网站注册域名要知道什么&#xff1f;注意什么&#xff1f;网站注册域名的问题咱们聚名网已经跟大家说了很多了&#xff0c;但是注册好域名之后&#xff0c;接下来该做哪些&#xff0c;咱们聚名网还没和大家细细的说&#xff0c;一般网站注册好之后需要做哪些事情呢&#xff1f;…

iis网站属性在哪_IIS在使用URL Rewrite 重写的时候由于目标服务器响应时间长,导致出现502问题解决...

按照正常来说&#xff0c;再iis网站界面会有一个application requestrouting cache 的 icon&#xff0c; 可以点击 设置timeout 但是这里没有显示找到了 官方说明可以用命令行解决这个问题https://blogs.iis.net/richma/502-3-bad-gateway-the-operation-timed-out-with-iis-ap…

网站可行性报告范文_孝感做可行性报告本地立项范文

孝感做可行性报告本地立项范文 公司名称&#xff1a; 环建工程有限公司 公司介绍&#xff1a; 环建工程有限公司致力于发展成为一家业界的化服务公司&#xff0c;专注于为客户提供化的服务。主要经营范围项目建议书、可行性报告、资金申请报告、项目申请报告、商业计划书、计划…

springboot访问静态页面404_网站404是什么原因,网站404怎么解决

404对于SEO的影响是非常严重的。一旦处理不当网站就会被K&#xff0c;轻微的是降权。所以死链接的处理一定要用正规的处理方式。而更加重要的就是预防404&#xff0c;因为企赢SEO优化那么多网站从来没有出现过死链接这东西。首先我们要知道404出现的原因有哪些&#xff0c;才能…

5个在线资源搜索网站,用的人求生欲很强!

分享5个平时经常用的在线资源搜索网站&#xff0c;只有你想不到没有你找不到的资源&#xff01;一起来了解下吧&#xff01; 西林街搜索http://www.xilinjie.com/ 强烈推荐的资源搜索网站&#xff1a;视频、文库&#xff08;文档、古籍、专业书籍、电子书[PDF、ePub、Mobi等格…

这6个免费精品自学网站,提升能力让你月薪2w(值得收藏)

学习是我们一辈子的事情&#xff0c;永远不会毕业的&#xff0c;我们只有不断的学习&#xff0c;不断的提升自己&#xff0c;才能成为人上人&#xff0c;这时候肯定有人会问&#xff0c;那么应该如何学习呢&#xff1f;我认为这取决于三颗心&#xff1a;"一信心、二决心、…

大神偷偷收藏的7个自学网站,质量高且免费,请低调使用

很多年轻人都不甘于现状&#xff0c;总想着努力提升自己&#xff0c; 摆脱当前困境。 那么下面我就给大家分享&#xff0c;大神也偷偷收藏的7个自学网站&#xff0c;质量高且免费&#xff0c;每天坚持学习半小时&#xff0c;能让你变得更优秀。 01*学堂在线 看到这个名字就激发…

实用帖!分享5个素材丰富的资源网站

如果你是从事设计相关的工作者&#xff0c;那么这篇干货贴你可得收藏好了&#xff0c;我保证你能用得上&#xff01; 废话不多说&#xff0c;直接上干货&#xff01; 1、FoodiesFeed 这个网站主打饮食、蔬果等&#xff0c;吃货设计师的最佳站点。 如果需要各种各样的美食图片…

php德育元素,wsb_v2.0 智睿学校网站系统定位教育网行开发的 , 首页 概况 校园新闻 德育教学 WEB(ASP,PHP,...) 238万源代码下载- www.pudn.com...

文件名称: wsb_v2.0下载收藏√ [5 4 3 2 1 ]开发工具: EasyLanguage易语言文件大小: 6753 KB上传时间: 2013-03-27下载次数: 2详细说明&#xff1a;智睿学校网站系统定位教育网行开发的系统&#xff0c;网站首页 学校概况 校园新闻 德育教学 校园风彩 资源下载 求贤纳士 成…

网站发布到远程服务器时文件系统,php 文件上传到远程服务器

php 文件上传到远程服务器 内容精选换一换将文件上传至Windows云服务器一般会采用MSTSC远程桌面连接的方式。本节为您介绍本地Windows计算机通过远程桌面连接&#xff0c;上传文件至Windows云服务器的操作方法。Windows云服务器可以访问公网。在本地Windows计算机上&#xff0c…

匀速建站 华为云_笔记软件对比与使用云服务建立个人云笔记

此文作为自己的经验记录&#xff0c;也给经常使用笔记的同学们一些参考。以前人们使用笔记本记录想法&#xff0c;随着计算机和手机端广泛使用&#xff0c;越来越多的人使用云笔记&#xff0c;可以多端同步&#xff0c;有云备份不怕丢&#xff0c;但是各种笔记或多或少有些不便…

简单几步让网站支持https,windows iis下https配置方式

1.https证书的分类 SSL证书没有所谓的"品质"和"等级"之分&#xff0c;只有三种不同的类型。 SSL证书需要向国际公认的证书证书认证机构&#xff08;简称CA&#xff0c;Certificate Authority&#xff09;申请。 CA机构颁发的证书有3种类型&#xff1a; 域名…

无法访问此网站 localhost 拒绝了我们的连接请求

解决方法 进入 SQL Server 管理环境中 展开 数据库 – BOOK 1 右击 BOOK – 属性 &#xff0c;弹出BOOK的数据库属性画面 2 在选项页下面&#xff0c;点选 权限 3 在用户或角色列表中&#xff0c;点选 NT AUTHORITY/NETWORK SERVICE 4 在下面 NT AUTHORITY/NETWORK SERVICE …

[解决]Jupyter notebook 无法访问此网站localhost拒绝了我们的连接请求

问题描述&#xff1a; 每次打开jupyter notebook的时候&#xff0c;想要自己写项目或者查看已有项目时&#xff0c;都无法编译运行&#xff0c;刷新jupyter notebook目录页后&#xff0c;页面会变成如下图&#xff1a; 报错如下&#xff1a; 解决思路&#xff1a; 首先要先知…

JAVA爬需要账号登录的网_如何用 Python 爬取需要登录的网站?

最近我必须执行一项从一个需要登录的网站上爬取一些网页的操作。它没有我想象中那么简单&#xff0c;因此我决定为它写一个辅助教程。在本教程中&#xff0c;我们将从我们的bitbucket账户中爬取一个项目列表。教程中的代码可以从我的 Github 中找到。我们将会按照以下步骤进行&…

云服务器怎么优化网站图片缓存,云服务器挂站怎样提高打开速度?

对于网站管理员而言&#xff0c;提高网站加载速度始终是为访问者带来最佳体验的首要问题。如果访问时网站速度很慢&#xff0c;那么访问者肯定很难留住。但在谈论如何加速您的网站之前&#xff0c;我们需要知道如何测试您网站的真实速度&#xff0c;以避免混淆初学者。在本文中…

同一服务器 多网站,同一服务器 多网站

同一服务器 多网站 内容精选换一换普通的域名解析只为用户返回解析结果&#xff0c;不会考虑访问者IP的来源和类型&#xff0c;这样&#xff0c;所有的访问者都被解析到同样的IP地址上&#xff0c;容易出现由跨运营商或者跨地域访问引起网络体验欠佳。云解析服务的智能线路解析…

网站加投票系统 php,投票选项添加操作

这里需要对已经添加的投票问题进行全部查询展示:<?php 请选择问题$result $db->query("select * from votename");while($row mysqli_fetch_assoc($result)){?>"><?php echo $row[question_name]; ?>}?>全部代码:<?php includ…