The ASP.NET Diet Part 1 ' Making a Thin Contact Form

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.

Share This Article With Your Friends!