WebUIValidation.js перезагружается при асинхронных вызовах, когда в CompositeScript и UpdatePanel

Мой сценарий:

  • У меня есть валидатор в UpdatePanel,
  • Я хочу объединить свои сценарии, поэтому я использую CompositeScript в ScriptManager и включая ссылку на WebUIValidation.js
  • Я использую.NET 4.0

Моя проблема:

  • Когда я асинхронно обновляю панель, .NET загружается WebUIValidation.jsScriptresource.axd файл) в асинхронном ответе, даже если он был загружен в исходном CompositeScript сценарий. Это проблема, потому что у меня есть пользовательский код, который захватывает некоторые функции в WebUIValidation.js и асинхронный ответ отменяет мои угоны.
  • Если вы переместите ссылку на WebUIValidation.js в Scripts в ScriptManager, нет проблем.
  • Если бы вы имели WebUIValidation.js как единственный элемент в CompositeScript (бессмысленно я знаю) тогда нет проблем.
  • Эта асинхронная перезагрузка не происходит с другими скриптами библиотеки.NET, например WebForm.js

Что я хочу узнать:

  • есть ли причина, почему WebUIValidation.js загружается в асинхронный ответ, когда он уже включен в CompositeScript ?

Кто-то опубликовал аналогичную (но не повторяющуюся) проблему сегодня и пытается сказать, что WebUIValidation.js не может быть обработано ScriptManager, Кто-нибудь может это проверить?

Для репликации используйте следующие два файла

test1.js

// To be added to the composite script
console.log('Test 1 Loaded');

test.aspx

<%@ Page Language="vb" AutoEventWireup="false"  %>

<!DOCTYPE html>

<html>
<head runat="server">
    <title></title>
</head>
<body>
    <script language="VB" runat="server" runat="server">
        Protected Sub ButtonClicked(ByVal sender As Object, ByVal e As System.EventArgs) Handles TestButton.Click
            ButtonClickFeedback.Text = "Button clicked At " & Date.Now.ToString & "; Look at the scripts in your Developer Tools, there is now a separate script for WebUIValidation.js loaded, in spite of the composite script."
        End Sub 
    </script>

    <form runat="server">
        <asp:ScriptManager runat="server">
            <CompositeScript>
                <Scripts>
                    <asp:ScriptReference Path="~/test.js" />
                    <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" />
                </Scripts>
            </CompositeScript>
        </asp:ScriptManager>

        <h1>WebUIValidation.js, CompositeScript and UpdatePanel test</h1>

        <asp:UpdatePanel runat="server" ID="ButtonUpdatePanel">
            <ContentTemplate>
                <asp:Label runat="server" >This is a section with a validator that is within an UpdatePanel.  If you look at the scripts loaded, you will see the composite script in the detail.</asp:Label>
                <asp:Textbox ID="TestInputForValidator" runat="server" Text="This is populated so it will validate"/>
                <asp:RequiredFieldValidator runat="server" ControlToValidate="TestInputForValidator" ErrorMessage="You must write something" /><br />
                <asp:Button ID="TestButton" Text="Click Me!" runat="server"  /><br />
                <asp:Literal ID="ButtonClickFeedback" runat="server" />
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="TestButton" />
            </Triggers>
        </asp:UpdatePanel>
    </form>
</body>
</html>

Если вы используете Инструменты разработчика для проверки того, в какие скрипты загружаются, после нажатия кнопки вы увидите, как загружается дополнительный Scriptresource.axd (содержащий WebUIValidation.js), несмотря на существование Scriptresource.axd с составной скрипт. test.js - это просто пример файла js, имитирующий идею составных скриптов.

1 ответ

Я делюсь своим расследованием того, почему он снова загружает эти скрипты (WebUIValidation.js или Focus.js). Я только что нашел о Focus.js на данный момент.

