异步 WebForms 页面中的 AjaxControlToolkit 问题

AjaxControlToolkit issue in Async WebForms pages

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

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

经过一番分析,原因如下。

  1. ExtenderControl base class,所有 AjaxControlToolkit 扩展器 subclass,在其调用 ScriptManager.RegisterExtenderControl() OnPreRender 方法。此外,ScriptManager 会抛出异常 如果 RegisterExtenderControl() 在除 预渲染。
  2. 对于在 PreRender 阶段不可见的控件, OnPreRender 方法不会被调用,因此扩展器 控件将不会被注册。
  3. WebForms 页面 运行 所有异步任务 在 PreRender 阶段 之后,以及 在渲染阶段之前。所以,如果你让你的扩展器可见 异步任务,那么它在 PreRender 中还不可见 阶段,并且只在渲染阶段。
  4. 最后,扩展器控制调用 ScriptManager.RegisterScriptDescriptors() 在渲染阶段, 由于控件没有被抛出上述异常 在 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>

基于此处针对此问题发布的建议 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