ASP.NET ClientScriptManager


Sponsored Links

73058_New Scooba® 230 Floor Washing Robot + Free Shipping!

 

ClientScriptManager

Here we take a brief look at the ClientScriptManager object in ASP.NET and look at how it helps when dealing with Javascript.

ClientScriptManager

We can use the ClientScriptManager in our C# code to make life a little easier when working with Javascript on our client side. It offers some methods which help to utilise some of built-in features which come with ASP.NET. This is actually the main reason you'll probably use the ClientScriptManager for. You don't need to use it to run Javascript on ASP.NET pages, but there are certain situations when it makes like a little easier, such as when you want to generate Javascript from within your C#, or you need your Javascript to cause a Postback.

Here is a summary of some of it's main methods (which some can be overloaded methods too). Just taking a quick look suggests that it offers some solutions to some of the errors we can encounter when we're using ASP.NET AJAX:


GetCallbackEventReference

GetPostBackClientHyperlink

GetWebResourceUrl

IsClientScriptBlockRegistered

IsClientScriptIncludeRegistered

IsOnSubmitStatementRegistered

IsStartupScriptRegistered

RegisterClientScriptBlock

RegisterClientScriptInclude

RegisterClientScriptResource

RegisterForEventValidation

RegisterOnSubmitStatement

RegisterStartupScript

ValidateEvent


RegisterClientScriptBlock

We'll start with some basics. RegisterClientScriptBlock is the one way I came across first many years ago now, it allows one to write out Javascript code from within C# which will be placed and executed on the ASP.NET page once it has loaded. Passing in parameters which specify a unique key and type for the Javascript help keep if from been duplicated on the page. You can have it optionally provide the opening and closing <script> as well.

The following code creates some Javascript in C#, such that when the page loads the Javascript function alert will pop up a message for us:


protected void Page_Load(object sender, EventArgs e)
{
    ClientScriptManager csm = Page.ClientScript;
    csm.RegisterClientScriptBlock(this.GetType(), "myKey", "alert('hi');", true);
}


IsClientScriptBlockRegistered

A simple add on for RegisterClientScriptBlock is the method IsClientScriptBlockRegistered which checks to see if a particular Javascript code block has already been added to the page with RegisterClientScriptBlock based on the unique key and optionally type we specified in the call to RegisterClientScriptBlock.


ClientScriptManager csm = Page.ClientScript;

if (!csm.IsClientScriptBlockRegistered(this.GetType(), "myKey"))
{
    csm.RegisterClientScriptBlock(this.GetType(), "myKey2", "alert('2nd');", true);
}


RegisterClientScriptInclude

We should be trying to strive to keep our Javascript in external files, you adding Javascript by hand in C# may not be what you're doing. So RegisterClientScriptInclude offers the functionality of RegisterClientScriptBlock but for external files, so in C# we can create a script link to an external file:


protected void Page_Load(object sender, EventArgs e)
{
    ClientScriptManager csm = Page.ClientScript;
    csm.RegisterClientScriptInclude(this.GetType(), "myKey", ResolveClientUrl("~/Scripts/jscript.js"));
}



// jscript.js
alert('hello');


The resulting output is:


<script src="Scripts/jscript.js" type="text/javascript"></script>


IsClientScriptIncludeRegistered

Again we have a method called IsClientScriptIncludeRegistered which allows us to check to see if we have registered a particular include file, IsClientScriptIncludeRegistered

RegisterOnSubmitStatement

Well this is quite an interesrting one, RegisterOnSubmitStatement acts a little bit like an UpdateProgress control in that this method registers some Javascript to fire off once the HTML form has been submitted, well actually just before it's submitted. So my initial thoughts are instead of having an animated GIF in the UpdateProgress control you could actually execute some Javascript of some sort. Again there is a related method called IsOnSubmitStatementRegistered which allows you to check if you have already registered a particular Javascript piece of code, identified by the unique key you provide in RegisterOnSubmitStatement.

So for the code behind in my demo aspx page I used the following C#:


