Showing posts with label bug. Show all posts
Showing posts with label bug. Show all posts

Monday, March 26, 2012

Access denied bug

Hi. Just letting yuo know that this code on the line 5959 of one of MS AJAX files, in getLocation func, yield "Access denied" bugs in cross-domain scenarios. Or http with https iframe scenario in our case. top is obviously inaccessible...

var w = element.ownerDocument.parentWindow;
var offsetL = w.screenLeft - top.screenLeft - top.document.documentElement.scrollLeft + 2;
var offsetT = w.screenTop - top.screenTop - top.document.documentElement.scrollTop + 2;

See this: http://weblogs.asp.net/bleroy/archive/2007/01/31/how-to-work-around-the-quot-access-denied-quot-cross-domain-frame-issue-in-asp-net-ajax-1-0.aspx

Saturday, March 24, 2012

about AjaxToolKit project page

a question really remotely related to the AtlasToolkit, but I did not know where else to ask: the bug tracking and work item tracking that you have there is really nice, what is that for a system? Homemade or somewhere available?

It'sCodePlex, Microsoft's public project management system.

A Simple Atlas Work,but Still have Unknown Error BUG

Simply, i Place a Textbox and a button,when i click the button, it response.write(textbox1.text)
but, when i click the button, it show a java script pop-up and show me Unknown error..

below is the code:

1Default.aspx2<%@dotnet.itags.org. Page Language="VB" AutoEventWireup="true" ValidateRequest="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>34<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">5<html xmlns="http://www.w3.org/1999/xhtml">6<head runat="server">7 <title>ASPNET_Atlas_Testing</title>8</head>9<body>10<form id="form1" runat="server">11<div>12 <atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="True"/>13<!-- This section of the page is wrapped by an UpdatePanel. -->14 <atlas:updatepanel id="up" runat="server" mode="Conditional" rendermode="Inline">15 <triggers>16 <atlas:controleventtrigger controlid="TextBox1" eventname="TextChanged" />17 </triggers>18 <contenttemplate>19 <asp:TextBox ID="TextBox1" runat="server" OnTextChanged="TextBox1_TextChanged"></asp:TextBox><br/>20 </contenttemplate>21 </atlas:updatepanel>2223<!-- This section is also wrapped by an UpdatePanel. -->24 <atlas:updatepanel runat="server" id="up1" mode="Conditional" rendermode="Inline">25 <triggers>26 <atlas:controleventtrigger controlid="Button1" eventname="Click" />27 </triggers>28 <contenttemplate>29 <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/>30 </contenttemplate>31 </atlas:updatepanel>32</div>33</form>34</body>35</html>3637
1Default.vb23PartialClass _Default4Inherits System.Web.UI.Page56Protected Sub Button1_Click(ByVal senderAs Object,ByVal eAs System.EventArgs)Handles Button1.Click7 Response.Write(TextBox1.Text)8End Sub910 Protected Sub TextBox1_TextChanged(ByVal senderAs Object,ByVal eAs System.EventArgs)11 Response.Write(TextBox1.Text)12End Sub13End Class1415
Check to make sure your web.config file is setup right and that your dll is in place (/bin) and not corrupt, as I'm not getting a javascript error when I try your code. It also doesn't work as you wrote it, though, and so I tried adding a label to one of the update panels and having the button change its value based on the text prop of the textbox1, and that worked fine. So I suspect that with update panels (this is just a guess) that you can't use Response.Write; whcih would make sense if you conceive of the Response object as passing a whole page rather than just the partial page the update panel is looking for.

Hi,

Remove all response.write statements & replace them with this.page.registerclientscriptblock(script);

Amit Lohogaonkar

mcp,mcad

lohogaonkaramit@.yahoo.com

Wednesday, March 21, 2012

A bug? None-Stop Timer~~Need Help!

I placed a timer in an update panel, and add a trigger to the update panel. when a button clicked the trigger raised and the timer enabled, once again clicked the button, the timer have should be stopped, but it still works. click again! It seems there's a new timer and the old timer works, too~~~~

It is a bug? the following is the code.

=========================================

<%@dotnet.itags.org. Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="True">
</atlas:ScriptManager>
<div>
<atlas:UpdatePanel ID="upTimer" runat="server" EnableViewState="True" Mode="Conditional">
<ContentTemplate>
<atlas:TimerControl ID="timerProgress" runat="server" Enabled="false" EnableViewState="False" Interval="1000" OnTick="timerProgress_Tick">
</atlas:TimerControl>
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="cmdStart" EventName="Click" />
<atlas:ControlEventTrigger ControlID="cmdCancel" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>
<atlas:UpdatePanel ID="upProgress" runat="server" EnableViewState="True" Mode="Conditional">
<ContentTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" />
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="timerProgress" EventName="Tick" />
<atlas:ControlValueTrigger ControlID="timerProgress" PropertyName="Interval" />
</Triggers>
</atlas:UpdatePanel>
<atlas:UpdatePanel ID="upButtons" runat="server" Mode="Conditional">
<ContentTemplate>
<asp:Button ID="cmdStart" runat="server" EnableViewState="False" OnClick="cmdStart_Click"
Text="开始上传" />
<asp:Button ID="cmdCancel" runat="server" OnClick="cmdCancel_Click" Text="取消上传" Visible="False" />
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="cmdStart" EventName="Click" />
<atlas:ControlEventTrigger ControlID="cmdCancel" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>

</div>
</form>
</body>
</html>
=========================================

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected void cmdStart_Click(object sender, EventArgs e)
{
cmdStart.Visible = false;
cmdCancel.Visible = true;
timerProgress.Enabled = true;
}
protected void cmdCancel_Click(object sender, EventArgs e)
{
cmdStart.Visible = true;
cmdCancel.Visible = false;
timerProgress.Enabled = false;

}
protected void timerProgress_Tick(object sender, EventArgs e)
{
CheckBox1.Checked = !CheckBox1.Checked;
}
}

I am having the same problem. The timer cannot be turned off - even if the timer itself is placed inside the updatepanel. Often what you wanna do is have the update panel update every x seconds while some task is running, and then be turned off.

Any suggjestions on how to disable the timer? - (or is this a bug) ?


There are several issues with the TimerControl and partial rendering. I solved the problem by writing a custom control. Copy the code from this snippet to a file in your App_Code directory

using System;using Microsoft.Web.UI.Controls;namespace CustomControls{ /// /// Summary description for StoppableTimer /// public class StoppableTimer : TimerControl { public StoppableTimer() { } protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (this.Page.IsPostBack) { this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "TimerStop", "Web.Application.findObject('" + this.ClientID + "').set_enabled(" + (this.Enabled ? "true" : "false") + ");" , true); } } protected override void RenderScript(Microsoft.Web.Script.ScriptTextWriter writer) { writer.WriteStartElement("timer"); writer.WriteAttributeString("id", this.UniqueID); writer.WriteAttributeString("interval", this.Interval.ToString(System.Globalization.CultureInfo.InvariantCulture)); writer.WriteAttributeString("enabled", this.Enabled.ToString()); writer.WriteStartElement("tick"); writer.WriteStartElement("postBack"); writer.WriteAttributeString("target", this.UniqueID); writer.WriteAttributeString("argument", string.Empty); writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); } }}
Next register this custom control as a tag and use it.
<%@. Page Language="C#" AutoEventWireup="true" CodeFile="TimerTest.aspx.cs" Inherits="Default2" %><%@. Register TagPrefix="AppCode" Assembly="App_Code" Namespace="CustomControls" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>Untitled Page</title></head><body> <form id="form1" runat="server"> <atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true"> </atlas:ScriptManager> <div> <atlas:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <span id="Span1" runat="server"></span> <AppCode:StoppableTimer runat="server" ID="Timer1" Interval="1000" Visible="true" OnTick="Timer1_Tick"> </AppCode:StoppableTimer> </ContentTemplate> <Triggers> <atlas:ControlEventTrigger ControlID="Timer1" EventName="Tick" /> </Triggers> </atlas:UpdatePanel> </div> </form></body></html>

When the issues with Atlas timer control are fixed in a release you can simply replace AppCode:StoppableTimer with atlas:TimerControl.


how to use your custom control in an application like : to fetch the data without postback at a regular interval and depending upon some condition need to stop the timer so that we can stop data fetching operation?

Jaideep


Nice pice of code Rama Krishna.

I tried to modify your component to Marts CTP, but I cant get it to work. Writing the following:

writer.WriteAttributeString(

"id", UniqueID);

Will result in a assertion error from atlas - stating that the control is dublicate (it is not - looking at the source) - and the script (set_enabled part) will set the xml enabled = false - but the update continues. Im having a hard time - anyone got this to work?

Here is my (not functional) Marts CTP version of the control - what am I doing wrong here ?

public

classStoppableTimer :TimerControl {public StoppableTimer() {

}

protectedoverridevoid OnPreRender(EventArgs e) {base.OnPreRender(e);if (Page.IsPostBack) {

Page.ClientScript.RegisterStartupScript(Page.GetType(),

"TimerStop","Sys.Application.findObject('" + UniqueID +"').set_enabled(" + (Enabled ?"true" :"false") +");"

,

true);

}

}

protectedoverridevoid RenderScript(Microsoft.Web.Script.ScriptTextWriter writer) {

writer.WriteStartElement(

"timer");

writer.WriteAttributeString(

"id", UniqueID);

writer.WriteAttributeString(

"interval", Interval.ToString(System.Globalization.CultureInfo.InvariantCulture));

writer.WriteAttributeString(

"enabled", Enabled.ToString());

writer.WriteStartElement(

"tick");

writer.WriteStartElement(

"postBack");

writer.WriteAttributeString(

"target", UniqueID);

writer.WriteAttributeString(

"eventArgument",string.Empty);

writer.WriteEndElement();

writer.WriteEndElement();

writer.WriteEndElement();

}

}


This solved my problem of the timer not writing out an ID when its created on the server. Also I'm very happy there is a script writer.

protected override void RenderScript(Microsoft.Web.Script.ScriptTextWriter writer)

Thanks.


Thank you everyone who contributed in previous posts

I've got this workn with March CTP in internet explorer 6

Its mostly the same but my main goal was to create a timer on the server and be able to stop and start it on the client and there was no clientid there. Argh I already have vb in app_code so its now vb and it has a Namespace to match my other Atlas stuff.

Heres the prerender routine. First off I'm adding a script to use on the client to start and stop the timer. Since I check the result of the findobject I don't bother checking for postback and I use enabled.tostring.tolower instead of the inline if.

Imports

Microsoft.VisualBasic

Imports

Microsoft.Web.UI.Controls

Namespace

DWS.Web.AtlasProtectedOverridesSub OnPreRender(ByVal eAs System.EventArgs)IfNotMe.Page.ClientScript.IsClientScriptBlockRegistered(Me.GetType,"DWSTimerStartStop")ThenDim sbAsNew StringBuilder

sb.Append(

"function DWSTimerStartStop (clientid,boolstop){")

sb.Append(

"var s = Sys.Application.findObject(clientid);")

sb.Append(

"if (s) {s.set_enabled(boolstop)};")

sb.Append(

"}")

Page.ClientScript.RegisterClientScriptBlock(

Me.GetType,"DWSTimerStartStop", sb.ToString,True)EndIfIfNotMe.Page.ClientScript.IsStartupScriptRegistered(Me.GetType,"DWSTimerStartStop" &Me.ClientID)ThenDim sbAsNew StringBuilder

sb.Append(

"DWSTimerStartStop(""" &Me.ClientID &""",")

sb.Append(

Me.Enabled.ToString.ToLower)

sb.Append(

");")

Page.ClientScript.RegisterStartupScript(

Me.GetType,"DWSTimerStartStop" &Me.ClientID, sb.ToString,True)EndIfMyBase.OnPreRender(e)EndSub

I think everyone had the renderscript. I put a MS timercontrol on the page and checked the render xml-script side by side (view source on browser) so I could compare the groups control output with that of Atlas.

ProtectedOverridesSub RenderScript(ByVal writerAs Microsoft.Web.Script.ScriptTextWriter)

writer.WriteStartElement("timer")

writer.WriteAttributeString("id",Me.ClientID)

writer.WriteAttributeString("interval",Me.Interval.ToString(System.Globalization.CultureInfo.InvariantCulture))

writer.WriteAttributeString("enabled",Me.Enabled.ToString())

writer.WriteStartElement("tick")

writer.WriteStartElement("postBack")

writer.WriteAttributeString("target",Me.UniqueID)

writer.WriteAttributeString("eventArgument",String.Empty)

writer.WriteEndElement()

writer.WriteEndElement()

writer.WriteEndElement()

EndSub

EndClass

I was going for server so here's a server example

PartialClass C_photo

Inherits DWS.Web.WebParts.WebPartBasectrl

'here it is

PrivateWithEvents txAsNew DWS.Web.Atlas.TimerControl

ProtectedSub Page_Load(ByVal senderAsObject,ByVal eAs System.EventArgs)HandlesMe.Load

'Set timer interval

tx.ID =

"dan1"

tx.Interval = 5000

Me.Controls.Add(tx)'Here are my two controls that operate on the client. They use the script generated in the control prerender.

Dim xAsNew HtmlButton

x.InnerText ="stop"

x.Attributes.Add(

"onclick","DWSTimerStartStop(""" & tx.ClientID &""",false)")Me.Controls.Add(x)Dim yAsNew HtmlButton

y.InnerText =

"start"

y.Attributes.Add(

"onclick","DWSTimerStartStop(""" & tx.ClientID &""",true)")Me.Controls.Add(y)EndSub

EndNamespace

And of course the group goal of having the enabled works too.

Protected

Sub Button1_Click(ByVal senderAsObject,ByVal eAs System.EventArgs)Handles Button1.ClickIf Button1.Text ="Stop"Then

Button1.Text =

"Play"

tx.Enabled =

FalseElse

Button1.Text =

"Stop"

tx_Tick(sender, e)

tx.Enabled =

TrueEndIfEndSub

Thank you to whoever started this thread.

Thank you to the scriptwriter example.

Thank you eventArgument fix.

DWS


I just started using Atlas with the April CTP. I'd really like to have the ability to cancel the timer. I can't seem to get this to work though. I converted the code in the previous post to C#. I think that went ok.

Should the Timer control be incuded in the UpdatePanel or should it be outside the panel?

Thanks,

Andy


hello.

i'd put it out...btw, there's another thread on this forum (it's huge, maybe 3 pages now) that shows another option to clear a timer from a page.


Rama Krishna, this was very helpful!

I modified the code a bit to work with the April CTP, and added a few client side APIs to pause, resume and toggle the timer. Here is the modified code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.Web.UI.Controls;

namespace Yadda.Web.UI.WebControls {

/// <summary>
/// This is a workaround for an issue in the June CTP of Atlas - the provided TimerControl cannot be stopped or paused
/// by the client.
/// This is based on code from Rama Krishna, http://forums.asp.net/1222935/ShowPost.aspx
/// This one inherits from the provided TimerControl and fixes these issues.
/// Once this is fixed in Atlas this control should be removed and replaced with the standard one.
/// Client-side API:
/// TimerToggle(clientID) - toggles the timer between off and on state
/// TimerPause(clientID) - temporarily pause the timer; no events will be fired until TimerResume will be called.
/// TimerResume(clientID) - resumes a paused timer; Can be safely called multiple times.
/// </summary>public class TimerControlWithPause : TimerControl {
public TimerControlWithPause() {
//
// TODO: Add constructor logic here
//}protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
// Render client-side APIs:this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(),"TimerToggle",
"function TimerToggle(clientId) {" +
"var timerObj = $object(clientId); " +
"if (!timerObj) return; " +
"if (timerObj.get_enabled()) TimerPause(clientId); else TimerResume(clientId); " +
"}" +
"function TimerPause(clientId) {" +
"var timerObj = $object(clientId); " +
"if (!timerObj) return; " +
"timerObj.set_enabled(false); " +
"}" +
"function TimerResume(clientId) {" +
"var timerObj = $object(clientId); " +
"if (!timerObj) return; " +
"timerObj.set_enabled(true); " +
"}",
true);// This will sync the client side state with the server state on postbacks:if (this.Page.IsPostBack) {
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(),"TimerStop",
(this.Enabled ?string.Format("TimerResume('{0}');",this.ClientID) :string.Format("TimerPause('{0}');",this.ClientID))
,true);
}
}

protected override void RenderScript(Microsoft.Web.Script.ScriptTextWriter writer) {
writer.WriteStartElement("timer");
writer.WriteAttributeString("id",this.ClientID);
writer.WriteAttributeString("interval",this.Interval.ToString(System.Globalization.CultureInfo.InvariantCulture));
writer.WriteAttributeString("enabled",this.Enabled.ToString());
writer.WriteStartElement("tick");
writer.WriteStartElement("postBack");
writer.WriteAttributeString("target",this.UniqueID);
writer.WriteAttributeString("eventArgument",string.Empty);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}


Nice solution yanivgolan. This is working great.


I'm still waiting for Visual Web Developer to finish installing- I have no experience with Atlas and very little ASP.net experience and this thread is a little old, but it sounds like the timer thing is a bug that will be fixed in future versions of Atlas, so a lot of these workarounds seem a little convoluted... wouldn't the following workaround be good enough for most applications until Atlas fixes itself??:

protected void timerProgress_Tick(object sender, EventArgs e)
{

If (timerProgress.Enabled )
CheckBox1.Checked = !CheckBox1.Checked;
}


When I use code similar to this... (I've actually tried it a few different ways now...) It compiles and runs fine under VS 2005's internal web... But when I try to publish it and run it from any other stand alone web server (including the IIS on the same box the VS 2005 is on) I get an error when I try to load the page:

Compilation Error

Description:An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message:CS0117: 'ASP.default_aspx' does not contain a definition for 'myTimer_Tick'

Source Error:


Line 16: </atlas:ScriptManager>
Line 17: <div>
Line 18: <AppCode:StopableTimer runat="server" ID="myNewTimer" Enabled="false" Interval="900" OnTick="myTimer_Tick">
Line 19: </AppCode:StopableTimer>


Does anyone have any sort of suggestion as to why this may be happening, and how I might fix it..?

Any thoughts or suggestions would be very much appreciated!

Thanks! ;)

- Andrew

hello.

according to the error message, it seems like the myTimer_Tick method isn't being found. where have you defined it?


Hello,

Thanks for the reply...

Of course... myTimer_Tick -has- to be defined, or it would not run under Visual Studio, right? ;)

But you're right in that it seems it isn't being found.. but why not..?

It is defined in the Default.aspx.cs file - referenced as the "CodeFile" at the top of the Default.aspx file. Here's the top two lines of my Default.aspx file:

<%@. Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@. Register TagPrefix="AppCode" Namespace="MyCustomControls" %
The Namespace is where the StoppableTimer is that's similar to the code a few posts above, which I got from:

http://runithomsen.blogspot.com/2006_03_01_runithomsen_archive.html

Do I need to define it some other way..? It still doesn't make sense (to me!) that it works under Visual Studio's internal web browser, but not when I publish it to an IIS server. :(

Any thoughts or suggestions would be appreciated! :)

Thanks!

Cheers

- Andrew

a bug of ServicePath

the ServicePath can't parse "~/", since the control runs at "server", it should can.Agreed - we'll get a fix for this and post the code here.

Good find, mg1616! This issue was also brought up by someone else in a separate instance. I've just checked the following change in to the implementation of CascadingDropDown so it'll be available with future releases of the Atlas Control Toolkit. For now, simply paste the new method below into the implementation of the CascadingDropDown class in CascadingDropDownExtender.cs (perhaps below the OnLoad override). My testing suggests that it enables "~"-based virtual paths as requested.

Thanks so much for your help!

/// <summary>/// Override ExtenderControlBase.SerializePropertyToString to fix up virtual path references/// </summary>protected override string SerializePropertyToString(CascadingDropDownProperties props, PropertyDescriptor prop,bool force){string result =base.SerializePropertyToString(props, prop, force);// Fix up virtual path references for the ServicePath propertyif ("ServicePath" == prop.Name) { result = ResolveClientUrl(result); }return result;}

Regarding this:

if ("ServicePath" == prop.Name)

It seems to me that we have some incestuous knowlege of the name of the property. I suggest that in general the property names should be exposed by the respective Properties class. This would eliminate a whole host of oopsies. That gets us to:

public class CascadingDropDownProperties : TargetControlPropertiesBase<DropDownList>{// Constant strings for each property namepublic const string stringParentControlID ="ParentControlID";public const string stringCategory ="Category";public const string stringPromptText ="PromptText";public const string stringServicePath ="ServicePath";public const string stringServiceMethod ="ServiceMethod";

Of course, that makes the names of the constants appear quite ugly (I thought "Hungarian" notation was dead by now). My coding convention leads to this:

public class CascadingDropDownProperties : TargetControlPropertiesBase<DropDownList>{// Constant strings for each property namepublic static class PropertyName {public static readonly string ParentControlID ="ParentControlID";public static readonly string Category ="Category";public static readonly string PromptText ="PromptText";public static readonly string ServicePath ="ServicePath";public static readonly string ServiceMethod ="ServiceMethod"; };


Yeah, I see your point. I'm not really sure that makes ita lotbetter with respect to your concern. In either case you're still relying on the property string name. Your method is a little better, I'll agree.

But in this case, David and I were talking and think we have an even more general solution in mind that would require none of this. Basically, mapping a property to a client URL is something that will happen regularly so I think we'll bake this into the framework for our next release, probably later this month.

Thanks!

A bug in AJAX RC ScriptManager

I've been adopting MS AJAX Extensions, and founded a small bug, wich i would like to describe in that post.

It's about script registration order when using ScriptManager static methods. As I suppose, they should work same way as Page.ClientScript methods. But, they don't, wich i believe is a bug.

When someone registers more than one script via ScriptManager with different Control references, the order of script registration is undetermined. And ClientScriptManager (Page.ClientScript) registers scripts in order as they were registered in user code.

I've looked via reflector into the scriptmanager code, and it seems, the bug source is System.Web.UI.ScriptRegistrationManager+ScriptSubmitStatementEntry class wich stores registered script entries in a ScriptBlocks property of type Dictionary<Control, List<ScriptBlockEntry>>.

That effectively means, that when i register some scripts with same control entry, the order of registration is right, but when i pass different control instances - the order is undermined due to Dictionary implementation (HashTable).

So. If we have;

Control button1 = new Button();
Control button2 = new Button();

ScriptManager.RegisterClientScriptInclude(button1, ...)
ScriptManager.RegisterClientScriptInclude(button2, ...)

The second script may actually register before first one, wich can lead to a bugs. Because script registration order is important.

I'm not sure where to submit this, so i hope someone will fix it.

Hi...

I don't think that's a bug, actually. If you look at the "ClientScriptManager.RegisterStartupScript Method (Type, String, String)" documentation, under "Remarks", it notes that "...The script blocks are not guaranteed to be output in the order they are registered. ". It offers the suggestion that, if you need the scripts in a specific order, you should concatenate them together in a single string and register that.

Hope this helps.


Hm.. interesting point. There is no such remark on RegisterScriptInclude method.

And actually, it works as i described. Maintaining the order. I think scripts are stored in arbitary array or list inside page.

Still, even if it's not a formal bug, it clearly a wrong behavior. ScriptManager states that it's methods can be used simply instead Page.ClientScrip methods, and it's obviously not true in that case.

If you programmatically register includes, you often don't have an option of concatenation. And still need to maintain the correct order.


JiCheng, you're incorrect.

There is indeed a static RegisterScriptInclude method on the ScriptManager object in the RC. And no, you cannot simply use Page.ClientScript.RegisterScriptInclude instead. This won't work in asynchronous postback scenarios.

To answer the original question, multiple calls to RegisterClientScriptIncludeshould result in loading the scripts in the order you registered them. I did a quick test with just two files, and they loaded in order on the client. (I checked by putting an alert() in each, so I could watch what order the alerts popped up.) When I switched the order of the RegisterClientScriptInclude calls, the order switched on the client as well.

To sum up, I can't reproduce the behavior you're seeing (where order isn't guaranteed), but I would consider it a bug. Please share code that reproduces this bug so I can verify.


I gotScriptManager.RegisterClientScriptInclude Method (control, type, key, url) method from this document -http://ajax.asp.net/docs/mref/M_System_Web_UI_ScriptManager_RegisterClientScriptInclude_4_6597d783.aspx.

TheRegisterClientScriptInclude(Control, Type, String, String) method is used to register a client script file for a page or part of a page that is participating in partial-page updates. If your page or part of the page is not using partial-page updates and you want to register a client script file, use the ClientScriptManager class registration methods. You can get a reference to ClientScriptManager object from the ClientScript property of the page.

TheRegisterClientScriptInclude(Control, Type, String, String) method registers a client script file on the page by rendering a <script> element with a src attribute. The url parameter is used to set the src attribute of the <script> element. To resolve client URLs, use the ResolveClientUrl(String) method. This method uses the context of the URL on which it is called to resolve the path.

Both theRegisterClientScriptInclude(Control, Type, String, String) andRegisterClientScriptResource(Control, Type, String) methods load script files into the browser. If a script with the same type and key (for a script file) or type and resource name (for a script resource) is already loaded, the script is not reloaded. The script blocks that are loaded using these two methods should avoid script that executes inline functions and should instead should contain function definitions and other supporting definitions for your application.

Sample Codes as follows:

%@. Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
public void Page_Load(Object sender, EventArgs e)
{
if (!IsPostBack)
Calendar1.SelectedDate = DateTime.Today;

}
protected void Page_PreRender(object sender, EventArgs e)
{
ScriptManager.RegisterClientScriptInclude(
this,
typeof(Page),
"AlertScript",
ResolveClientUrl("~/scripts/script_alertdiv.js"));
}
protected void IncrementButton_Click(object sender, EventArgs e)
{
Calendar1.SelectedDate = Calendar1.SelectedDate.AddDays(1.0);
}
protected void DecrementButton_Click(object sender, EventArgs e)
{
Calendar1.SelectedDate = Calendar1.SelectedDate.AddDays(-1.0);
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ScriptManager RegisterClientScriptInclude</title>
<style type="text/css">
div.MessageStyle
{
background-color: Green;
top: 95%;
left: 1%;
position: absolute;
visibility: hidden;
}
</style>
</head>
<body>
<form id="Form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1"
runat="server"/>

<script type="text/javascript">
Sys.WebForms.PageRequestManager.instance.add_endRequest(Notify);
</script>

<asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional"
runat="server">
<ContentTemplate>
<asp:Calendar ID="Calendar1" runat="server"/>
<br />
Change the selected date:
<asp:Button runat="server" ID="DecrementButton" Text="-" OnClick="DecrementButton_Click" />
<asp:Button runat="server" ID="IncrementButton" Text="+" OnClick="IncrementButton_Click" />
</ContentTemplate>
</asp:UpdatePanel>

<div id="NotifyDiv" class="MessageStyle">
Updates are complete.
</div>
</div>
</form>
</body>
</html>


Note I have two typos in my first paragraph where I wrote "RegisterScriptInclude" instead of "RegisterClientScriptInclude." Sorry for any confusion.