Click here to Skip to main content
11,924,995 members (46,235 online)
Click here to Skip to main content
Add your own
alternative version


55 bookmarked

Simplify the construction of HTML inside ASP.NET server controls using ControlInjector

, 1 Jul 2005
Rate this:
Please Sign up or sign in to vote.
Apply a String.Format pattern to control building of separate HTML from private controls.

Sample Image - ControlInjector.jpg


ASP.NET server controls are great. They allow for building reusable components, and are easy to distribute because they are entirely contained in an assembly (no .ascx files needed). One of the drawbacks of server controls is the lack of a designer/HTML editor for creating your layout. The HTML is generated in the code and generally looks messy. It can also be a headache to tweak/debug because your controls are being added in a mess of LiteralControls for the HTML.


After creating a server control with some very complex HTML, I realized that the method of mixing HTML literal content with my private controls is not ideal. What if there was a way to accomplish something similar to String.Format()? We could parse a string and look for blocks like {xxx} and inject our control there... all HTML content before and after those blocks would be added to the Control collection as LiteralContent.

Doing this will allow us to separate layout from content, and we can easily use a designer to construct and view the HTML, then copy it into a string to place in the code.

The Implementation

The HTML can be stored as a single string, and with C#, we can use string literals @"string" to allow for multi-line strings without any concatenation code. It will be relatively simple to cut-n-paste from another designer. We will need to parse the HTML string and have placeholders for each control we want to inject. I chose to use "{controlID}" as the placeholder text. Some might argue that a use of {0} {1} would fit the String.Format pattern a little better, but I chose to be more verbose here because clarity of code is what I am going for here.

Our private controls will need to be contained inside of a hashtable. We can use the control ID as the key, so it will be easy to work with.

Update -- I decided to follow some advice and keep the Hashtable internal to the class. The ControlInjector will no longer hold static methods, so you will need to instantiate it before use. I like this design a lot better.

We will parse the HTML string, find the indices of the { and }, add the text to the left as a literal control, replace the {xxx} text with the actual control, and continue. The end result will be one single control that the client code can add to the control tree.

The Code

The ControlInjector class contains three useful methods:

public void AddControl(Control c)
    //make sure that the ID is valid
    if(c.ID == null || c.ID == "")
        throw new ArgumentException("Control" + 
              c.ToString() + " must have a valid ID", "c");
    //add it to our private hashtable
    _hashControls.Add(c.ID, c);

public Control Inject(string html)
    //create a container for our controls
    PlaceHolder phContent = new PlaceHolder();

    //loop while we still have content to render
    while( html.Length > 0 )
        //find the next { character
        int iLBrace = html.IndexOf("{", 0);
        int iRBrace = html.IndexOf("}", 0);
        //make sure the order is correct                
        if( iRBrace < iLBrace )
            throw new FormatException("your html string " + 
                  "is not properly formatted -- a } was found before a {");
        //process control (if any)
        if( iLBrace >= 0 )
            //add the literal content first
            phContent.Controls.Add( new 
                      LiteralControl( html.Substring(0, iLBrace) ) );

            //get the inner content of the { }
            string controlID = html.Substring(iLBrace+1, iRBrace-iLBrace-1);
            //make sure that the control exists in the hash table
            if( ! _hashControls.ContainsKey(controlID) )
                throw new ArgumentNullException("hashControls[" + 
                          controlID + "]", 
                          "hashControls must contain the control to add");

            //add the control
            phContent.Controls.Add(_hashControls[controlID] as Control);
            //strip the part of the string that we have dealt with
            html = html.Substring(iRBrace + 1);
            //not more controls, just add the rest 
            //of the html and break out of the loop
            phContent.Controls.Add( new LiteralControl( html ) );

    return phContent;

Update -- After using this utility for a while, I realized quickly that I was still not getting any kind of designer support, and for large, complex controls, it was still a bit unreadable. I wrote a method to allow for getting the HTML string from an embedded resource. This way I can create an HTML page inside my class library, set it as an embedded resource and retain HTML designer support. Still, the designer support is limited - you cannot design the individual controls, only the layout. Another drawback is that I cannot edit the inner HTML of one of the controls, I must use separate HTML files for this.

The best part about this is that the HTML file is included in your DLL, so you do not introduce any file dependencies at all, which is ideal.

public Control InjectFromResource(string resourceName)
    //get assembly from the code that called us
    System.Reflection.Assembly dll = 

    //make sure resource exist in the assembly
    string[] resourceNames = dll.GetManifestResourceNames();
    bool found=false;
    foreach(string rName in resourceNames)
        if(rName == resourceName)
            found = true;
            break; //no need to continue searching

        throw new ArgumentException("The resource did not exist" + 
              " in this assembly. Resource name:" + 
              resourceName, "resourceName");

    //get the resource from the dll
    System.IO.Stream streamResource = 

    //read the resource data into a byte array, then convert to string
    byte[] resourceData = new byte[streamResource.Length];
    streamResource.Read(resourceData, 0, (int)streamResource.Length);

    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    string html = enc.GetString(resourceData, 0, resourceData.Length);

    //now pass this string to the original method to parse
    return Inject(html);

