Controllers and Actions

1. Introduction

For ASP.NET Core web applications, the controller is where the job is done. That's because controller encapsulates the business logic and it is the center of the MVC pattern. The goal of this module is to deliver the knowledge of how to design and implement controllers for ASP.NET Core web applications. Several critical topics are covered by this module, including:

  • URL routing, naming convention of controllers and actions
  • Advanced model binding and model validation
  • Action design and action results

2. Controllers and Actions

2-1. Lesson Overview

  • The basic concept of controllers and actions
  • The design of controllers
  • The design of actions

2-2. What are Controller and Actions

A controller is a .NET class that used to define and group a set of actions. An action (or action method) is a method on a controller which handles HTTP requests.

A controller logically groups actions together. For example, the ProductControllercontains the actions for creating, deleting, updating or searching products. HTTP requests are mapped to controller's actions through URL routing, which we will discuss later in next lesson.

Usually, the actions will launch the rendering process of the views and return the rendering result. Sometimes an action can transfer the logic execution to another action, which called redirection.

2-3. The Design of Controller

For a well-designed controller, there are some constraints and conventions.

Constraints: Mark a Class as Controller

To help the ASP.NET Core framework recognize that a class is a controller, the class has to satisfy _at least one _of the constraints below:

  • The class name is suffixed with “Controller”
  • The class inherits from a class whose name is or is suffixed with “Controller”
  • The class is decorated with the [Controller] attribute

The four classes in the example code below are all valid ASP.NET Core controllers:

using Microsoft.AspNetCore.Mvc;

namespace App.Controllers {
    // Controller 1: the class name is suffixed with "Controller"
    public class ProductController {
        // Actions
    }

    // Controller 2: the class inherits from a class whose name is or is suffixed with "Controller"
    public class Product : Controller {
        // Actions
    }

    // Controller 3: the class is decorated with the [Controller] attribute
    [Controller]
    public class Product {
        // Actions
    }

    // Controller 4: preferred name
    public class ProductController : Controller {
        // Actions
    }
}

Conventions: Design a Good Controller

To make the controller class work for a real-world ASP.NET Core web application, we need to follow the conventions below:

  • Put all controller classes in the project's root-level Controller folder. It will lower the cost of maintenance. When you create a new class in the Controllersfolder with Visual Studio Code, the class will be organized into the Controllersnamespace.

  • Make the controller class inherit from Microsoft.AspNetCore.Mvc.Controller. This allows you to reuse the properties and methods implemented by the Controllerbase class. For example, call Viewmethod to render a view or, call RedirectToActionto transfer the execution logic to another action method.

2-4. The Design of Actions

Public methods of a controller are actions. An action method contains the logic for mapping an HTTP request to a business concern. The return value of an action represents the state of the web application.

For example, when the user searches products by name, the action ProductController.GetProductsByName(string name)will be called. In the body of this action method, the data access component will be called to search for the products in the database. After the database returns the search result, the action will choose a proper view to render the result. HTML content, the rendered view, represents the status of the application - either there ARE some products that have that name, or there is NO such product in the database with that name. Below is the sample code:

public class ProductController : Controller {
    public DatabaseContext dbContext { get; set; }

    public IActionResult GetProductsByName(string name) {
        IList<Product> products = null;
        if(String.IsNullOrWhiteSpace(name)){
            products = dbContext.GetAllProducts();
        }else{
            products = dbContext.GetProductsByName(name);
        }

        return RedirectToAction("Index", products);
    }

    public IActionResult Index(IList<Product> products) {
        return View(products);
    }
}

2-5. The Return Value of Actions

Theoretically, you can return values of any type from an action. For example, the actions below:

public class SampleController {

    public string SayHello() {
        return "Hello, ASP.NET Core!";
    }

    public double Add(double a, double b) {
        return a + b;
    }

    public IActionResult CylinderVolume(double r, double h) {
        double v = Math.PI * Math.Pow(r, 2) * h;
        return new JsonResult(v);
    }
}

