Sanjeev Agarwal

Extending Web with ASP.NET

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

Comments

emremp said:

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

Also good article. thanks

# July 23, 2008 1:41 PM

John said:

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

# July 23, 2008 11:20 PM

SanjeevAgarwal said:

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.

# July 23, 2008 11:46 PM

John said:

Thanks for the quick response!

# July 24, 2008 12:06 AM

SanjeevAgarwal said:

John,

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

# July 24, 2008 12:11 AM

sntacrz411 said:

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.

# July 25, 2008 3:02 PM

SanjeevAgarwal said:

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

# July 26, 2008 3:59 AM

Stephen said:

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

# August 10, 2008 2:38 PM

Natalia said:

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

# August 13, 2008 1:53 PM

Natalia said:

This is the error I get

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

# August 13, 2008 2:11 PM

SanjeevAgarwal said:

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

# August 14, 2008 12:33 AM

DM said:

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

# September 1, 2008 1:13 AM

Greg said:

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!

# September 2, 2008 11:59 PM

Ben said:

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?

# September 3, 2008 2:22 PM

Anny said:

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 :(

# September 25, 2008 7:56 AM

Jonah said:

How do I go about merging viewstates to get the events in the controls to fire?

Can you give an example of this?

# September 30, 2008 8:24 AM

Abhay maini said:

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?)

# November 10, 2008 3:31 PM

SanjeevAgarwal said:

Dear Abhay,

          Please forward your sample code at sanjeev.agarwal@emirates.com for review

# November 12, 2008 12:36 AM

hung_asd321 said:

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

# November 18, 2008 1:29 AM

Chris said:

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

# December 8, 2008 12:11 PM

Arunvijay said:

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

# December 31, 2008 7:15 AM

mike said:

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<object> and then just adding them in there which should then be available to the user controls.

thanks again for this, very helpful.

# January 20, 2009 5:52 AM

skurocks said:

Nice approach

But the If want the Button Click of the Login Control to work what is that you suggest ?

Thanks & Regards

Senthil

# January 21, 2009 7:02 AM

muratinci said:

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

# February 18, 2009 11:31 AM

ojorma said:

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

# March 18, 2009 7:14 AM

Luke said:

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

# April 6, 2009 2:51 AM

jamalovitch said:

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?

# May 3, 2009 10:36 PM

OMAIR said:

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?

# June 3, 2009 2:24 AM

Dannster said:

Hi Sanj

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

Cheers

Martin

# June 4, 2009 9:38 AM

Dannster said:

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

# June 4, 2009 11:03 AM

vishal Sharma said:

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.

# June 25, 2009 12:32 PM

Carlos Pilão said:

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

# July 28, 2009 10:51 AM

m7e7 said:

How Do u pass a QueryString to the userControl.

# August 14, 2009 3:11 PM

Nuwan said:

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

# October 20, 2009 5:22 AM

Ishan said:

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

# November 13, 2009 1:44 AM

Albroz said:

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

# June 28, 2010 3:42 AM

avin037 said:

/

# August 10, 2010 1:03 AM

matt said:

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.

# August 21, 2010 2:05 PM

ian_c22 said:

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...

# January 9, 2011 8:36 AM

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

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

# January 14, 2011 1:56 AM

Sabarinath said:

What about a grid with paging ?

# February 16, 2011 7:35 AM

Mohammad Aamir said:

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

# April 12, 2011 6:43 AM

bermelhos said:

Hola, yo use este codigo para dibujar controles en mi pagina dinamicamente, y como a muchos le ocurrio me dio el error del viewstate al realizar el postback, despues de mucho intentar pude llegar a una solucion, en javascript capturar la respuesta y quitarle el primer div aspNetHidden, con esto ya pude realizar el postback sin problema.

# May 7, 2011 4:55 PM

Hariharans87 said:

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

# May 16, 2011 9:03 AM

dnn said:

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."

# August 3, 2011 9:22 AM

onednd said:

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

# February 7, 2012 7:18 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)