在CompositeScript和UpdatePanel中,WebUIValidation.js会在异步调用中重新加载

时间:2014-01-08 14:59:34

标签: asp.net updatepanel scriptmanager scriptresource.axd

我的情景:

  • 我在UpdatePanel中有一个验证器。
  • 我想合并我的脚本,以便我在CompositeScript中使用ScriptManager,并包含对WebUIValidation.js的引用
  • 我使用的是.NET 4.0

我的问题:

  • 当我异步更新面板时,.NET会在异步响应中加载WebUIValidation.js(在Scriptresource.axd文件中),即使它已在最初的CompositeScript生成的脚本中加载。这是一个问题,因为我有自定义代码劫持WebUIValidation.js中的某些函数,而异步响应会覆盖我的劫持。
  • 如果您将WebUIValidation.js中的引用移至Scripts ScriptManager,则没有问题。
  • 如果您要WebUIValidation.js作为CompositeScript中的唯一项目(我知道毫无意义),那么就没有问题。
  • 其他.NET库脚本不会发生此异步重新加载,例如: WebForm.js

我想知道的是什么:

  • 如果WebUIValidation.js已包含在CompositeScript
  • 中,为什么会在异步响应中加载WebUIValidation.js

今天有人发布了similar (but not duplicate) issue,并且正在转向ScriptManager可能无法处理// To be added to the composite script console.log('Test 1 Loaded'); 。任何人都可以验证这个吗?

要复制,请使用以下两个文件

test1.js

<%@ 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>

Test.aspx文件

{{1}}

如果您使用开发人员工具检查正在加载的脚本,您应该看到在单击按钮后加载的其他Scriptresource.axd(包含WebUIValidation.js),尽管存在Scriptresource。使用复合脚本的axd。 test.js只是一个模拟复合脚本概念的示例js文件。

1 个答案:

答案 0 :(得分:0)

分享我对它为什么再次加载这些脚本的调查(WebUIValidation.js或Focus.js)。我现在刚刚发现了Focus.js。

首先,http请求的来源是更新面板生成的部分更新。如果你看一下异步xhr POST请求的响应,你就会有这样的事情。注意几乎在ScriptResource.axd url的末尾。这是由客户端的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|

现在调试服务器端代码,从https://referencesource.microsoft.com/加载.net程序集符号(使用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直接写入作者的内容,例如&#34; len | type | id | content |&#34;,包括writer.Write(content);,其中content"/ScriptResource.axd?d=Uup1IW...q450&t=ffffffffd4ee116f"。没有检查这个脚本是否已经在ScriptManager中注册,它没有调用ScriptManager.RegisterXXXX。

所以在我看来,这是因为已经加载了某些东西的另一个http请求的原因。 ProcessFocus是作为&#34; Render&#34;的一部分完成的,为时已晚,无法使用任何ScriptManager功能。

我无法想出一种避免此http请求的方法(除了不使用.net框架中的任何SetFocus类型的东西)。

(运行VS 2015,.net framework 4.6.2,ajax control toolkit 17.1)