In the previous article of this series, we presented API Development with .NET. Alright, now we're going to explore ASP.NET Core, which happens to be a compelling framework for modern web application development. From covering its architecture, middleware, request processing, dependency injection, and service configuration to revealing the main ideas, this part will be indispensable to your application. In this chapter, we'll explore ASP.NET Core Architecture and its components then see about Middleware and Request Pipeline.

Understanding ASP.NET Core Basics

ASP.NET Core Architecture:

ASP.NET Core is a versatile, high-performance framework that runs on cross platforms and allows you to build next-generation web applications. The architecture is modular and flexible permitting developers to select servings of the components they need only.

Components of ASP.NET Core:

  1. Hosting Environment
  2. Request Processing
  3. Middleware
  4. Dependency Injection
  5. Services
  6. Application Models
I)  Hosting Environment

ASP.NET Core applications can run on different hosts:

  • IIS (Internet Information Services): ASP.NET Core apps hosted on IIS are accessed by the ASP.NET Core Module, which makes the requests to the Kestrel server. IIS has attributes such as process management, logging as well as security.
  • Kestrel: Kestrel is the built-in web server that runs on all platforms and belongs to ASP.NET Core. It is lightweight and it can work directly as a web application server or behind a proxy serving purposes such as an IIS or Nginx one.
  • Self-hosting: ASP.NET Core web applications can run themselves without the need for other tools outside the application. This makes it possible for microservices or light usage applications that don't require full-fledged web servers like IIS.
II)  Request Processing

Requests in ASP.NET Core go through a series of steps in the request processing pipeline:

  • HTTP Request: It begins with a client (browser, API client) sending an HTTP request (GET, POST, PUT, DELETE, etc).
  • Middleware Pipeline: In ASP.NET Core, a middleware pipeline is established where a callback chain mechanism determines the order of middleware functions. Each middleware component in this pipeline handles the request by collecting, modifying, or passing it to the next middleware. This approach facilitates efficient request processing and response development within the application
  • Routing Middleware: Select which method and controller the request should hit based on the URL and routes defined by the application.
  • Controller Action: The given controller action assembles requests, interacts with models and services, and prepares answers.
  • HTTP Response: The reaction is interpreted and sent by action method to the client.
III)  Middleware

Middleware components in ASP.NET Core:

  • Built-in Middleware: ASP.NET Core currently has a built-in middleware to deal with the following tasks: routing, authentication, authorization, logging, and error handling. These middleware objects are passed into the pipeline in the `Startup.cs` file as arguments to `app.Use` methods.
  • Custom Middleware: Coders can build personalized middleware that will handle tasks that are different from general middleware. Custom middleware is accomplished in two ways: by a simple function or by a class that follows the middleware pattern, which is added to the pipeline by `app.UseMiddleware`.
IV)  Dependency Injection (DI)

Dependency injection is a key aspect of ASP.NET Core:

  • DI Container: ASP.NET Core comes with a DI container which is incorporated in the framework. Once registration is done in the container during the application startup, the service (dependency) is defined by the `ConfigureServices` method in `Startup.cs`.
  • Service Lifetime: The services can have different life cycles, such as Singleton (one instance throughout the application), scoped (one instance per request), or transient (new instance every time requested).
  • Injection in Controllers and Components: Controllers, middlewares, views, and many other components would depend on these dependencies to instantiate them in either constructor or property injection. Complex applications often reuse common functionality across modules. Components must communicate with each other using well-defined methods and this leads to loose coupling, testability, and maintainability.
V)  Application Models:

ASP.NET Core supports various application models:

  • MVC (Model-View-Controller): Transforms the user account management concerns into the data (model), the user interface (view), and the business logic (controller). The programmers ensure that the requests are captured, interact with models and services, and then respond with the appropriate views or data for clients.
  • Web API: They are used for the holistic development of RESTful APIs to expose the data and functionality over HTTP. API controllers return data (JSON, XML, etc.) rather than render the views.
  • Razor Pages: A light programming model that uses code inline on an HTML page, merging it with C# code. It is exactly what you need if constructing a simple web application or a couple of pages that do not demand the totality of MVC structure.   

Middleware and Request Pipeline:

so, in this tutorial, we will dissect the middleware and HttpRequestPipeline idea of the ASP.NET Core.

I)  Middleware in ASP.NET Core:

Middleware classes represent server components that process incoming HTTP requests and the same for outgoing HTTP responses in ASP.NET Core applications. They are appended to the request stream and subsequently executed in the sequence they are appended.

Steps in Middleware Execution:

  • Middleware Registration: Middleware components are being registered in the Configure method of the Startup.cs file where the `app.UseMiddleware<MiddlewareClass>()` method is called to do so.

public void Configure(IApplicationBuilder app)
{

      app.UseMiddleware<CustomMiddleware>();

      // Other middleware registrations

}

  • Middleware Class Implementation: To achieve the functionality, middleware classes implement the `IMiddleware` interface (interface for middleware or have methods named `Invoke` or `InvokeAsync` that accept an `HttpContext` parameter and return a `Task`. Instead of `RequestDelegate _next`, the `RequestDelegate` parameter in the constructor represents the following middleware component in the pipeline.
  • Invoke Method Execution: Whenever you get a request (which ASP.NET Core refers to as a “pipeline”), the `Invoke` or ` InvokeAsync` method of each middleware component in the ASP.NET Core pipeline is called. Request at the midst of the `Invoke` method can scan, manipulate, or stop the request with logic inside of middleware the method, after that call the `_next(context)` to provide the request to the succeeding middleware component.
  • Order of  Execution: Middleware plugins are executed in order as they enter the pipeline. The first thing middleware does is to receive a request and the last thing is to send a response. The middleware where you added it first will be the first one to execute and the one you added last will be the last to execute.
II)  Request Pipeline:

ASP.NET Core Middleware is a request pipeline that runs through multiple components to process incoming HTTP requests. Each middleware component, in turn, can perform a request or response alteration that it passes to the next component.

Anatomy of the Request Pipeline:

  • HTTP Request: When a client sends an HTTP request (e.g., GET, POST) to the ASP.NET Core application, it transits to the request pipeline.
  • Middleware Execution: Each middleware component in the pipeline inspects the request within itself, and that starts from the first one added (`CustomMiddleware` in our example). Each middleware component can perform the following functions: authentication, logging, routing, exception handling, etc.
  • Request Modification: Middle components can be used to modify the request (headers, data, etc.) that may precede it to the next component.

public async Task Invoke(HttpContext context)

{

// Middleware logic before passing to the next component

context.Request.Headers.Add("Custom-Header", "Value");

await _next(context); // Pass the request to the next component

// Middleware logic after the next component has processed the request

}

  • Response Generation: After being passed throw all other middleware components, the request reaches the controller or endpoint and then produces a response.
  • HTTP Response: The process continues through the middleware pipeline so every middleware component can tweak or catch the result. Next, it is the turn to send a reply to the client.

Now, Chapter 1 concludes. I hope it has been helpful. In the second chapter, you will learn about Dependency Injection in ASP.NET Core and Configuring and Customizing ASP.NET Core Services.