protected void Page_Load(object sender, EventArgs e)
{
    ClientScriptManager csm = Page.ClientScript;

    if (!csm.IsOnSubmitStatementRegistered("myKey"))
    {
        csm.RegisterOnSubmitStatement(Page.GetType(), "myKey", "alert('Posting back');");
    }
}

protected void Button_Postback_OnClick(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(2000);

    Label1.Text = "I'm back";
}


In my ASPX page I have a Button and a Label:


<asp:Button ID="Button_Postback" runat="server" Text="Cause a postback" OnClick="Button_Postback_OnClick" />

<asp:Label Text="text" ID="Label1" runat="server" />


So what happens, well the Page_Load event with RegisterOnSubmitStatement actually inserts the following markup into the HTML:


<script type="text/javascript">
//<![CDATA[
function WebForm_OnSubmit() {
    alert('Posting back');
    return true;
}
//]]>
</script>


So the RegisterOnSubmitStatement has injected our Javascript into the WebForm_OnSubmit function which is the name of the function called when ASP.NET posts back. What's the result of this, well when we click on the Button control to cause a postback, our Javascript executes, and in this case as it's an alert box, the Postback does not occur until I click the OK button. The MSDN documentation says it's possible to cancel the postback using RegisterOnSubmitStatement, or you could do whatever Javascript you wanted to. Perhaps you could dim the screen, or animate an object or something else?

RegisterStartupScript

RegisterStartupScript works by getting your Javascript to fire when page loads. Almost like a Resonse.Write it writes exactly the Javascript you provide, so you may need to put your own <script> tags to the bottom of the page. Also provided by the ClientScriptManager is the IsStartupScriptRegistered method which can be used to indicate if a piece of Javascript has already been registered to the page using the unique key and type.


protected void Page_Load(object sender, EventArgs e)
{
    ClientScriptManager csm = Page.ClientScript;

    if (!csm.IsStartupScriptRegistered(Page.GetType(), "myKey"))
    {
        csm.RegisterStartupScript(Page.GetType(), "myKey", "<script type='text/javascript'>alert('Firing engines up!');</script>");
    }
}


This wrote the exact text I gave it to the HTML output:


<script type='text/javascript'>alert('Firing engines up!');</script>


GetPostBackClientHyperlink

GetPostBackClientHyperlink lets you perform a postback using client code whilst specifying an event argument to pass back. You need to implement the interface IPostBackEventHandler which simply means you need to implement a method called RaisePostBackEvent which acts as the method which will deal with your postback created from GetPostBackClientHyperlink, receiving the argument you specified, almost like a Click or Command event handler of a button.

Well I struggled with this one for a little while to get working, until I discovered I needed to use the 'this' reference as the control to reference, rather than the actual control I was applying the resultant text to.


using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace Demo_ClientScriptManager
{
    public partial class PostBackLinkHyperLink1 : System.Web.UI.Page, IPostBackEventHandler
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            HtmlInputButton button = (HtmlInputButton)this.FindControl("SomeButton");

            ClientScriptManager csm = Page.ClientScript;

            String link = csm.GetPostBackClientHyperlink(this, "roses are red");

            button.Attributes.Add("onclick", link);
        }

        public void RaisePostBackEvent(string eventArgument)
        {
            String argument = eventArgument;
        }
    }
}


The associated ASPX is simply:


<input type="button" value="Click Me" runat="server" id="SomeButton" />


So in my example I've actually used the result of GetPostBackClientHyperlink to be applied to the onclick client side event of my HTML button, in effect causing a postback to the server when you click the HTML button, passing in a string 'roses are red' as the argument, which can then be retrieved in the RaisePostBackEvent method.

So what did GetPostBackClientHyperlink actually output into the HTML in this case> A javascript call to __doPostBack passing in the Page and my 'roses are red' string as parameters:


javascript:__doPostBack('__Page','roses are red')


GetCallbackEventReference

The ClientScriptManager's GetCallbackEventReference produces Javascript code which causes a client callback from a client Javascript function. The page needs to implement the interface ICallbackEventHandler, so you'll need to implement methods GetCallbackResult and RaiseCallbackEvent in the server code.

Here is my C# to get started:


