首页 > 解决方案 > 异步 WebForms 页面中的 AjaxControlToolkit 问题

问题描述

运行异步任务的 WebForms 页面中的 AjaxControlToolkit 扩展程序(或任何其他扩展程序)存在问题。如果您的扩展程序最初是不可见的,并且您运行了一个异步任务,使其可见(例如,如果应根据您异步读取的数据确定可见性),那么您将获得以下 System.ArgumentException:

Extender control '[ControlID]' is not a registered extender control.
Extender controls must be registered using RegisterExtenderControl() before calling RegisterScriptDescriptors().

经过一番分析,这是造成这种情况的原因。

  1. 所有 AjaxControlToolkit 扩展程序子类的 ExtenderControl 基类ScriptManager.RegisterExtenderControl()在其 OnPreRender方法中调用。RegisterExtenderControl()此外,如果在 PreRender 以外的任何阶段调用ScriptManager,都会抛出异常。
  2. 对于在 PreRender 阶段不可见的控件, OnPreRender不会调用该方法,因此不会注册扩展器控件。
  3. WebForms 页面在 PreRender 阶段之后和 Render 阶段之前运行所有异步任务。所以,如果你让你的扩展器在异步任务中可见,那么它在 PreRender 阶段是不可见的,只有在 Render 阶段才可见。
  4. 最后,扩展器控件 ScriptManager.RegisterScriptDescriptors()在Render阶段调用,由于控件没有在PreRender阶段注册,抛出上述异常。

有没有人找到解决方法或解决方法?

这似乎是 WebForms 中的一个巨大限制,您无法在同一页面中有效地同时使用异步任务和扩展器控件。

以下是说明此问题的示例网页。

<%@ Page Async="true" MasterPageFile="~/Site.Master" Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.Page" %>
<%@ Import Namespace="System.Threading.Tasks" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
    <asp:Panel ID="Panel1" runat="server">
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <ajaxToolkit:CalendarExtender ID="CalendarExtender1" runat="server" TargetControlID="TextBox1" />
    </asp:Panel>
</asp:Content>

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        Panel1.Visible = false;
        RegisterAsyncTask(new PageAsyncTask(ReadAsync));
    }

    // Making the panel visible below will result in the following exception:
    // Extender control 'CalendarExtender1' is not a registered extender control.
    // Extender controls must be registered using RegisterExtenderControl() before calling RegisterScriptDescriptors().
    private async Task ReadAsync()
    {
        Panel1.Visible = true;
        await Task.CompletedTask;
    }
</script>

标签: asp.netasynchronouswebformsajaxcontroltoolkit

解决方案


根据在此处https://forums.asp.net/p/2163988/6293999.aspx?p=True&t=637169211245961059 和此处https://github.com/DevExpress/AjaxControlToolkit/issues/523发布到此问题的建议 ,我已经想出了一个通用的方法来解决这个问题。

基本上,您的页面将跟踪具有扩展器的控件,并且可以在异步任务中运行时更改其可见性。然后它将在适当的时间在 PreRender 上使这些控件暂时可见以避免错误,然后在 PreRender 完成后根据需要隐藏它们。这里的关键是使用页面的新SetControlVisible方法来设置控件的可见性。

此解决方法的完整源代码发布在此处:https ://github.com/Xomega-Net/XomegaFramework/blob/master/src/Xomega.Framework.Web/Views/WebPage.cs


推荐阅读