In theControllerclass, there are two groups of overloading methods,ViewandRedirectToAction. The function ofViewmethods is to render a view. The function ofRedirectToActionmethods is to transfer the execution of one action to another. Accordingly, return types of these two groups of overloading methods areViewResultandRedirectToActionResult, both of them are implementations ofIActionResult.

In short, usuallyreturn View(/*...*/);orreturn RedirectToAction(/*...*/);will be the last statement of an action.

3. URL Routing

3-1. Lesson Overview

The URL routing determines the map of an ASP.NET Core web application. Thus, a well-designed URL routing system is very critical. In this lesson, we will learn the concept of URL routing and how to use URL routing in a web application.

3-2. What is URL Routing

URL routing(or routing) functionality is responsible for mapping an incoming request to a route handler. Usually, the handler is an action.

Routes describe how URL paths should be mapped to actions, and they are case-insensitive. ASP.NET Core uses _Routing middleware _to match the URLs of incoming requests with pre-defined routes; then the valid URLs will be mapped to the target actions. As a result, the target actions will be triggered.

There are two types of routes supported in ASP.NET Core:

  • Conventional routing
    • Conventional routing defines routes by using conventions. In daily communication, conventions, URL templates, route templates are names that are interchangeable. A typical convention is"{controller=Home}/{action=Index}/{id?}".
  • Attribute routing
    • Attribute routing uses a set of attributes to map actions directly to route templates. For example, if a controller class is modified by [Route("Product")], all URLs start with _Product _will be navigated to this controller. If an action in this controller is modified by [Route("Create")], the URL product/createwill be handled just by this action.

3-3. Conventional Routing

After creating an ASP.NET Core application, you will find a file named Startup.csin the project. If you open this file you can see a class namedStartup. The methods of this class will be invoked when the web application starts and many critical configuration options, including conventional routing creation, happen in here.

In the body of theConfiguremethod you can see the code below:

app.UseMvc(routes =
>
 {
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

This piece of code does two things:

  1. Tells the web application to load the MVC middleware. Without this, the application is not an MVC application at all.
  2. Adds a route named default to its conventional routing system.

3-4. Routing Template

The string"{controller=Home}/{action=Index}/{id?}"is the routing template of the default route.

The “syntax” of a routing template is very simple, below is a summary of how to deal with most of the scenarios you may encounter:

  1. There are only two kinds of content in a routing template -route parameters_and_literal strings

Route parameters are the curly braced items, for example{controller},{action}and{id}

Literal string is all the content that is other than route parameters. For example, in the templatesearch/{year}/{file}.{ext}, thesearch/, the/between{year}and{file}, and the.between{file}and{ext}are all literal strings.

Two route parameters must be separated by literal strings, or you will get an exception when the application starts.

  1. There are some constraints and decorators for route parameters:

  2. The{controller}and{action}are two special parameters, their values will be mapped to the target controller's name and target action's name correspondingly.

  3. When mapping the{controller}parameter to the target controller class, theControllersuffix (if it exists) of the class name, will be ignored. For example, if the{controller}parameter gets the valueProduct, it matches the class ProductController , the class Product modified by [Controller] and the class Product inherits Microsoft.AspNetCore.Mvc.Controller .

  4. Except {controller} and {action} , other parameters will be mapped to the parameters of the target action by default.
  5. A ? suffix indicates the parameter can be omitted, for example the {id?}
  6. A route parameter can have a default value, for example the Home in {controller=Home} and the Index in {action=Index}
  7. You can modify the route parameter by adding constraints. For example {id:int} limits the parameter to accept only integer values, and {ssn:regex(^\\d3-\\d2-\\d4$)} requires the value of the parameter {ssn} to matching the regular expression. You can modify a parameter with multiple constraints, for example {password:minlength(6):maxlength(20)} .

Based on the descriptions above, let's have a closer look at the template{controller=Home}/{action=Index}/{id?}:

results matching ""

    No results matching ""