ASP.NET 4.5 新特性 - 第 1 部分






4.93/5 (46投票s)
在本文中,您应该具备 Web 开发的基本知识以及 .NET Framework 早期版本中引入的一些特性,尤其是 ASP.NET 特性。
.NET Framework 4.5 带来了许多出色的特性。虽然无法一一赘述所有特性,但我想重点介绍一些与 ASP.NET 相关的特性。
现在我正在思考应该从何处以及如何开始?
我想我应该从谈论目标受众开始。 请允许我明确一点,本文不适合那些想学习 ASP.NET Web Forms 或 ASP.NET MVC 的人。为了理解本文,您应该具备 Web 开发的基本知识以及 .NET Framework 早期版本中引入的一些特性,尤其是 ASP.NET 特性。 | ![]() |
那么我们将学习什么?
我们不会涵盖 4.5 中引入的每一个 ASP.NET 特性。相反,我们将讨论一些我个人觉得不错并认为应该分享的特性。如果您认为还有其他需要涵盖的内容,您可以使用评论区,我将尽力为您提供。
议程
- 理解异步 HTTP 模块和处理程序
- ASP.NET 4.5 中的 WebSocket 协议支持
- 新的请求验证特性
- 接下来是什么和结论?
废话少说,让我们开始工作。
理解异步 HTTP 模块和处理程序。
HTTP 模块和 HTTP 处理程序是每个 ASP.NET 开发人员都常听到的两个词。很多时候,我们希望在请求任何 Web 资源(如图像、文本或 aspx)之前实现预处理逻辑。例如,我们希望在实际页面/资源处理开始之前添加安全检查。
HTTP 模块在 ASP.NET 请求管道中发出大量事件,我们可以在其中编写自己的逻辑,因此它被称为基于事件的方法。每个请求都通过 HTTP 模块。
另一方面,HTTP 处理程序不会对每个请求都执行,它取决于我们请求的资源的扩展名,因此它被称为基于扩展名的方法。假设最终用户请求扩展名为 `.jpg` 的图像,但我们在内部从数据库中检索图像并将其作为响应发送。HTTP 处理程序在此处最适合。
如果您对这两个概念更感兴趣并想深入学习,请单击此处。
ASP.NET 中的请求处理
现在 IIS Web 服务器维护一个线程池,每当有新请求到来时,它就会从该池中取出一个线程并将其分配给请求处理。只要线程池中有可用线程,ASP.NET 就能够处理所有请求。但是,一旦所有线程都忙于处理请求,线程池中没有空闲线程,新请求就必须等待线程空闲。显然,存在等待时间,之后服务器将抛出“HTTP 503 server busy
”或“Server Unavailable
”错误。
增加线程池大小并不能真正解决问题。
缺少线程不是真正的问题,真正的问题是现有线程没有得到有效利用。
很多时候,我们的请求处理线程将等待 I/O 完成而不是执行代码,我称之为线程的低效使用。我们应该在 I/O 操作开始时立即释放线程,并在 I/O 操作完成时立即获取一个新线程。
同步 HTTP 模块
让我们讨论一个场景,我们希望在 HTTP 模块中编写一个复杂的长时间运行任务。
任务可能包括
| ![]() |
出于演示目的,假设我们希望将所有请求的详细信息记录到数据库中。
现在,如果我们以同步方式执行模块,它将大大降低站点性能,因为它会在整个数据库处理过程中使请求处理线程(在开始时分配的线程)保持忙碌。
异步 HTTP 模块
现在 ASP.NET 支持创建异步 HTTP 模块。在这种情况下,一旦 I/O 或任何其他不需要 CPU 的操作开始,我们将释放线程。
为此,我们将在 HTTP 模块中使用异步方法而不是同步方法。在示例中,我们使用 `AddOnPostAuthorizeRequestAsync` 方法,它是同步事件 `PostAcquireRequestState` 的异步版本。
那么 ASP.NET 4.5 有什么新功能?
尽管早期版本的 ASP.NET 允许创建异步 HTTP 模块,但随着 4.0 中 Task 的引入以及 4.5 中 `async`/`await` 关键字的引入,它变得更加简单。
在 ASP.NET 4.5 中,我们有一个名为 `EventHandlerTaskAsyncHelper` 的类和一个名为 `TaskEventHandler` 的委托类型,我们可以使用它们将基于 Task 的异步方法与 ASP.NET HTTP 管道公开的旧异步编程模型集成。让我们快速看一下上面代码片段的重构版本。
同步 HTTP 处理程序
让我们讨论上面讨论的图像处理场景(在解释 HTTP 处理程序时)。现在,如果我们为此创建同步 HTTP 处理程序,它只会长时间阻塞请求处理线程。我们应该在开始从数据库检索图像时立即将线程释放到线程池(以便它可以处理其他请求),并在检索完成后分配一个新线程。
异步 HTTP 处理程序
最终的解决方案将是异步 HTTP 处理程序。
通常,为了创建 HTTP 处理程序,我们使用 `IHttpHandler`,但为了创建异步 HTTP 处理程序,我们将使用 `IHttpAsyncHandler`。
public class MyAsyncHandelerOldWay: IHttpAsyncHandler
{
public MyAsyncHandelerOldWay()
{
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallbackcb, object
extraData)
{
//......
}
public void EndProcessRequest(IAsyncResult result)
{
//......
}
public bool IsReusable
{
//......
}
public void ProcessRequest(HttpContext context)
{
//......
}
}
那么 ASP.NET 4.5 有什么新功能?
同样的问题。实现起来太复杂了。但 .NET 4.5 使用 `async`/`await` 关键字和一个名为 `HttptaskAsyncHandler` 的类使其易于实现。
publicclassMyAsyncHandeler:HttpTaskAsyncHandler
{
public MyAsyncHandeler()
{
}
public override async Task ProcessRequestAsync(HttpContext context)
{
SqlCommand cmd = newSqlCommand();
Object Image= await cmd.ExecuteScalarAsync();
context.Response.BinaryWrite((byte[])Image);
context.Response.End();
}
}
ASP.NET 4.5 中的 WebSocket 支持
HTML 5 `WebSocket` 现在已是众所周知的功能。它将套接字带入 Web。
客户端连接到服务器并发送一个带有特殊标头的 HTTP 请求(以“ws://
”或“wss://
”为前缀),然后 Web 服务器响应 HTTP 101 并带有特殊响应标头。这就是 WebSocket 中的握手工作方式。这将通过 HTTP 在客户端和服务器之间建立安全、实时的通信。
现在不再需要使用长轮询或周期性轮询等技术来模拟 Web 中的套接字行为,现在由于 `WebSocket` 的存在,无需太多努力即可实现。
ASP.NET 4.5 有什么新功能?
现在要使用 `WebSocket`,我们需要
- 我们可以使用的客户端 JavaScript API
- 用于启动连接
- 用于向服务器发送消息
- 用于从服务器接收消息
- 用于创建和托管 WebSocket 服务器的服务器端 .NET API
客户端 API
现在对于客户端脚本,我们有 HTML 5 提供的 API。
代码 1 – 启动连接
window.onload = function ()
{
//Url of WebSocket Server
var url = "ws://:9495/ChatServer.ashx?Name=Sukesh";
var ws = new WebSocket (url);
}
代码 2 - 发送消息
$('#BtnSend').click
(
function ()
{
ws.send($('#TxtMessage').val());
$('#TxtMessage').val('');
}
);
代码 3 – 接收消息
ws.onmessage = function (e)
{
$('#ResponseDiv').append("<br>" + e.data.toString());
}
注意:以上代码中的 $ 来自 jQuery。对于 DOM 操作,我们使用 jQuery。
服务器端 API
ASP.NET 4.5 提供了 API,开发人员可以使用这些 API 轻松(这里的“轻松”一词非常重要)编写以下代码:
- 接受客户端的 `WebSocket` 请求并将 HTTP Get 请求升级为 `WebSocket` 请求。
用于接受 `WebSocket` 请求的代码HttpContext.Current.AcceptWebSocketRequest (// WebSocket delegate goes here)
注意:在 Web Forms 中,此代码将写入 HTTP 模块或 HTTP 处理程序中,在 MVC 中,我们将使用 Web API。
用于 `WebSocket` 委托的代码private async Task MyProcessTask(AspNetWebSocketContext context) { //Code goes here }
- 同步或异步从 `WebSocket` 对象读取字符串或二进制数据。用于创建 `WebSocket` 对象的代码
WebSocket socket = context.WebSocket; //context -> parameter of MyProcessTask
用于接收消息的代码ArraySegment<byte> buffer = newArraySegment<byte>(newbyte[1024]); //receive data from Client WebSocketReceiveResult result = await socket.ReceiveAsync( buffer, CancellationToken.None);
用于发送消息的代码//Send data to client await socket.SendAsync( buffer, WebSocketMessageType.Text, true, CancellationToken.None);
代码示例显示 `WebSocket` 请求在内部完全异步运行。
应用程序异步等待客户端消息,为此,我们使用了 `await socket.ReceiveAsync`。
同样,通过调用 `await socket.SendAsync`,异步消息被发送到客户端。
ASP.NET 4.5 中的新请求验证功能
请求验证是 ASP.NET 中的重要功能之一。它检查传入请求并确定是否包含潜在危险内容。
-
“危险内容”是什么意思?
任何出于恶意目的而添加的 HTML 或 JavaScript 代码。 -
这里的“请求内容”是什么意思?
它表示请求的已发布值、查询字符串、Cookie 和标头。 -
为什么需要请求验证?
它避免了 XSS(跨站脚本)。假设我们在页面中有一个 `textbox` 和一个按钮。当有人点击按钮时,`textbox` 中的值将显示在页面本身中。现在假设如果有人在 `textbox` 中输入了一些带有 `script` 标签的 JavaScript 代码,当我们尝试将 `textbox` 内容写入页面时,浏览器将执行 JavaScript 代码。 -
如果请求验证失败会发生什么?
ASP.NET 将抛出“potentially dangerous value was detected
”错误并停止页面处理。
如果我们的应用程序需要接受 HTML 内容,这将是一个大问题。接受 HTML 内容的应用程序示例是论坛网站。
解决方案 – 禁用请求验证
- 要么在页面级别
<%@PagevalidateRequest="false"%>
- 要么在应用程序级别
<configuration> <system.web> <pagesvalidateRequest="false" /> </system.web> </configuration>
这样好吗?
显然不好!!!因为我们必须验证页面中的每个控件,这样 XSS 才不会受到影响。项目要求只有某些控件会接受 HTML 内容,因此禁用页面(或应用程序)中所有控件的请求验证是没有意义的。
ASP.NET 4.5 有什么新功能?
它提供了 2 个新功能
- 延迟请求验证
- 引入 `ValidateRequestMode` 属性
为了理解这两个功能,让我们创建一个简单的表单,如下所示
为了解决这个问题,我们将导航到 `web.config` 并将 `requestValidationMode` 更改为 `4.5`(ASP.NET 4.5 中的新功能)。
<system.web>
<compilationdebug="true"targetFramework="4.5"/>
<httpRuntimetargetFramework="4.5"requestValidationMode="4.5"/>
</system.web>
这只会消除错误。现在是时候在代码隐藏中消耗这些值以进行进一步处理了。所以让我们在按钮点击处理程序中编写一些代码。
看来错误仍然存在。现在唯一的区别是,它是在我们尝试访问值时出现的。调用 `Request.Form["forum_post"]` 仍然会触发对该特定请求值的请求验证。
这就是我们所说的延迟请求验证。
但是如何访问这些值呢?
为此,我们将使用 `Request.Unvalidated.Form`。
示例
stringHtmlContent = Request.Unvalidated.Form["TxtHtmlContents"];
如果我想使用服务器端控件怎么办?
这个问题仅适用于 ASP.NET Web Forms。在上面的示例中,我们使用了输入 `textbox`(HTML 控件)。现在让我们尝试使用服务器端 `textbox` 的相同示例。
<div>
(Html Contents): <br/>Server Textbox
<asp:TextBoxrunat="server"ID="TxtHtmlContents"/><br/>
(Normal Contents): <br/>Server Textbox
<asp:TextBoxrunat="server"ID="TxtNormalContents"/><br/>
<asp:ButtonID="Button1"Text="Submit"runat="server"OnClick="Button1_Click"name="Address"/>
</div>
当我们执行代码时,我们会看到一个奇怪的行为。在 `textbox` 中放入一些 HTML 内容并单击按钮。我们将得到相同的“Potential Error
”。将 `requestValidationMode` 设置为 `4.5` 只是将请求验证从一个时间委托到另一个时间(我们尝试检索值的时间)。当我们仔细查看 ASP.NET 生命周期事件时,我们会发现在 `Page_Load` 事件之前,会触发一个名为 `LoadPostBackData` 的事件,它将从已发布数据中获取所有值并将它们加载到相应的 `textbox` 中。这意味着,在后台,ASP.NET 正在尝试从已发布的表单数据中访问值,这导致了错误。
解决方案是什么?
好消息是 ASP.NET 4.5 为每个服务器控件添加了一个新属性,名为 `ValidateRequestMode`。将其设置为“`disabled`”。使用此属性,我们可以禁用对单个控件的请求验证。
4.5 中引入的一些小而重要的功能
我想讲一些非常小但有用的功能。
-
使用 `<%: %>` 进行自动 HTML 编码
-
非侵入式验证 –
这将显著减少页面标记中内联呈现的 JavaScript 数量,从而减少页面总大小。 -
关于 HTML 5 的新功能
- `Textbox` 的 `TextMode` 属性现在支持更多值,例如 `email`、`datetime`
- 许多 HTML 5 控件支持 `runat=”server”` 属性,以便在指定 URL 时支持“
~
”符号 - 文件上传控件支持多文件上传
接下来是什么和结论?
在本文中,我们尝试理解 ASP.NET 4.5 中的 3 个新功能,希望您喜欢。我们从异步 HTTP 模块和处理程序开始,然后演示了 Web 套接字,最后介绍了新的请求验证功能。
在接下来的系列中,我们将讨论 ASP.NET MVC 的改进。
- ASP.NET Web API
- 异步控制器
- 显示模式支持
感谢阅读。您的反馈、评论和评分不仅激励我们,也提升我们。
继续编码,继续分享。
获取更多类似内容,请单击此处。订阅文章更新或在 Twitter @SukeshMarla 关注。
单击此处获取更多关于ASP.NET /.NET 和 C# 学习资料
请阅读这篇文章,其中讨论了5 个重要的 .NET 4.5 新功能。