Directory structure – Model-View-Controller-1

Directory structure – Model-View-Controller-1

The default directory structure contains a Controllers folder to host the controllers. On top of that, we can create a Models folder to store your model classes or use any other structure.

While controllers are typically housed in the Controllers directory for organizational purposes, this convention is more for the benefit of developers than a strict requirement. ASP.NET Core is indifferent to the file’s location, offering us the flexibility to structure our project as we see fit.

Section 4, Applications Patterns, explores many ways of designing applications.

Next, we look at the central part of this pattern—the controllers.

Controller

The easiest way to create a controller is to create a class inheriting from ControllerBase. However, while ControllerBase adds many utility methods, the only requirement is to decorate the controller class with the [ApiController] attribute.

By convention, we write the controller’s name in its plural form and suffix it with Controller. For example, if the controller relates to the Employee entity, we’d name it EmployeesController, which, by default, leads to an excellent URL pattern that is easy to understand:

  • Get all employees: /employees
  • Get a specific employee: /employees/{id}
  • And so on.

Once we have a controller class, we must add actions. Actions are public methods that represent the operations that a client can perform. Each action represents an HTTP endpoint.More precisely, the following defines a controller:

  • A controller exposes one or more actions.
  • An action can take zero or more input parameters.
  • An action can return zero or one output value.
  • The action is what handles the HTTP request.

We should group cohesive actions under the same controller, thus creating a loosely coupled unit.

For example, the following represents the SomeController class containing a single Get action:

[Route(“api/[controller]”)]
[ApiController]
public class SomeController : ControllerBase
{
    [HttpGet]
    public IActionResult Get() => Ok();
}

The preceding Get method (action) returns an empty 200 OK response to the client. We can reach the endpoint at the /api/some URI. From there, we can add more actions.

The ControllerBase class gives us access to most of the same utility methods as we had with the Minimal APIs TypedResults class.

Next, we look at returning value.

Returning values

Building a REST API aims to return data to clients and execute remote operations. Most of the plumbing is done for us by the ASP.NET Core code, including serialization.

Most of the ASP.NET Core pipeline is customizable, which is out of the scope of this chapter.

Before returning values, let’s look at a few valuable helper methods provided by the ControllerBase class:

MethodDescription
StatusCodeProduces an empty response with the specified status code. We can optionally include a second argument to serialize in the response body.
OkProduces a 200 OK response, indicating the operation was successful. We can optionally include a second argument to serialize in the response body.
CreatedProduces a 201 Created response, indicating the system created the entity. We can optionally specify the location where to read the entity and the entity itself as arguments. The CreatedAtAction and CreatedAtRoute methods give us options to compose the location value.
NoContentProduces an empty 204 No Content response.
NotFoundProduces a 404 Not Found response, indicating the resource was not found.
BadRequestProduces a 400 Bad Request response, indicating an issue with the client request, often a validation error.
RedirectProduces a 302 Found response, accepting the Location URL as an argument. Different Redirect* methods produce 301 Moved Permanently, 307 Temporary Redirect, and 308 Permanent Redirect responses instead.
AcceptedProduces a 202 Accepted response, indicating the beginning of an asynchronous process. We can optionally specify the location the client can query to learn about the status of the asynchronous operation. We can also optionally specify an object to serialize in the response body. The AcceptedAtAction and AcceptedAtRoute methods give us options to compose the location value.
ConflictProduces a 409 Conflict response, indicating a conflict occurred when processing the request, often a concurrency error.

 Table 6.1: a subset of the ControllerBase methods producing an IActionResult.

Other methods in the ControllerBase class are self-discoverable using IntelliSense (code completion) or in the official documentation. Most, if not all, of what we covered in Chapter 5, Minimal APIs, is also available to controllers.

Leave a Reply

Your email address will not be published. Required fields are marked *