using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace Demo_ClientScriptManager
{
    public partial class DemoCallbackEventRef3 : System.Web.UI.Page, ICallbackEventHandler
    {
        private string _CallBackResult = null;
        protected void Page_Load(object sender, EventArgs e)
        {
            ClientScriptManager csm = Page.ClientScript;

            HtmlInputButton button = (HtmlInputButton)this.FindControl("ButtonCallback");

            string callbackRef = csm.GetCallbackEventReference(this, "arg", "ReceiveFromServer", "context");

            string callbackScript = "function UseCallback(arg,context){ context = context + '. Start from callback.'; " + callbackRef + "; }";

            csm.RegisterClientScriptBlock(this.GetType(), System.Guid.NewGuid().ToString(), callbackScript, true);

            button.Attributes.Add("onclick", "return UseCallback('paramForServer','paramForClientFromServerCallbck');");
        }

        public void RaiseCallbackEvent(string eventArgument)
        {
            _CallBackResult = eventArgument + ". On Server for Raise callback";
        }

        public string GetCallbackResult()
        {
            return _CallBackResult;
        }
    }
}


In the .ASPX I have the following code, simply a HTML Input button and a Javascript function to be called once the callback is sent back from the server to the client:


<script type="text/javascript"> function ReceiveFromServer(result, context) {
    alert(result + ". Arrived at final destination");
    alert(context + ". Arrived at final destination");
}
</script>

...

<input type="button" value="Start Callback" id="ButtonCallback" runat="server" />


I have to admit that I got a little lost trying to work out how to use GetCallbackEventReference and had to refer to some sample code at MSDN to get something working.

So what Javascript was generated when we called upon GetCallbackEventReference? Well it's a call to WebForm_DoCallback passing in our parameters we specified in the call to GetCallbackEventReference.


<script type="text/javascript">
//<![CDATA[
function UseCallback(arg,context){ context = context + '. Start from callback.';
WebForm_DoCallback('__Page',arg,ReceiveFromServer,context,null,false); }//]]>
</script>


So all this caused the HTML button to callback to the server, executing through the RaiseCallbackEvent and GetCallbackResult methods before getting to our client side registered function ReceiveFromServer. It's quite interesting to see how our 2 original parameters used in the starting method on the client generated by GetCallbackEventReference get used, and this looks like some interesting usage could be made if you were to use GetCallbackEventReference in a real-world project, perhaps in overcoming so postback issues you're having or some magic from a client side control.

The final parameter values:


paramForServer. On Server for Raise callback. Arrived at final destination.
paramForClientFromServerCallbck. Start from callback.. Arrived at final destination


RegisterForEventValidation and ValidateEvent

RegisterForEventValidation and ValidateEvent work together to register an event reference for validation for a client control and to validate that the event was registered for event validation. Time pushed I'm a little vague on this at the moment, but here can serve as a basis to work from should I ever encounter the 'Event not registered for EventValidation' error with this working example:


using System;
using System.Web.UI;

namespace Demo_ClientScriptManager
{
    public partial class ValidatingEventReg : System.Web.UI.Page, ICallbackEventHandler
    {
        Boolean passedEventValidation = false;

        protected void Page_Load(object sender, EventArgs e)
        {
            ClientScriptManager csm = Page.ClientScript;

            String cbReference = csm.GetCallbackEventReference("'" +
                Page.UniqueID + "'", "arg", "ReceiveServerData", "",
                "ProcessCallBackError", false);
            String callbackScript = "function CallTheServer(arg, context) {" +
                cbReference + "; }";
            csm.RegisterClientScriptBlock(this.GetType(), "CallTheServer",
                callbackScript, true);
        }

        public void RaiseCallbackEvent(string eventArgument)
        {
            try
            {
                ClientScriptManager csm = Page.ClientScript;

                csm.ValidateEvent(clientButton.UniqueID);

                passedEventValidation = true;
            }
            catch (Exception ex)
            {

            }
        }

        public string GetCallbackResult()
        {
            return passedEventValidation.ToString();
        }

        protected override void Render(HtmlTextWriter writer)
        {
            ClientScriptManager csm = Page.ClientScript;
            csm.RegisterForEventValidation(clientButton.UniqueID);

            base.Render(writer);
        }
    }
}