HTTP Overview and the Bridge to ASP.NET Core

Before we can talk about ASP.NET Core, we should at least discuss the major parts of HTTP so we can know how each of those things fit into bigger picture.

What is HTTP?

HTTP is a protocol that allows clients to communicate with servers. It's the protocol that powers the web.

Let's take a brief look at a typical request/response

This is an example GET request sent from a client to a server:

GET /index.html HTTP/1.1
Host: www.example.com
Accept: text/html
Accept-Language: en-US

Deconstructing the request, line-by-line:

Line Description
GET /index.html HTTP/1.1 This is the request line. It specifies the HTTP method (GET), the resource being requested (/index.html), and the HTTP version (1.1).
Host: www.example.com The Host header specifies the domain name of the server (virtual host) to which the request is being sent.
Accept: text/html The Accept header tells the server what content types the client is able to understand. In this case, it's requesting HTML content.
Accept-Language: en-US This header indicates the natural language and locale that the client prefers. Here, it's specifying US English.

The response:

HTTP/1.1 200 OK
Content-Type: text/html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
etc...

The response has the following parts:

Line Description
HTTP/1.1 200 OK This is the status code line. It indicates the HTTP version (1.1), the status code (200), and a short phrase describing the status (OK).
Content-Type: text/html This header specifies the MIME type of the response body, indicating that the response content is HTML.

The body of the response contains the HTML content of the requested page.

HTTP Methods

Also known as HTTP verbs, these are the methods that browsers use to tell the server what they want to do.

  • GET: Requests a representation of the specified resource.
  • POST: Submits an entity to the specified resource, often causing a change in state or side effects on the server.
  • PUT: Replaces the specified resource with the request payload.
  • DELETE: Deletes the specified resource.

These status code are used, but not as often, and won't be covered in this course.

  • PATCH: Applies partial modifications to a resource.
  • HEAD: Asks for a response identical to that of a GET request, but without the response body.
  • OPTIONS: Describes the communication options for the target resource.

Most of the time, people are using the top four, GET, POST, PUT, and DELETE.

HTTP Status Codes

Status codes are three-digit codes that indicate the result of a request. They are separated into five classes:

  • 1xx: Informational - Request received, continuing process
  • 2xx: Success - The action was successfully received, understood, and accepted
  • 3xx: Redirection - Further action must be taken in order to complete the request
  • 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
  • 5xx: Server Error - The server failed to fulfill an apparently valid request

The most common status codes for this course are:

Code Description
200 OK - The request was successful
201 Created - A new resource was successfully created
400 Bad Request - The request is invalid
401 Unauthorized - Authentication is required
403 Forbidden - Access is forbidden
404 Not Found - The requested resource was not found
500 Internal Server Error - The server encountered an error

Let's look at a POST request real fast

The request we made above lacked what's called a body - a way to send data to the server. GET requests don't support bodies, but POST does.

Here's an example of a POST request:

POST /employees/create HTTP/1.1
Host: www.example.com
Content-Type: application/json

{
    "name": "John Doe",
    "email": "john.doe@example.com",
    "message": "Hello, world!"
}

In this request:

  • The POST method is used to submit data to the server.
  • The Content-Type header specifies the MIME type of the request body, indicating that the request content is JSON.
  • The request body contains the data to be submitted to the server.

What is ASP.NET Core?

ASP.NET Core is a framework for building web applications and APIs. It's built on the .NET runtime and is designed to be a high-performance, modular web framework.

You're one command away from creating a new ASP.NET Core project:

dotnet new webapi -n MyWebApp

This will create a new web API project in the MyWebApp directory.

Here's the Program.cs file that is generated:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast =  Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Let's deconstruct it right quick:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

This part of the file is used to configure the services that the application will use.

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

This part of the file is used to configure the HTTP request pipeline. Any place where the API starts with "Use" or "Get" will typically be adding something to the HTTP middleware pipeline. In this case, it's checking if the application is in development mode and if so, it's adding the Swagger and Swagger UI services to the application middleware pipeline.

Swagger?

Swagger is a tool that allows us to document our API. It's what we're using to generate the API documentation you see in the browser. Very useful for API developers!

It generates something that looks like this when you start the app:

Swagger UI

Wait, what the heck is middleware?

Middleware are the things that handle HTTP requests and responses in ASP.NET Core.

Middleware pipeline Source: ASP.NET Docs

Let's dive into the Swagger source code and see for ourselves:

/// <summary>
/// Register the Swagger middleware with provided options
/// </summary>
public static IApplicationBuilder UseSwagger(this IApplicationBuilder app, SwaggerOptions options)
{
    return app.UseMiddleware<SwaggerMiddleware>(options);
}

This is the Swagger middleware, which is used to serve the Swagger UI and the generated JSON documentation. Watch the video to see how this is deconstructed!

Adding our own middleware to prove a point

Let's add some middleware to our pipeline to prove a point: the middleware is always in control.

After the Swagger calls, we'll add this middleware:

app.Use(async (HttpContext context, RequestDelegate next) =>
{
    context.Response.Headers.Append("Content-Type", "text/html");
    await context.Response.WriteAsync("<h1>Welcome to Ahoy!</h1>");
});

This middleware will skip the rest of the pipeline and write its own goodies to the response.

Ok, but what is HttpContext?

HttpContext is the main class that represents the incoming HTTP request - and all related things around handling that request - in ASP.NET Core. It's the main object that is passed around in the middleware pipeline.

It contains all the information about the request and response.

Here are the most important properties of each:

Property Description
Request The request object
Response The response object
Items A dictionary of items that can be used to store data during the request/response process
User The user object - we'll discuss this more when we get to authentication
Features A collection of features that can be used to store data or add behaviors to the request/response process

The Request and Response properties are the most important ones, as they are the ones that contain the request and response data.

For instance, Request contains the request headers, the request method, the request URL, the request body, etc.

Most of Spencer's time is spent reading the Request or User objects.

Continuing the breakdown

We took an off ramp but we're back on the highway:

app.UseHttpsRedirection();

This is the middleware that redirects HTTP requests to HTTPS. It's not strictly speaking required for this course, but it's good practice to have in so tha you use HTTPS as much as possible.

var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
    var forecast =  Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

This is the middleware that handles the GET request for the /weatherforecast endpoint. As you can see, all it does is return some random data with weather forecasts.

The .WithName and .WithOpenApi methods are used to add metadata that OpenAPI uses to generate the documentation.

app.Run();

This is where the app actually starts. After you've registered all of your services and middleware, you call app.Run() to start the application.