My scenario:
- I have a validator in an
UpdatePanel
. - I want to combine my scripts so I am using
CompositeScript
inScriptManager
, and including a reference toWebUIValidation.js
- I am using .NET 4.0
My problem:
- When I asynchronously update the panel, .NET loads
WebUIValidation.js
(in aScriptresource.axd
file) in the async response, even though it has been loaded in the initialCompositeScript
-generated script. This is a problem because I have custom code that hijacks some functions inWebUIValidation.js
, and the async response overrides my hijacks. - If you move the reference to
WebUIValidation.js
toScripts
inScriptManager
, there is no problem. - If you were to have
WebUIValidation.js
as the only item inCompositeScript
(pointless I know) then there is no problem. - This async reload does not happen with other .NET library scripts, e.g.
WebForm.js
What I want to find out:
- is there a reason why
WebUIValidation.js
is loaded in the async response when it is already included in theCompositeScript
?
Someone has posted a similar (but not duplicate) issue today, and is veering towards saying that WebUIValidation.js
might not be handled by ScriptManager
. Can anyone verify this?
To replicate use the following two files
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>
If you use your Developer Tools to inspect what scripts are being loaded in, you should see an additional Scriptresource.axd (that contains WebUIValidation.js) getting loaded in after clicking the button, in spite of the existence of a Scriptresource.axd with the composite script. test.js is just a sample js file to simulate the idea of composite scripts.
Sharing my investigation on why it's loading these scripts again (WebUIValidation.js or Focus.js). I've just found about Focus.js for now.
First, the origination of the http request is in the partial update generated by the update panel. If you look at the reponse to the asynchronous xhr POST request, you'll have something like this. Note almost at the end the ScriptResource.axd url. This is processed by the ajax framework on the client side and since it's a script block with a path, it gets loaded:
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|
Now debugging server side code, loading the .net assemblies symbols from https://referencesource.microsoft.com/ (with VS configuration as described there).
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);
}
}
}
We are deep inside Page.ProcessRequest, and now in Page.Render, RenderPageCallback and ProcessFocus. The highlighted EncodeString near the end writes directly to the writer things like "len|type|id|content|", including writer.Write(content);
where content
is "/ScriptResource.axd?d=Uup1IW...q450&t=ffffffffd4ee116f"
. There is no check to see if this script is already registered with the ScriptManager, it's not calling ScriptManager.RegisterXXXX.
So it seems to me that's the cause of getting another http request for something that's already loaded. ProcessFocus is done as part of "Render", far too late to use any ScriptManager functinality.
I can't think of a way to avoid this http request (apart from not using any SetFocus
type thing from the .net framework).
(Running VS 2015, .net framework 4.6.2, ajax control toolkit 17.1)
来源:https://stackoverflow.com/questions/20999104/webuivalidation-js-gets-reloaded-in-async-calls-when-in-compositescript-and-upda