Dynamically create ASP.NET user control using ASP.NET Ajax and Web Service

Thanks for your tremendous response for my first post on asp.net blog Reduce ASP.NET Page size and complexity using JQuery-Part 1. Within last 10 days it's got more then 1500 views. To subscribe my blog through mail, Please click here subscribe blog by email.

In this post I will explain how to load ASP.NET user control dynamically using ASP.NET AJAX and Web Service. In next post I will explain the samething using JQuery. Lot of user asked me to mentioned examples in VB.NET, so in this article, I will explain code in both language C#/VB.NET.      

You can download the VB.NET solution code here and the C# solution code here

To make web UI dynamic and more responsive to the various situations and modes, several techniques are used by the developers like making irrelevant controls invisible, disabling unused controls. This technique makes you page complex and heavy in size. Dynamic user control is another story. With dynamic control creation you will get the unmatched flexibility and innovation with robustness. Using this technique you can add any usercontrol to any page as per demand without postback or update panel.

I am using the last post example and extending it to use this feature. In last post I created the gridview control and placed on the page, In this example I will create this control on page dynamically using web service and ASP.NET Ajax and enhance it to support tooltip, mouseover, mouseout and click effect using ASP.NET Ajax client side framework. 

Below is the screenshot of the initial page.

Gridview Effect 

When user clicks on "Load Customer Order", It will call the webservice get the usercontrol html data and load in the 'testDIV'.

Gridview Effect 

Same way user can clicks on "load login" button to load "User Login" form.

Gridview Effect 

the XHTML code of the page in mentioned below.  

<%@ Page Language="C#" EnableViewState="false" %>

<!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 id="head" runat="server">

    <title>With MS Ajax</title>

    <link type="text/css" href="StyleSheets/iGridView-classic.css" rel="stylesheet" />

    <link type="text/css" href="StyleSheets/iGridView-common.css" rel="stylesheet" />

    <style type="text/css">

        body

        {

            width:95%;

            padding-left:20px;

            font-family:Arial;

            font-size:10pt;

            padding-right:20px;

        }

    </style>

</head>

<body>

    <form id="form" runat="server">

        <asp:ScriptManager runat="server">

        <Services>

        <asp:ServiceReference Path="~/ScriptService.asmx" />

        </Services>

        </asp:ScriptManager>

        <input type="button" value="Load Customer Order" onclick="getData('~/Controls/GridView.ascx');" />

        <input type="button" value="Load Login" onclick="getData('~/Controls/LoginControl.ascx');" />

        <input type="button" value="Register New User" onclick="getData('~/Controls/NewUserControl.ascx');" />

        <div id="testDiv"></div>

    </form>

</body>

</html>


To use web service on page you need to mention it in ScriptManager.

<asp:ScriptManager runat="server">

<Services>

<asp:ServiceReference Path="~/ScriptService.asmx" />

</Services>

</asp:ScriptManager>


Also update maxJsonLength in web.config otherwise you will get "maximum length exceed" exception for large json data.

<system.web.extensions>

              <scripting>

                     <webServices>

        <jsonSerialization maxJsonLength="5000000" />

                     </webServices>

              </scripting>

       </system.web.extensions>

 


Below is the code of webservice file in C# with comment, don't forget to add

System.Web.Script.Services.ScriptService() attribute to mark this web service as script service. 

using System;

using System.Collections;

using System.IO;

using System.Text.RegularExpressions;

using System.Web;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.Services;

using System.Web.Services.Protocols;

 

/// <summary>

/// Summary description for ScriptService

/// To access from ASP.NET AJAX remember to mentioned

/// System.Web.Script.Services.ScriptService() attribute

/// </summary>

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.Web.Script.Services.ScriptService()]

public class ScriptService : System.Web.Services.WebService

{

 

    public ScriptService()

    {

        //Uncomment the following line if using designed components

        //InitializeComponent();

    }

 

    /// <summary>

    /// Get User Control Html

    /// use EnableSession=true if you are using session variables

    /// </summary>

    /// <returns>Html Table</returns>

    [WebMethod(EnableSession = true)]

    public string GetControlHtml(string controlLocation)

