Coding Beginner's Guide: the Life of an HTTP Request

Published Nov 17, 2015Last updated Mar 22, 2017
Coding Beginner's Guide: the Life of an HTTP Request

An HTT-what request?

Open your favorite browser and type "www.codementor.io" in the address bar. You'll see Codementor's home page show up right away. It might look simple, but there's quite a story involved in how the browser showed you that page! That story starts with a HTTP Request.

Think of HTTP like a language. Just like two people who both speak English can understand each other and communicate, two computers which both speak HTTP can understand each other and communicate. The conversation between your browser and codementor went something like this.

  • Browser - Hey, codementor, could you send me your homepage?
  • Codementor - Sure, here it is. It's in HTML, so make sure to render it before showing the user.
  • Browser - Will do. Thanks!

There's a lot more technical details than that, but it's a pretty accurate picture of what happened. Next, we'll start to dig in to what the request has and how MVC uses it.

1. The Route Table

Let's have another look at that request.

Hey, codementor, could you send me your homepage?

Notice those two critical pieces of information the browser said? 1) It said what site it was talking to, and 2) it said what page it wanted from that site. Sometimes, the browser will say a few more things like: "I want version 1" or "my username is john.doe". That extra information is sent along with the request as key/value pairs like version=1 or username=john.doe.

This is where an ASP.NET MVC application gets started. The MVC framework takes the raw request and tries to find a matching route in the route table. If there's a match, you get a RouteData object. It's the same information that was in the request, but it's been separated into an easy to use dictionary.

RouteData includes

  • The name of the controller and action from the request
  • Named parameters defined the route table like id
  • Rules about when the route is valid and how to use it (DataTokens)

2. The ControllerFactory

With the RouteData, MVC understands the request better than it originally did. Now it knows what controller to look for. But how will it find it in an application jam-packed with classes? That's the ControllerFactory's job. The ControllerFactory uses Reflection to find every class in your code which inherits from System.Web.Mvc.Controller. It doesn't matter what folder / namespace that controller is in, all that matters is inheriting from Controller. Next, the factory does a simple name match. If two controllers have the same name, you get an error, even though they are in different namespaces! Think putting the controllers in different namespaces will help? Think again. You'll get the same error no matter where the controllers are defined as long as they have the same name.

This is our first encounter with the peculiar relationship between an HTTP request and a .NET application. In .NET, we can reuse the same names over and over as long as we follow scope, namespace, and overloading rules. In an HTTP request, we can't. All we have is name matching. Fortunately, we can add additional rules to our routes (DataTokens as mentioned above) to specify where the factory should look for controllers. For example, route.DataTokens["Namespaces"] = new string[]{"MyApp.Controllers"} tells the factory only to use controllers from the MyApp.Controllers namespace.

If the factory successfully finds one match, we move on!

3. The ActionInvoker

The ActionInvoker follows almost the exact same pattern as the ControllerFactory except on methods in your controller. Be careful! If you use .NET method overloads like Index(int id) and Index(), you'll get a crash in your app! Why? It's exactly like we explained. The HTTP request said "/Home/Index". It didn't say which index it wanted, so how could MVC pick between them.

At this stage you can use ActionFilter's and ActionSelector's to help MVC pick the right method for each request. If it finds an action that matches the request, we move on. Otherwise, we get an error message.

4. The ModelBinder

In .NET we use method arguments to pass data around. Add those same style of arguments to your action methods and you'll find they automagically get values from the request. That's the MVC model binder working for you. The model binder does name matching on the raw data in the request. There's automatic type conversion built in as well as a validation system. The entire process of receiving and interpreting data is dealt with in this step, and it is all automatic.

By now, we have 5 things from our request:

  1. The actual HTTP request
  2. The RouteData built in step 1
  3. The controller built in step 2
  4. The action method found in step 3
  5. The model bound in step 4

Instead of just the raw request, our action method code has access to all of those, courtesy of the MVC framework.

5. Your Code

Now your code runs. You find the right view, query a database, etc. When your done, you send back a ViewResult.

6. The ViewEngine

Your view is written in Razor with .NET code interspersed with HTML. The browser doesn't speak .NET so we need to compile and run the view before returning it. That's the ViewEngine's job. The view engine finds a matching view by checking the RouteData, compiles it, executes it, deals with any special editor templates, display templates, or layouts you might have, and finally returns the generated HTML content.

7. The HTTP Response

After all the work is done, MVC sends back plain HTML to the browser. The whole process takes a few milliseconds, but does hours of work for you.

Discover and read more posts from Yaakov Yisroel Kosbie
get started