Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / XHTML

AJAX UpdatePanel With Inline Client Scripts Parser

3.29/5 (5 votes)
9 Oct 2008CPOL 1  
AJAX UpdatePanel with inline client scripts parser.

Introduction

This control solves the problem when you need inline client scripts within an ASP.NET UpdatePanel to work. Inline scripts, to my knowledge, are not registered to the Script Manager when the "AJAX call" is made. The problem occurs if you have a UserControl, containing an inline script that is dynamically added into an UpdatePanel after an AJAX postback.

Background

If you, like me, already have (had) an existing Web application that's cluttered with inline scripts, and want to take advantage of the features that ASP.NET AJAX provides, you might find yourself with a tedious refactoring job. I managed to solve 99% (1% was invalid markup) of all my inline script problems by using this control.

Hopefully, it can do the same for you!

Using the Code

The control inherits from the original UpdatePanel and uses a Regex to parse for client scripts. You use it just like the original UpdatePanel, and can switch on/off the parsing for inline scripts by setting the property RegisterInlineClientScripts to false.

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Text.RegularExpressions;
using System.IO;

namespace Tuna.Web.Controls
{
public class TunaUpdatePanel : UpdatePanel
{
    private static readonly Regex REGEX_CLIENTSCRIPTS = new Regex(
    "<script\\s((?<aname>[-\\w]+)=[\"'](?<avalue>.*?)[\"']\\s?)*\\s*>(?<script>.*?)</script>",
    RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled |
    RegexOptions.ExplicitCapture);
    private bool m_RegisterInlineClientScripts = true;

    /// <summary>
    /// If the updatepanel shall parse and append inline scripts, default true
    /// </summary>
    public bool RegisterInlineClientScripts
    {
        get
        {
            return this.m_RegisterInlineClientScripts;
        }
        set
        {
            this.m_RegisterInlineClientScripts = value;
        }
    }

    protected virtual string AppendInlineClientScripts(string htmlsource)
    {
        if (this.ContentTemplate != null && htmlsource.IndexOf(
            "<script", StringComparison.CurrentCultureIgnoreCase) > -1)
        {
            MatchCollection matches = REGEX_CLIENTSCRIPTS.Matches(htmlsource);
            if (matches.Count > 0)
            {
                for (int i = 0; i < matches.Count; i++)
                {
                    string script = matches[i].Groups["script"].Value;
                    string scriptID = script.GetHashCode().ToString();
                    string scriptSrc = "";

                    CaptureCollection aname = matches[i].Groups["aname"].Captures;
                    CaptureCollection avalue = matches[i].Groups["avalue"].Captures;
                    for (int u = 0; u < aname.Count; u++)
                    {
                        if (aname[u].Value.IndexOf("src",
                            StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            scriptSrc = avalue[u].Value;
                            break;
                        }
                    }

                    if (scriptSrc.Length > 0)
                    {
                        ScriptManager.RegisterClientScriptInclude(this,
                            this.GetType(), scriptID, scriptSrc);
                    }
                    else
                    {
                        ScriptManager.RegisterClientScriptBlock(this, this.GetType(),
                            scriptID, script, true);
                    }

                    htmlsource = htmlsource.Replace(matches[i].Value, "");
                }

            }
        }
        return htmlsource;
    }

    protected override void RenderChildren(HtmlTextWriter writer)
    {
        ScriptManager sm = ScriptManager.GetCurrent(Page);
        if (this.RegisterInlineClientScripts && sm != null && sm.IsInAsyncPostBack)
        {
            using (HtmlTextWriter htmlwriter = new HtmlTextWriter(new StringWriter()))
            {
                base.RenderChildren(htmlwriter);

                string html;
                int outputSize;

                //Get the actual rendering and size
                html = htmlwriter.InnerWriter.ToString();
                outputSize = html.Length;

                //Append inlinescripts and fetch the new markup and size
                html = this.AppendInlineClientScripts(html);
                outputSize -= html.Length;

                //Replace ContentSize if there are any gains
                if (outputSize > 0)
                {
                    html = this.SetOutputContentSize(html, outputSize);
                }

                writer.Write(html);
            }
        }
        else
        {
            base.RenderChildren(writer);
        }
    }

    private string SetOutputContentSize(string html, int difference)
    {
        string[] split = html.Split('|');
        int size = int.Parse(split[0]);
        split[0] = (size - difference).ToString();
        return string.Join("|", split);
    }
}
}

Optimization suggestions are welcome!

Enjoy!

Thanks to Rogic for solving the issue I hade with replacing the response context to opitmize traffic!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)