Во-первых, источником http-запроса является частичное обновление, созданное панелью обновлений. Если вы посмотрите на ответ на асинхронный запрос xhr POST, у вас будет что-то вроде этого. Обратите внимание, почти в конце URL ScriptResource.axd. Это обрабатывается инфраструктурой ajax на стороне клиента и, поскольку это блок скрипта с путем, он загружается:

1|#||4|2999|updatePanel|ctl00_LoginContent_ctl00|
<div id="ctl00_LoginContent_...">[...html content here]</div>|
0|hiddenField|__LASTFOCUS||
0|hiddenField|__EVENTTARGET||
0|hiddenField|__EVENTARGUMENT||
904|hiddenField|__VIEWSTATE|UdWhNvH6wpBcPOigY[...]SIphbw==|
8|hiddenField|__VIEWSTATEGENERATOR|25748CED|
176|hiddenField|__EVENTVALIDATION|q+FUEVGVj+t[...]AzAm|
0|asyncPostBackControlIDs|||
0|postBackControlIDs|||
26|updatePanelIDs||tctl00$LoginContent$ctl00,|
0|childUpdatePanelIDs|||
25|panelsToRefreshIDs||ctl00$LoginContent$ctl00,|
2|asyncPostBackTimeout||90|
14|formAction||./Default.aspx|
119|scriptBlock|ScriptContentNoTags|function PopulateTimeZoneOffset(){[my own js here...]}|
154|scriptBlock|ScriptPath|/ScriptResource.axd?d=Uup1Lt[...]q450&t=ffffffffd4ee116f|
31|focus||ctl00_LoginContent_LoginControl|

Теперь выполните отладку кода на стороне сервера, загрузив символы сборок.net с https://referencesource.microsoft.com/ (с настройкой VS, как описано там).

PageRequestmanager.cs

    private void ProcessFocus(HtmlTextWriter writer) {
        // Roughly stolen from Whidbey Page.cs
        if (_requireFocusScript) {
            Debug.Assert(ClientSupportsFocus, "If ClientSupportsFocus is false then we never should have set _requireFocusScript to true.");
            string focusedControlId = String.Empty;

            // Someone calling SetFocus(controlId) has the most precedent
            if (!String.IsNullOrEmpty(_focusedControlID)) {
                focusedControlId = _focusedControlID;
            }
            else {
                if (_focusedControl != null && _focusedControl.Visible) {
                    focusedControlId = _focusedControl.ClientID;
                }
            }
            if (focusedControlId.Length > 0) {
                // Register focus script library
                string focusResourceUrl = _owner.GetScriptResourceUrl("Focus.js", typeof(HtmlForm).Assembly);
                EncodeString(writer, ScriptBlockToken, "ScriptPath", focusResourceUrl); 
                // *********** THIS ENCODESTRING OUTPUTS THE PROBLEM !!!

                // Send the target control ID to the client
                EncodeString(writer, FocusToken, String.Empty, focusedControlId);
            }
        }
    }

Мы глубоко внутри Page.ProcessRequest, и теперь в Page.Render, RenderPageCallback и ProcessFocus. Подсвеченный EncodeString ближе к концу записывает непосредственно в писатель такие вещи, как "len|type|id|content|", включая writer.Write(content); где content является "/ScriptResource.axd?d=Uup1IW...q450&t=ffffffffd4ee116f", Нет проверки, зарегистрирован ли этот скрипт в ScriptManager, он не вызывает ScriptManager.RegisterXXXX.

Так что мне кажется, что это причина получения еще одного http-запроса на то, что уже загружено. ProcessFocus выполняется как часть "Render", слишком поздно, чтобы использовать какую-либо функцию ScriptManager.

Я не могу придумать, как избежать этого http-запроса (кроме того, что я не использую SetFocus наберите вещь из.net framework).

(Запуск VS 2015, .net Framework 4.6.2, инструментарий управления ajax 17.1)

Другие вопросы по тегам