Nothing really exciting here, the code uses reflection to get the current assembly object, then checks to see if the resource exists. The only requirement is that the caller assembly contains the embedded resource and they supply the fully qualified name of the resource.

The Advantage

What does this code give you? Well, here's a snippet from a server control with mixed HTML and controls:

protected override void CreateChildControls()
    base.CreateChildControls ();

    label1 = new Label();
    label1.ID = "label1";
    label1.Text = "i am a label!";

    textBox1 = new TextBox();
    textBox1.ID = "textBox1";
    textBox1.Text = "i am a textbox!";

    dropdown1 = new DropDownList();
    dropdown1.ID = "dropdown1";
    dropdown1.Items.Add    ( new ListItem("i am a dropdown", "") );
    string html = @"
        <table border=2>
                <td align=center colspan=2>Title!</td>


    using(ControlInjector injector = new ControlInjector())
        this.Controls.Add( injector.Inject(html) );

To demonstrate the resource example, go to Visual Studio and add an HTML page to your webcontrols project. Design the above HTML using the Visual Studio HTML editor. Make sure and right-click the file in Solution Explorer and choose Embedded Resource. If you don't do this, the file will not be found at runtime. Once you have done this, the above method can be reduced to the following:

protected override void CreateChildControls()
    base.CreateChildControls ();

    label1 = new Label();
    label1.ID = "label1";
    label1.Text = "i am a label!";

    textBox1 = new TextBox();
    textBox1.ID = "textBox1";
    textBox1.Text = "i am a textbox!";

    dropdown1 = new DropDownList();
    dropdown1.ID = "dropdown1";
    dropdown1.Items.Add    ( new ListItem("i am a dropdown", "") );    
    using(ControlInjector injector = new ControlInjector())
        this.Controls.Add( injector.InjectFromResource("MyWeb" + 
                                  "Controls.MyControl.html" ) );

This will get the HTML from the resource located in the MyWebControls namespace, entitled MyControl.html.

Without the injector, we would have something like this:

Controls.Add( new LiteralControl("<table><tr><td>label1</td><td>") );
Controls.Add( label1 );
Controls.Add( new LiteralControl("</td></tr><tr><td>textbox1</td></tr>") );
Controls.Add( textbox1 );

... you get the idea... multiply this mess by 100 lines of HTML mixed with controls and it's not very easy to see what's going on.

What's next?

This method has very minimal error checking, and that would be the first place I would expand, but it is out of the scope of this article. (I wanted to keep it clean and easy to understand.)

The next thing I would like to add would be the ability to nest content inside of the controls, something like {control1}nested html{/control1}, but that introduces a large level of complexity to the parser, so I haven't decided if the benefit will be worth it.


Hopefully this will be of some use, and I am sure that there are other methods of accomplishing the same task. I welcome any comments or criticisms.


  • June 30, 2005 - I removed the static methods in favor of an instantiated use of the control. This allowed me to contain the hashtable as an internal reference only, making the calling code a lot simpler. I also added a method to read from an embedded resource to get the HTML string. These two additions make the class 100% more readable in my server controls. I hope it helps you as well!


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Web Developer
United States United States
Ben Scheirman is a professional web developer providing enterprise level ASP.NET solutions.

He started programming in QBASIC in 1993, learning from examples downloaded online. He migrated to Pascal in 1996, C/C++ ruled his spare time during the late 90's, and for the past 2 years he has been developing using C# & VB.NET.

He enjoys programming in his spare time, especially toying around with Managed DirectX.

Read his blog here

You may also be interested in...

Comments and Discussions

QuestionWhy not create templated server controls? Pin
Member 371021826-Feb-08 13:35
memberMember 371021826-Feb-08 13:35 
GeneralAdd Event to the control Pin
Abu Shanab31-Oct-07 23:03
memberAbu Shanab31-Oct-07 23:03 
GeneralRe: Add Event to the control Pin
subdigital1-Nov-07 6:26
membersubdigital1-Nov-07 6:26 
GeneralTeir Merging Pin
icestatue30-Nov-06 14:59
membericestatue30-Nov-06 14:59 
GeneralRe: Teir Merging Pin
subdigital1-Nov-07 6:26
membersubdigital1-Nov-07 6:26 
GeneralSuper Pin
azamsharp8-Jun-05 5:25
memberazamsharp8-Jun-05 5:25 
GeneralRe: Super Pin
subdigital8-Jun-05 7:27
membersubdigital8-Jun-05 7:27 
GeneralGood Idea! Pin
Uwe Keim27-May-05 22:09
sitebuilderUwe Keim27-May-05 22:09 
GeneralRe: Good Idea! Pin
subdigital28-May-05 5:57
membersubdigital28-May-05 5:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.151125.3 | Last Updated 1 Jul 2005
Article Copyright 2005 by subdigital
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid