Looking Up Zip Codes with C# ASP .NET MVC and AJAX

modified

Introduction

With the release of the ASP .NET MVC (model view controller) framework for Visual Studio and .NET, many developers are considering the move to the new MVC architecture, in place of classic ASP .NET. The MVC framework for C# ASP .NET provides a loosely-coupled and robust architecture for creating web applications, with distinct separation of the user interface, UI logic, and business logic layers. However, in addition to the logic architecture, the MVC pattern diverges from classic ASP .NET even more.

In this tutorial, we’ll examine how to create a basic ASP .NET MVC application, which allows entering a zip code and asynchronously displaying the city and state associated with a zip code via AJAX and jQuery.

One Degree Away From Classic ASP .NET

ASP .NET WebForms centered around the idea of callbacks and events. Controls, such as buttons, would fire events back to the code and trigger associated logic via a postback. Even the ASP .NET AJAX Framework and the UpdatePanel still utilized a full postback. By relying on the ViewState and the large amounts of HTML associated with it, ASP .NET WebForms may not be the optimal framework in some instances.

The ASP .NET MVC framework largely takes away the notion of the postback and event-driven model, and replaces it with a strictly REST based architecture for web applications. Form submissions post a specific request back to the C# ASP .NET web application, which processes the request in the MVC controller and returns back an associated view. This architecture can greatly speed up the display and processing time of individual web pages in the web browser and on the server, due to the optimized HTML which is passed during form submits.

To really get into the ASP .NET MVC, let’s get started on the zip code lookup tutorial.

Cleaning Up the Initial MVC Project

When creating a C# ASP .NET MVC project, the first step is to install the MVC framework. Once installed, create a new Visual Studio project and select ASP .NET MVC Web Application as the project type. Select No, when asked if you wish to create unit tests.

Visual Studio will automatically generate a skeleton MVC project to start with. We’ll need to do some cleaning to start with a blank slate.

  1. Expand the folder Content.

  2. Delete the file Site.css

  3. Expand the folder Controllers.

  4. Delete the files AccountController.cs and HomeController.cs

  5. Expand the folder Views.

  6. Delete the folders Account and Shared.

  7. Expand the folder Views->Home.

  8. Delete the files About.aspx and Index.aspx

Once cleaned up, we now have a blank ASP .NET MVC project slate to begin with.

What Exactly are the Controllers, Models, and Views Folders For?

Before jumping into the code, you should have at least a basic understanding of what the Model, View, and Controller pieces are within an ASP .NET MVC project.

The View

The most visible piece is the View, which resides in the Views folder. A view is the user-interface, or anything the user would see. In the case of the ASP .NET MVC project, a view is any .aspx or .ascx file.

The Controller

The Controller is the layer which connects the View to the Model. In the traditional Model View Controller pattern, the View knows nothing about the Model and the Model knows nothing about the View. The Controller is the intermediary who connects the two and allows interchanging Views and Models. In the ASP .NET MVC, the controller is the user interface logic, associated with the .aspx or .ascx file. All form submission and page requests are processed in the controller. The controller essentially replaces the code-behind file that was traditionally used with the .aspx file.

The Model

The Model functions as the core business logic layer. Typically, a Model would be a class or object used within the web application or displayed to the user. An Employee class could be a model, as would a Car class, or even a collection of Stocks. Models can be passed throughout the ASP .NET MVC application, but are specifically used by the controller and rendered in the view.

With a basic understanding of each part within the ASP .NET MVC project, we can now move on to creating our first Controller.

This Isn’t Your Typical Code-Behind

In classic ASP .NET, a code-behind file existed for each .aspx page. This code-behind file provides various event and callback functions, associated with the page. In the Controller, we still have access to override various events, but the core processing logic will occur using the REST architecture (basic URL requests). Therefore, you won’t see the typical Page_Load() function within this example.

Creating Your First Controller

To begin, right-click the Controllers folder and select Add->Controller. For the name, type in HomeController. Leave the checkbox empty. A new controller will be added to your MVC project, containing a single function, Index(). This function is called any time the page (view) is requested. While there are other events for handling the different parts of a page load, the Index() function is all we’ll need for this example. An empty controller isn’t very interesting, so let’s add a view.

Creating Your First View

Open the controller by double-clicking HomeController.cs. Right-click the Index() function and select Add View. Leave the View name as “Index” and leave all checkmarks empty. Click Add. A new view will be added to your MVC project in the Home folder.

Let’s add some basic formatting to the view to allow the user to enter a zip code and view the City and State in real-time. We’ll use the following HTML in our view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

<!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 runat="server">
    <title>Index</title>
    <script src="/Scripts/MicrosoftAjax.debug.js" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" _fcksavedurl=""/Scripts/MicrosoftAjax.debug.js"" type="text/javascript"></script>
    <script src="/Scripts/MicrosoftMvcAjax.debug.js" type="text/javascript"></script>
</head>
<body>
    <div style="border: solid 1px #000000; width: 600px; height: 58px; background-color: #f0f0f0; padding: 5px;">
        <div style="float: left; width: 100px;">
            Zip Code
        </div>
        <div style="float: left;">
            <input type="text" id="txtZipCode" name="txtZipCode" value="" />
        </div>
        <div id="lblCityState" name="lblCityState" style="float: left; padding-left: 10px; padding-top: 3px; font-size: small;">Enter a zip code</div>
        <div style="clear: both;" />
        <div style="float: left; width: 100px;">&nbsp;</div>
        <div style="float: left;">
            <input type="submit" id="btnLookup" name="btnLookup" value="Lookup" />   
        </div>
    </div>
</body>
</html>

Notice in the HTML, we’re not using classic ASP .NET server side controls. Instead, we’re actually using basic HTML controls. Since the ASP .NET MVC framework uses the REST model for web applications, the postback model no longer applies. Although you may still be able to use some server-side controls, those which rely on ViewState postbacks are not currently compatible with the MVC framework. In this example, we’ve simply added a textbox, a label (in the form of a div tag), and a button to the view. It’s also important to include both the ID and Name tag for form controls.

To link the button in our view to the controller, we need to add an AJAX form around it. This will function similar to the classic ASP .NET UpdatePanel from the AJAX .NET framework. We can do this by modifying the HTML as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

<!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 runat="server">
    <title>Index</title>
    <script src="/Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>
    <script src="/Scripts/MicrosoftMvcAjax.debug.js" type="text/javascript"></script>
</head>
<body>
    <% using (this.Ajax.BeginForm("Lookup", null, new AjaxOptions { UpdateTargetId = "lblCityState" }, new { id = "myForm" }))
       {
    %>
    <div style="border: solid 1px #000000; width: 600px; height: 58px; background-color: #f0f0f0; padding: 5px;">
        <div style="float: left; width: 100px;">
            Zip Code
        </div>
        <div style="float: left;">
            <input type="text" id="txtZipCode" name="txtZipCode" value="" />
        </div>
        <div id="lblCityState" name="lblCityState" style="float: left; padding-left: 10px; padding-top: 3px; font-size: small;">Enter a zip code</div>
        <div style="clear: both;" />
        <div style="float: left; width: 100px;">&nbsp;</div>
        <div style="float: left;">
            <input type="submit" id="btnLookup" name="btnLookup" value="Lookup" />   
        </div>
    </div>
    <% } %>   
</body>
</html>

Notice in the modified HTML, we’ve added the Ajax.BeginForm tag and it’s associated closing tag around our form. This is how you create an AJAX submit in the ASP .NET MVC model. Rather than a full page postback, as performed in classic ASP .NET, the MVC model only transfers the neccessary form fields. You can include as many Ajax forms as needed on your page to obtain the asynchronous functionality required for your application.

The first parameter of the Ajax.BeginForm tag is the action name called within your controller. In this case, we’ll be creating a Lookup() function to handle this call. We also specify the HTML control to receive a text update once the AJAX call is complete.

Now that we’ve created our controls, lets link the view to the controller by defining the function to handle the Lookup button.

Wiring the Controller to the View

To handle the Lookup button, we’ll create a new function in HomeController.cs directly after the Index() function, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public string Lookup(string txtZipCode)
{
    if (txtZipCode == null || txtZipCode.Length == 0)
    {
        return "Enter a zip code";
    }
    else if (txtZipCode.Length != 5)
    {
        return "Enter a zip code with 5 digits.";
    }
    else
    {
        // Request zip code from Model.
        return "Philadelphia, PA";
    }
}

The Ajax.BeginForm tag will pass our controller the form field txtZipCode. We can then lookup the associated city and state information, based upon the data. This all occurs asynchronously via AJAX within the ASP .NET MVC framework. The string returned will be automatically updated in our div label. From the controller, you can request business logic or data from various Models, to appropriately display the City and State per zip code entered.

At this point, you can run the project, enter some text in the Zip Code field, click Lookup, and watch the AJAX request retrieve the text value from your controller and update the HTML in the view.

But That’s Hard-Coded!

Lets expand the functionality of our zip code lookup utility in the MVC framework by utilizing a Model and actually looking up the city and state. To do this, right-click the Model folder and add a new class called ZipCode.cs. Note, the following code reads a text file of zip codes and determines the matching city and state. For simplicity, this code is not at all optimized for usage in a web application, as it reads a large text file for each request. However, it shows one method for utilizing the Model to pass data back to the controller and view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System.IO;

namespace ZipCodeLookup.Models
{
    public class ZipCode
    {
        public string City;
        public string State;
        public bool IsValid = false;

        private const int ZIPCODE = 1;
        private const int CITY = 3;
        private const int STATE = 2;

        public ZipCode(string rootPath, string txtZipCode)
        {
            if (txtZipCode.Length == 5)
            {
                using (TextReader textReader = new StreamReader(rootPath + "\..\\zips.txt"))
                {
                    while (textReader.Peek() != -1)
                    {
                        // "01","35004","AL","ACMAR",86.51557,33.584132,6055,0.001499
                        string line = textReader.ReadLine().Replace("\"", "");
                        string[] parts = line.Split(',');

                        if (parts.Length > CITY)
                        {
                            if (parts[ZIPCODE] == txtZipCode)
                            {
                                City = parts[CITY];
                                State = parts[STATE];
                                IsValid = true;

                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

Next, modify your controller’s Lookup function, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using ZipCodeLookup.Models;

public string Lookup(string txtZipCode)
{
    if (txtZipCode == null || txtZipCode.Length == 0)
    {
        return "Enter a zip code";
    }
    else if (txtZipCode.Length != 5)
    {
        return "Enter a zip code with 5 digits.";
    }
    else
    {
        // Request zip code from Model.
        ZipCode zipCode = new ZipCode(Server.MapPath("."), txtZipCode);

        if (zipCode.IsValid)
        {
            return zipCode.City + ", " + zipCode.State;
        }
        else
        {
            return "Unknown zip code.";
        }
    }
}

Notice we create a ZipCode class by passing the zip code string entered in the form. We also happen to pass the local file path on the server so that our Model knows where to locate the text file (our controller has access to the Request and Server objects, but our model does not; while not optimal, this allows for simplicity in our example).

You can now run the project and notice after typing a zip code and clicking the Lookup button, our application updates the City and State selection using the MVC framework, and AJAX.

What About Real-Time Updates?

So far, we’ve clicked a button to fire off the AJAX request to update the city state text field. However, using Javascript and jQuery, we can enhance our form with real-time updates, while the user is typing. We just need to add a single event handler to the text field control of our form, as follows:

1
<input type="text" id="txtZipCode" name="txtZipCode" value="" onkeyup="$get('btnLookup').click();" />

We’ve simply added a javascript onkeyup event handler which submits our form when a key is typed. The MVC AJAX framework automatically calls our Lookup() controller function to update the user interface asynchronously. The $get command comes from the jQuery library and replaces the need for document.getElementById() function calls.

What Makes This MVC Web Application REST?

REST web application architecture centers around the idea of url mapping to process requests. In the above example, we can call the Lookup button directly (also called the Lookup Action, in MVC terms) by accessing the following URL:

http://localhost/Home/Lookup

or

http://localhost/Home/Lookup?txtZipCode=12345

Notice, you’ll receive the response back which is actually intended for the page’s AJAX. However, the request is valid and completes successfully.

We’ve Only Scratched the Surface

While you’ve just completed an ASP .NET MVC application, the MVC architecture goes much further than this! A series of MVC tutorials are available for learning more about Models, specifically strongly-typed Models, routing, and much more.

Conclusion

The C# ASP .NET MVC framework brings a new project architecture and REST web application process to .NET developers. By separating layers of logic by model, view, and controller, the MVC framework helps decouple project dependencies, enhance test driven development, and foster code re-use. The MVC framework also helps optimize web application page display time and server load by only transfering required form fields, rather than full postbacks. With these advantages, the ASP .NET MVC framework excels in specific project situations, but should be used selectively along-side classic ASP .NET and server-side controls.

About the Author

This article was written by Kory Becker, software developer and architect, skilled in a range of technologies, including web application development, machine learning, artificial intelligence, and data science.

Share