    {

        // Create instance of the page control

        Page page = new Page();

 

        // Create instance of the user control

        UserControl userControl = (UserControl)page.LoadControl(controlLocation);

 

        //Disabled ViewState- If required

        userControl.EnableViewState = false;

       

        //Form control is mandatory on page control to process User Controls

        HtmlForm form = new HtmlForm();

 

        //Add user control to the form

        form.Controls.Add(userControl);

       

        //Add form to the page

        page.Controls.Add(form);

 

        //Write the control Html to text writer

        StringWriter textWriter = new StringWriter();

 

        //execute page on server

        HttpContext.Current.Server.Execute(page, textWriter, false);

       

        // Clean up code and return html

        return CleanHtml(textWriter.ToString());

    }

 

    /// <summary>

    /// Removes Form tags

    /// </summary>

    private string CleanHtml(string html)

    {

        return Regex.Replace(html, @"<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase);

    }

 

}


Same code of script service in VB.net is mentioned below

 

Imports System

Imports System.Collections

Imports System.IO

Imports System.Text.RegularExpressions

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.HtmlControls

Imports System.Web.Services

Imports System.Web.Services.Protocols

''' <summary>

''' Summary description for ScriptService

''' To access from ASP.NET AJAXremember to mentioned

''' System.Web.Script.Services.ScriptService() attribute

''' </summary>

<WebService([Namespace]:="http://tempuri.org/")> _

<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _

<System.Web.Script.Services.ScriptService()> _

Public Class ScriptService

    Inherits System.Web.Services.WebService

    'Uncomment the following line if using designed components

    'InitializeComponent();

    Public Sub New()

    End Sub

    ''' <summary>

    ''' Get User Control Html

    ''' use EnableSession=true if you are using session variables

    ''' </summary>

    ''' <returns>Html Table</returns>

    <WebMethod(EnableSession:=True)> _

    Public Function GetControlHtml(ByVal controlLocation As String) As String

        ' Create instance of the page control

        Dim page As New Page()

        ' Create instance of the user control

        Dim userControl As UserControl = DirectCast(page.LoadControl(controlLocation), UserControl)

        'Disabled ViewState- If required

        userControl.EnableViewState = False

        'Form control is mandatory on page control to process User Controls

        Dim form As New HtmlForm()

        'Add user control to the form

        form.Controls.Add(userControl)

        'Add form to the page

        page.Controls.Add(form)

        'Write the control Html to text writer

        Dim textWriter As New StringWriter()

        'execute page on server

        HttpContext.Current.Server.Execute(page, textWriter, False)

        ' Clean up code and return html

        Return CleanHtml(textWriter.ToString())

    End Function

    ''' <summary>

    ''' Removes Form tags

