DEV Community

Bemn
Bemn

Posted on โ€ข Originally published at blog.lofibean.cc on

Fixing AjaxControlTookit Unexpected Page Reload in ASP.NET Web Form Application

Table of Contents

๐Ÿ˜จ Problem

TL;DR: see Summary and the working code snippet if you want to try it right away.

In my company there is an old Web Form Website running .NET Framework 3.5. I migrated it to an ASP.NET Web Form Application running .NET Framework 4.7.2 few months ago. The website is running just like the old one but recently a user reported that:

a <select> list which should triggers an AJAX call and refresh part of the page does not work. Instead, the page is reloaded everytime when the item in the <select> list is changed.

I used almost a day to figure out whatโ€™s (probably) happened and I hope that this article will be helpful to someone in the future who (still) encounter this problem.

Expected vs Actual Behavior

There is a <form> containing a <select> list (generated by <asp:DropDownList>). When the selected option is changed, an AJAX call will be fired and new items will be fetched. Besides, there is a text area for user to input remarks. A submit button will submit the form.

image-20210212150215986

Expected

The page will not be reloaded when the selected option is changed. The content in the text area retains.

Actual

Once the selected option is changed, a form POST is fired (instead of an AJAX call). The content in the text area is therefore being cleaned.

This is related to AJAX calls so the first thing I checked was how the AJAX call was initiated.

๐Ÿ˜€ Solution (Part 1): Updating AjaxControlToolkit

In the .aspx file I saw a <asp:UpdatePanel> and a <asp:DropDownList>. This is the simplified structure of that part:

<asp:UpdatePanel runat="server" ID="UpdatePanel2" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:DropDownList runat="server" ID="ddItemTypes" AutoPostBack="true" OnSelectedIndexChanged="ddItemTypes_OnSelectedIndexChanged" />
</ContentTemplate>
</asp:UpdatePanel>
Enter fullscreen mode Exit fullscreen mode

AutoPostBack is there so the app should use AjaxControlToolkit to make AJAX calls (I guess thatโ€™s the standard right?).

Nuget Package Update

I checked the package.config:

<package id="AjaxControlToolkit" version="4.1.50508" targetFramework="net35" />
Enter fullscreen mode Exit fullscreen mode

Looks like the targetFramework is not right. Maybe itโ€™s time to update the package too.

<package id="AjaxControlToolkit" version="20.1.0" targetFramework="net472" />
Enter fullscreen mode Exit fullscreen mode

Some Breaking Changes

AjaxControlToolkit has some breaking changes since version 15+. In short, you need to:

  1. Uninstall the old version and install the new version of AjaxControlToolkit.

  2. Change <asp:ToolkitScriptManager> to <asp:ScriptManager>

  3. Remove some unused configs in web.config (see this)

  4. [Optional] Install AjaxControlToolkit.HtmlEditor.Sanitizer

  • Change the namespace AjaxControlToolkit.HTMLEditor to AjaxControlToolkit.HtmlEditor

  • Change the namespace AjaxControlToolkit.HTMLEditor.ToolbarButton to AjaxControlToolkit.HtmlEditor.ToolbarButtons

You may also readthe official complete migration guide.

After I upgrade the Nuget package, the AJAX calls was working partially: It only works on Chromium-base browsers like Chrome and Edge. However, it does not work on Firefox (85.0) and Safari (14.0.1).

๐Ÿ˜ ๐Ÿ˜ ๐Ÿ˜

Different __doPostBack() in Firefox?

This is what I got from Firefoxโ€™s dev tool:

call stack form Firefox image-20210212140706748

The initiator is from __doPostBack() in the .aspx page. In Chrome, itโ€™s from ScriptResource.axd. Below is the expected call stack: the call is an XHR request fired from ScriptResource.axd.

Expected call stack image-20210212141300293

Looks like the stack items from bottom to _doPostBack() are the same. I therefore dug into _doPostBack() and eventually found this piece of code in ScriptResource.axd:

if (!this._postBackSettings.async) {
  form.onsubmit = this._onsubmit;
  this._originalDoPostBack(eventTarget, eventArgument);
  form.onsubmit = null;
  return;
}
Enter fullscreen mode Exit fullscreen mode

if this._postBackSettings.async is false, _originaldoPostBack() will be called and that is the __doPostBack() function defined in the .aspx page. This will trigger a page reload instead of an AJAX call.

Furthermore, I found that the asyncTarget in _postBackSettings is null but in Chrome that target is the <select> list.

In Firefox (v85.0) the javascript event initiated is somehow keep propagating to a higher level than the <select> list (probably to the formโ€™s level) and therefore being treated as a form POST instead of an AJAX call.

๐Ÿ˜€ Solution (Part 2): Adding <asp:AsyncPostBackTrigger>

I did some research related to the Firefox-specific page reload and seems none of them were talking about the issue I met. I tried to study the fundamentals of this PostBack behaviour.

Finally I got this article Avoid (Prevent) Page refresh (PostBack) after SelectedIndexChanged is fired in ASP.Net DropDownList. It suggested what I might missing is an asp:AsyncPostBackTrigger.

Also, this StackOverflow answer menitoned the asp:AsyncPostBackTrigger thing.

So my understanding is:

When using the ScriptManager (i.e. the one we introduced when updating the AjaxControlToolkit), we need to define an asp:AsyncPostBackTrigger Trigger in order to make the call AJAX.

Therefore, I added a Trigger section to the .aspx file:

<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddItemTypes" EventName="SelectedIndexChanged" />
</Triggers>
Enter fullscreen mode Exit fullscreen mode

This Trigger section should be placed under the same <asp:UpdatePanel> with the <asp:DropDownList>. Here is the complete snippet:

The Working Code Snippet

<asp:UpdatePanel runat="server" ID="UpdatePanel2" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:DropDownList runat="server" ID="ddItemTypes" AutoPostBack="true" OnSelectedIndexChanged="ddItemTypes_OnSelectedIndexChanged" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddItemTypes" EventName="SelectedIndexChanged" />
</Triggers>
</asp:UpdatePanel>
Enter fullscreen mode Exit fullscreen mode

Note:

  1. EventName is optional here but since I just want this trigger to listen the SelectedIndexChanged event, I add them all.

  2. The ControlID has to be an exact match with the ID of <asp:DropDownList>.

After I added the <asp:AsyncPostBackTrigger>, all the browsers including Chrome, Edge, Firefox (85.0) and Safari (14.0.1) are working.

Summary

When your .NET 4.5+ ASP.NET Web Form Application using AjaxControlToolkit does not work as expected and cause the controls like <asp:DropDownList> cannot fire an AJAX call (but triggers a form POST), make sure that:

  1. The AjaxControlToolkit Nuget package is up to date (and did the proper migration steps here).

  2. The <asp:UpdatePanel> section should contain a <Triggers> section. In that section there is an <asp:AsyncPostBackTrigger> with ControlID same as the ID of your control (which is also placed under the same UpdatePanel section).

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

๐Ÿ‘‹ Kindness is contagious

Please leave a โค๏ธ or a friendly comment on this post if you found it helpful!

Okay