问题描述:这是很多 ASP.NET 初学者面临、发帖和询问的常见问题之一。通常,他们会发布如下错误消息并寻求解决方案,而不会分享他们正在尝试做的事情。
[ArgumentException:回发或回调参数无效。使用配置或页面中的 <%@ Page EnableEventValidation="true" %> 启用事件验证。出于安全目的,此功能验证回发或回调事件的参数是否源自最初呈现它们的服务器控件。如果数据有效且符合预期,请使用 ClientScriptManager.RegisterForEventValidation 方法注册回发或回调数据以进行验证。]
虽然,错误堆栈跟踪本身建议通过关闭事件验证来快速解决,但它不是推荐的解决方案,因为它会打开一个安全漏洞。知道它发生的原因以及如何解决/处理该根本问题总是很好的。
评估:进行事件验证以验证事件的起源是否是相关的呈现控件(而不是一些跨站点脚本左右)。由于控件在渲染期间注册其事件,因此可以在回发或回调期间验证事件(通过 __doPostBack 的参数)。这降低了未经授权或恶意回发请求和回调的风险。
参考:MSDN:Page.EnableEventValidation 属性
基于上述情况,我在讨论中遇到或听到的可能引发问题的场景是: 案例 #1:如果我们在请求数据中有尖括号,看起来某个脚本标签正在传递给服务器。
可能的解决方案:HTML 在提交表单之前借助 JavaScript 对尖括号进行编码,即替换“<” 用“<” 和“>”与“>”</p>
function HTMLEncodeAngularBrackets(someString)
{
var modifiedString = someString.replace("<","<");
modifiedString = modifiedString.replace(">",">");
return modifiedString;
}
案例#2:如果我们编写的客户端脚本在运行时更改客户端中的控件,我们可能会遇到一个悬空事件。一个示例可能是具有嵌入式控件,其中内部控件注册回发但由于在外部控件上执行的操作而在运行时隐藏。这是我在 Carlo 写的 MSDN 博客上读到的,在寻找相同的问题时,因为有多个表单标签。
可能的解决方案:在页面的 Render 方法中手动注册事件验证控件。
protected override void Render(HtmlTextWriter writer)
{
ClientScript.RegisterForEventValidation(myButton.UniqueID.ToString());
base.Render(writer);
}
如前所述,报告的另一种常见情况(看起来属于同一类别)是构建一个页面,其中一个表单标记嵌入在服务器上运行的另一个表单标记中。删除其中一个可以更正流程并解决问题。
案例#3:如果我们在每次回发时在运行时重新定义/实例化控件或命令,则可能会遇到相应/相关的事件。一个简单的示例可能是在每个页面加载(包括回发)上重新绑定数据网格。因为,在重新绑定网格中的所有控件时,都会有一个新的 ID,因此在由 datagrid 控件触发的事件期间,回发时控件 ID 会发生更改,因此事件可能无法连接到正确的控件,从而引发问题。
可能的解决方案:这可以通过确保不会在每次回发时重新创建控件来简单地解决(在此处重新绑定)。使用 Page 属性 IsPostback 可以轻松处理它。如果您想在每个回发上创建一个控件,那么有必要确保 ID 没有更改。
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostback)
{
// Create controls
// Bind Grid
}
}
结论:如前所述,一个简单/直接的解决方案可以在 Page 指令或 Web.config 文件中添加 enableEventValidation=”false”,但不推荐。根据实施和原因,找到根本原因并相应地应用解决方案。