    ''' </summary>

    Private Function CleanHtml(ByVal html As String) As String

        Return Regex.Replace(html, "<[/]?(form)[^>]*?>", "", RegexOptions.IgnoreCase)

    End Function

 

End Class

The javascript code to access web service with comment is mentioned below.

<script type="text/javascript">

        ///<summary>Method for Web Service Failed Event</summary>

        ///<param name="error">Error Object</param>

        ///<returns>false</returns>

        function onFailedWS(error)

        {

         alert(error.get_message());

        }

   

        ///<summary>This is the callback function that processes the Web Service return value.</summary>

        ///<param name="result">result Object from Web Service</param>

        function SucceededCallback(result)

        {

            //get the div element

            var RsltElem = $get("testDiv");

            //update div inner Html

            RsltElem.innerHTML =result;

            //format table inside the div

            //if you have multiple table call format table in loop

            formatTable(RsltElem.getElementsByTagName('table')[0].id)

        }

   

        ///<summary>This function calls the GetControlHtml Web Service method.</summary>

        ///<param name="error">Succeed Object</param>

        ///<param name="error">Error Object</param>

        function getData(controlLocation)

        {

                ScriptService.GetControlHtml(controlLocation, SucceededCallback, onFailedWS);

        }

       

        function formatTable(gvID){

            //get the gridview

            var gv = $get(gvID);

            //get numbers of column in grid view

            cols = gv.rows[0].cells.length - 1;

            //get numbers of rows in grid view

            rows = gv.rows.length -1;

            //intialized looping variables

            var i=0;

            var j=0;

            //loop for each row in gridview

            for(i=1;i<rows;i++){

                //attach mouseover event for row

                $addHandler(gv.rows[i], "mouseover", mouseOver);

                //attach mouseout event for row

                $addHandler(gv.rows[i], "mouseout", mouseOut);

                //attach click event for row

                $addHandler(gv.rows[i], "click", onClick);

                 //loop for each cell in row

                for(j=0;j<cols;j++){

                        //set tooltip for cells in row

                    setTitle(gv.rows[i].cells[j]);                        

                }

            }   

        }

        function setTitle(object){

            //check browser type

            if(Sys.Browser.name =="Firefox"){

            object.title = object.textContent;

            }

            else{

            object.title = object.innerText;

            }

        }

       

        function mouseOver(objectEvent){

            //is row already clicked

            if(! isClickedStyleSet(objectEvent.target.parentNode.className))

            {

            //set class name

            objectEvent.target.parentNode.className = "row-over" ;

            //check browser type

             if(Sys.Browser.name !="Firefox"){

                objectEvent.target.parentNode.style.cursor ="hand";

            }}

        }

        function mouseOut(objectEvent){

            //is row already clicked

            if(! isClickedStyleSet(objectEvent.target.parentNode.className)){

            //set class name

            objectEvent.target.parentNode.className = "data-row" ;

        }}

        function onClick(objectEvent){

            //set class name

            if(! isClickedStyleSet(objectEvent.target.parentNode.className))

            {

                objectEvent.target.parentNode.className = "row-select" ;

            }

            else

            {

                objectEvent.target.parentNode.className = "data-row" ;

            }

        }

        function isClickedStyleSet(className){

            //if row is already clicked return true

            if(className == "row-select"){

            return true;

            }

            return false;

        }

    </script>


To load any usercontrol you need to call "getdata" function with control location and name for example
getData("~/Controls/GridView.ascx");.

The benefit of the above approach are following

  • No need to the add usercontrol on the page at design time
  • Post back not required to load new User control
  • Update panel not required
  • Developer/ User can add usercontrol to any web page
  • Developer can load control on demand 
  • It will reduce intial page size
  • Easy to create custom User interface
  • More Responsive as less data is loaded on page

In next post I will explain above approach with JQuery. Please post your valuable feedback for this article.

You can download the VB.NET solution code here and the C# solution code here

kick it on DotNetKicks.com

45 Comments

  • Please write your name or this web page address somewhere in your projects.

    Also good article. thanks

  • Hi, quick question. What is this part of the regex meant to match? [ovwxp]:\w+

  • Thanks John,
    To point out issue in regex. [ovwxp]:\w+ means Anything beginning with o,v,w,x,p, followed by a : followed by another word. This regex is not required for xhtml code. It is used to clean up ms word html.

  • Thanks for the quick response!

  • John,
    VB.NET/C# Code in the article is also updated based on your comment.

  • Good article. I worked on this issue for a good while and with the use of the "RenderView" method(got it from ScottGu's blog, but basically it is your "GetControlHtml" method with functionality I added in to use Ajax controls in the views that are being rendered). If you would be interested in this, I'd be more than willing to post it somewhere, and you could take it and build on top of it, blog on it, whatever you want.

  • Thanks for your suggestion. You can email me or post it on your blog.

  • Does anyone know of a way to get this to work with the ReportViewer control?

    I get the "Microsoft JScript runtime error: 'this.m_clientController' is null or not an object" error just after the ReportViewer gets displayed. I had read that this error would creep up with the ReportViewer is inside an UpdatePanel, so I guess it is a similar scenario.

    Thanks,
    Stephen

  • Hi, I tryed the example and it worked out fine, but instead of the user controls given, I made one with just a label and a button.
    It was supposed to change the label text wen the button was clicked.
    But It doesn`t work, when I click the button I get the error:'error executing child request fon handler 'system.web.uipage'
    Does anybody know how can I solve this?
    Thanks,
    Natalia

  • This is the error I get

    The state information is invalid for this page and might be corrupted.

  • You need to merge viewstate of dynamic control with page viewstate to work it correctly

  • How do events on the dynamically created user controls get fired??

  • I have the same problem... the button events in the dynamically created user control in the UpdatePanel don't fire when clicked. Anyone point me in the direction of a solution? Thx!

  • I've been attempting to use this approach to dynamically add ASP.NET image controls to the page. This doesn't seem to work. Any idea on how to do that?

  • Can anyone help me out to execute usercontrol code(only code no html needed, no ajax needed) in the page ?
    e.g Server.Execute("./Controls/UserControl.ascx")
    but this gives error :(

  • How do I go about merging viewstates to get the events in the controls to fire?
    Can you give an example of this?

  • hi sanjeev,
    i made a separate file for vb and placed all your javascript code in it. but my user control (gridview) doesn't shows up on form.
    Code is executed fine without errors it also shows up on tooltip all the data if i debug the code.
    Please tell what is that im missing.
    i have written nothing in web config file regarding web service.(should i?)

  • Dear Abhay,
    Please forward your sample code at sanjeev.agarwal@emirates.com for review

  • theform not found if i put in a small page of master page

  • Hi Sanjeev,

    Great article, thank you. As others have commented above, I would love to see an article on enabling events to fire from with the dynamically loaded control. I'm trying to solve this problem at the moment and would love some help understanding how we can merge ViewStates and have our usercontrols act just the same as they would when they are statically implemented.

    Thanks,
    Chris

  • Hi
    The work through is Great but i need to add a New Row
    in Grid Control using Jquery to avoid PostBack

    pls help how to do this

  • very helpful article.

    do you have any thoughts on passing parameters into the controls?

    I was thinking about maybe creating a base user control with a params List and then just adding them in there which should then be available to the user controls.

    thanks again for this, very helpful.

  • Nice approach
    But the If want the Button Click of the Login Control to work what is that you suggest ?
    Thanks & Regards
    Senthil

  • great article indeed

    but when i click a asp:Button (on the main page) after loading a user-control, I got an error that says "[No relevant source lines]".

    how can i fix this problem.

    thanks in advance

    Murat

  • If you were using a formview in your usercontrol and you click the update to update the database will it cause a post back.

  • Hey great article.

    I took your base code and extended it slightly into a tabs example. I also removed the controls viewstate entirely to fix the corrupt viewstate errors I was experiencing on postback.

    Luke

  • HI,
    thanks for this post, it's very helpful.
    I have a trouble with viewstate when i want to update my gridview in the user control. Can you help me please?

  • dear, you have given a good thought, but to handle control's event, what should we have to do as i got this message:
    The state information is invalid for this page and might be corrupted
    would you please help me for this?

  • Hi Sanj

    How do you merge viewstates mate? I can't find anything on the web about this.

    Cheers

    Martin

  • I've just found something out that may help some people.

    If you don't need postbacks from the dynamically loaded control you can just remove the second __VIEWSTATE field from the dom using jQuery with this line...

    $("input[@name='__VIEWSTATE']:eq(1)").remove();

    Put this in your ajax success function after the new html has been added to the target div and it will stop the error happening.

    I tried to merge the 2 viewstates using jQuery but it still broke.

    Martin

  • I added asp.net button control (runat server) on my user control but this is not working and giving me error runat server form tag required to render button control. what is the solution for this.

  • Where can i find a way of merging viewstate of dynamic control with page viewstate??? If so, this is the right behaviour???

  • How Do u pass a QueryString to the userControl.

  • Thanks for wonderful piece of code. But this is not useful if you want to do any server-side execution in the user control.

  • Hi Sanjeev,
    Great solution.
    Just wondering that how do we access the values present in the user control loaded this way?
    Lets say - you added 5 user controls which have got 2 textboxes each. Now you want to save all the values present in these 10 textboxes. How do we do that?
    Please help :)

    Thanks - Ishan

  • How do you handle buttons click event. For example Login button?

  • /

  • I figured out the corrupt state error. In his service, he has code that adds the usercontrol to a form, to a page. Well this form comes w/ a viewstate and a form tag, which you probably already have in your aspx page.

    Just remove the form part and add the usercontrol to the page, and all works fine.

  • Hi,

    Has anyone got the ViewState issue sorted out? I've tried Dannster's approach of

    $("input[@name='__VIEWSTATE']:eq(1)").remove();

    But the ViewState is nor being removed from the HTML...

  • What is role of "EnableViewState=False" while creating controls dynamically

  • What about a grid with paging ?

  • Do i need to login to post material to this discussion?

  • Hi,
    I am Hari from India. Your program is working fine. I am getting error when i click newly added asp.net button in the page.

    The Error is "The state information is invalid for this page and might be corrupted."

    I have used the methods:
    1. $("input[@name='__VIEWSTATE']:eq(1)").remove();
    2. EnableViewState=False

    but the above methods are not working. Please help me.

    Thanks,
    Hari

  • This program is working but when i added asp.net
    button in this page and click on that getting the error Like "The state information is invalid for this page and might be corrupted."

  • useless if control has user interaction.. will lose all viewstate

Comments have been disabled for this content.