Welcome to Professional ASP.NET - Chris Love's Official Blog Sign in | Join | Help

Chris Love's Official ASP.NET Blog

Chris Love's Helpful tips, tricks and pragmatic development knowledge for the ASP.NET world.
Add to Technorati Favorites


ASP Insider Follow Me On Twitter
The ASP.NET Diet Part 1 – Making a Thin Contact Form

In my last post I waxed philosophically about the progression of ASP.NET. Today I want to start actually demonstrating how to take ASP.NET to the next level, at least in my opinion. The first thing I always add to a new web site is a contact form. Basically the form accepts a question or comment from a visitor and allows them to add their contact information to the request. The way I implement the form is to display a visual confirmation to the visitor, store the request in the site’s database, send an E-Mail to the visitor to confirm the request and send an E-Mail to the site administrator to alert them.  Traditionally this was done with a post-back to the server, which stored the information and sent the E-Mails. The confirmation was displayed in response to the post-back. Since AJAX has become popular this process has evolved.

First let’s examine implementing this form with an UpdatePanel and a MultiView control. I am not going to deal with the E-Mail or database activities because they do not really matter for this demonstration. The main thing is to see how to quickly add AJAX to the form. The UpdatePanel wraps a MultiView that is composed of two views, one for the form and one for the confirmation message.

<asp:UpdatePanel runat="server" ID="upContact">
        <ContentTemplate>
            <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
                <asp:View runat="server" ID="vForm">
                    <table cellspacing="1" cellpadding="1" width="92%" align="center" border="0">
                        <tr>
                            <td height="80" valign="top" align="left" colspan="3">
                                <h2 style="margin-top: 4px; margin-left: 5px; margin-right: 5px; text-align: center;">
                                    Contact Us Via FAT AJAX</h2>
                            </td>
                        </tr>
                        <tr>
                            <td colspan="3">

                <!-- Contact Form Elements Using Web Controls -->

                            </td>
                        </tr>
                    </table>
                    <p align="center">
                        <asp:Button ID="btnSubmit" runat="server" Text="Submit" /><br>
                        &nbsp;</p>
                </asp:View>
                <asp:View runat="server" ID="vThanks">

                <!-- Confirmation Message -->

                </asp:View>
            </asp:MultiView>
    </ContentTemplate>
</asp:UpdatePanel>

When the form is submitted the actions described above occur and the confirmation View is displayed. With the UpdatePanel in place this happens without a flicker happening on the screen, which is desirable. You can even add an UpdateProgress control to give a little visual indication while the data is stored and E-Mails sent.

Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click

        'Do Work Here

        MultiView1.ActiveViewIndex = 1

End Sub

Nothing really magically with this code, but I like to see what is going on under the hood. For this I crack open Fiddler. Monitoring the contact request with Fiddler shows it sends and receives a total of 2385 bytes. You can check out exactly what what was sent across the wire in both the request and the response. This will be important to remember later.

The UpdatePanel solution is sufficient in most cases. It is fast to market, provides a rich user experience and does the work needed. But in the public arena this may not cut it. I mean it is a very competitive world these days for market share and the leaner the better (well typically), but this often requires just a little more work. The next example makes a really thin Contact form, but requires a bit more work to make happen.

I am going to continue to use the ScriptManager control to make leveraging ASP.NET AJAX a lot easier. Instead of using Web Controls for inputs I am going to use the HTML Input tags. I like using the actual HTML Input tags over Web Controls because they are much cleaner to reference in JavaScript. Instead of an UpdatePanel I am going to use a Web Service and a simple JavaScript file. The Web Service and the script files are added to the ScriptManager as shown below. This is important, otherwise the form will not function.

<asp:ScriptManager ID="ScriptManager1" runat="server" LoadScriptsBeforeUI="false">
        <Services>
                <asp:ServiceReference Path="~/ContactService.asmx" />
        </Services>
        <Scripts>
                <asp:ScriptReference Path="~/js/Contact.js" />
        </Scripts>
</asp:ScriptManager>
<fieldset id="contactform">
        <legend>Contact Us</legend>
        <div id="dMakeContact">
                <!-- Contact Form -->
        </div>
        <div id="dThinking">
                Thinking....</div>
    <div id="ContactResponse">
                <p>
                    Your request has been recieved and will be responded to shortly.</p>
    </div>
</fieldset>

Notice there is no MultiView here either, instead there are a series of DIV elements. The dThinking and ContactResponse DIVs are hidden at load time by the JavaScript. This can also be done by setting the styles applied to these elements to hidden, but I wanted to keep CSS out of this post.

var dThinking = $get('dThinking');
var ContactResponse = $get('ContactResponse');

if (ContactResponse != null) {
    HideElement('ContactResponse');
    HideElement('dThinking');
}

There is no code-behind handling the click event of the form’s submit button, instead the request is sent to a web service that performs the business end of the form.

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Web.Script.Services

<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class ContactService
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    <ScriptMethod()> _
    Public Function PostContactRequest(ByVal vRequest As ContactInfo) As Boolean

        Dim ret As Boolean = False

        'Simulate doing some real work here
        Threading.Thread.Sleep(1000)
        ret = True

        Return ret

    End Function

End Class

Notice three modifications to this web service, the importing of the System.Web.Script.Services namespace and the addition of the ScriptService and ScriptMethod attributes to the class and method respectively. This makes the web service method work with ASP.NET AJAX by automatically using JSON to transmit data. JSON stands for JavaScript Object Notation and is a much nicer way to transmit data than XML in my opinion because it is very thin. This is done by creating the a ContactInfo object, a simple class I created to at as an entity for the data in this example. You can see the source in the attached zip file.

When the submit button is selected by the user the StoreContact function is called. This function gets the values in each of the inputs and assigns it to the corresponding property in the ContactInfo class. ASP.NET AJAX automatically lets you assign to the properties, so do not worry with this comes from. the ContactInfo entity is then passed to the PostContactRequest web method, along with two method callbacks, one for success and one for an exception. If the request is successful a confirmation message is displayed, if an exception occurs the user is alerted. This is not the most eloquent of solutions, but for demonstration purposes it will do.

function StoreContact() {

    HideElement('dMakeContact');
    HideElement('ContactResponse');
    ShowElement('dThinking');

    var FirstName = $get('FirstName');
    var LastName = $get('LastName');
    var Addr1 = $get('Addr1');
    var Addr2 = $get('Addr2');
    var City = $get('City');
    var State = $get('txtState');
    var Zip = $get('txtZip');
    var Phone = $get('txtPhone');
    var EMail = $get('EMail');
    var Comment = $get('Comment');

    var objCat = new ContactInfo();
    objCat.FirstName = FirstName.value;
    objCat.LastName = LastName.value;
    objCat.Address1 = Addr1.value;
    objCat.Address2 = Addr2.value
    objCat.City = City.value;
    objCat.State = State.value;
    objCat.Zip = Zip.value;
    objCat.phone = Phone.value;
    objCat.Email = EMail.value;
    objCat.Request = Comment.value;

    ContactService.PostContactRequest(objCat, StoreCommentCompleteEvent, StoreCommentErrorEvent);

    return false;
}


function StoreCommentCompleteEvent(result, context) {

    HideElement('dThinking');
    ShowElement('ContactResponse');

    ContactResponse.innerHTML = ContactResponse.innerHTML + '<BR/>' + result;

}

function StoreCommentErrorEvent(result, context) {
    alert('It blew up!');
    if (null != result) {
        alert(result.get_stackTrace());
    }
}

This time the resulting request and response account for a total of 936 bytes, about a third of the previous example. While not a lot of difference in the short term it can and does add up over time. Plus you have all the overhead associated with rendering the UpdatePanel’s markup I did not go over. The less you have to move across the wire the faster the content should be rendered to the user and the fastest is the best on the web.

Reviewing the actual data transported over the wire reveals two separate JSON data packages. The response alone is around a fifth the size of the UpdatePanel’s response. I also think if you are trying to troubleshoot what is happening this is much easier to read, etc.

While the UpdatePanel version is faster to put in production, the more pure AJAX version is the more optimal performing version. If you are in the process of upgrading existing ASP.NET web forms code to leverage AJAX, then by all means slap the UpdatePanel on the page, but do make a real plan to wean yourself from the use of the UpdatePanel. If it is a brand new form I hope you consider using the AJAX with web service version, after all AJAX is all about leveraging web services with JavaScript. It takes a little more time, but after you do it a couple of times it becomes a pretty easy and natural task to tackle.

Download the Code

Share this post :
Posted: Friday, January 30, 2009 11:19 PM

by Chris Love

Comments

Infocyde said:

Thanks for posting, some good json/web service code here.
# January 31, 2009 12:01 AM

nice said:

nice sample!
# January 31, 2009 12:03 AM

JC said:

Very nice. I'll have to try this out. FYI. The fiddler link is incorrect. It points to fiddlertools.com instead of fiddlertool.com
# January 31, 2009 11:57 AM

ASPInsiders said:

Given that I’ve been focusing a lot on diet and exercise in my personal life, as well as AJAX and JavaScript

# February 3, 2009 10:52 AM

Mark said:

I feel that the update panel works perfectly in the hardware is cheap theory. This optimization really only helps if you get thousands of requests a minute. http://www.codinghorror.com/blog/archives/001198.html
# February 3, 2009 12:19 PM

Chris Love said:

Mark, That is the tradeoff you have to consider. Do you want a fat site or a lean site. Behind the firewall the UpdatePanel is your friend, outside the firewall it just makes you look bad.
# February 5, 2009 12:59 PM

Chris Love's Official ASP.NET Blog said:

I was trolling the ASP.NET forums tonight and found a very good question from ctrlctrl, . He wanted to

# March 17, 2009 12:11 AM

Chris Love's Official ASP.NET Blog said:

Back in January I wrote about making a thin contact form in an effort to demonstrate how to make ASP.NET
# April 28, 2009 3:32 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS