Introduction to Controllers and Action Methods
This is part 20 of ASP.NET Core tutorial. In this video, we'll discuss what is controller and its role in an ASP.NET Core MVC.
In simple terms, a controller in MVC is a class that derives from the framework's controller base class, and the name of the controller class is usually suffixed with this word controller. For example, HomeController, EmployeesController, ProductsController, etc. When a request from the browser arrives at our application, it is this controller in the MVC design pattern that handles the incoming HTTP requests and responds to that user action.
A controller class usually has a set of public methods. These public methods within the controller are called as action methods. At the moment, within our HomeController, we only have one public method, which is index. So it is these action methods within the controller that handle and process the incoming HTTP requests.
Mapping a URL to an Action and Building the Model
Now, let's say we open our favorite browser and in the address bar we typed this URL: localhost/home/details. When this request arrives at our ASP.NET Core MVC application, it is the controller that handles this incoming HTTP request. This URL segment, /home/details, is mapped to the details public action method within the HomeController class. This mapping is done by routing rules defined in our application. We'll discuss routing in detail in our upcoming videos. For now, understand this URL segment, that is /home/details, is mapped to the details action method within the HomeController.
At the moment within our application, in the HomeController, we only have the index action method. Let's also create the details action method. I'm going to make a copy of this and then change the name of the method to details. We want this details action method to retrieve a specific employee's details and display those details on the browser. So as part of processing this request, the controller also builds a model. In our case, the model is the Employee class. If you recollect from our previous videos in the series, we already created this Employee model class.
So within the details action method within our HomeController, first, let's create the employee model object. It is this IEmployeeRepository service that is responsible for retrieving employee data. So our HomeController has a dependency on this IEmployeeRepository service. So this service is injected into the HomeController using the constructor. This is called dependency injection, and we discussed dependency injection in detail in our previous video.
Now, I'm going to make this private field read-only. This is a good practice because it prevents accidentally assigning another value to this private field, maybe inside another method within the controller. Now let's use this injected IEmployeeRepository service and then retrieve employee details whose ID is one. At the moment, we have the employee ID hard-coded to one. In our upcoming videos in the series, we'll discuss how to dynamically retrieve the employee ID value from the URL instead of hard-coding it like this.
Returning JSON Data from a Controller
Once the controller has the required model data, the controller may choose to return this model data to the caller if we are building an API or a restful service. For a minute, let's assume we're building an API and we want to return this model data in JSON format to whoever made this request. Now to be able to return JSON data, I am going to use the Json method and to it, let's pass our model object. And from the intellisense, as you can see, this method returns JsonResult. So let's change the return type of this method to JsonResult.
With all these changes in place, let's run our application. Change the URL to /home/details. Notice we see JSON data as expected. Notice the details action method explicitly returns JSON formatted data. This is okay if you want your details action to always return JSON data. This approach does not respect content negotiation and it ignores the incoming request's Accept header. Now if you're new to the concept of content negotiation and accept header, we'll discuss them in detail when we discuss building restful services.
Implementing Content Negotiation with ObjectResult
Now if you want your details action to respect content negotiation, then change the return type here to ObjectResult and build a new ObjectResult object, and to it pass the model object. Let's build our solution.
I have this tool called Fiddler running on my machine. Fiddler is a free tool to test our services. What we want to do now is issue a request to this URL. So let's copy and paste that same URL in Fiddler. Here we want to issue a get request, so GET is selected. Now we are using Fiddler because we want to be able to set the Accept header and specify that we want data in XML format. So we set the Accept header to application/xml and then click the execute button. Request completed. And if we look at the response right here, notice on the Raw tab we can see the data is still in JSON format.
This is because at the moment within our application, we don't have the required service configured to be able to return data in XML format. Our application needs to have the XML serializer formatter service added. We do that in the Startup.cs file. So within the ConfigureServices method, to this AddMvc() method we chain another method, and that is AddXmlSerializerFormatters() method.
So with this change in place, let's issue the same request again. Notice the Accept header is still set to application/xml. So when I click the execute button, request completed successfully. And when we inspect the response that we get, notice the data is in XML format as expected.
Returning a View in an MVC Application
In our case, we are not building a web API, we're building an MVC web application. So we want a view to present the model data to the user. So after the controller has built a model, it also selects a view and passes the model data to the view. The view then generates the required HTML to present that model data. This HTML is then sent over the network to the user who made that request.
So from the details action method from our HomeController, we want to return a view. So instead of using new ObjectResult here, we're going to use the View method. And from the intellisense, you can see this View method returns ViewResult. So let's change the return type of this method to ViewResult. With this change in place, when we reload the webpage, notice we have an error. It is basically complaining it cannot find this view file, details.cshtml. We'll discuss views in our next video.
Controller Role Summary: API vs. MVC
When a request from the browser arrives at our application, it is the controller in the MVC design pattern that handles the incoming HTTP requests and responds to the user action. As part of processing the incoming requests, the controller builds the model and simply returns that model data to the caller if we are building an API. So in the case of an API, we do not have a view; we just have the controller and the model. In case of an MVC web application, in addition to building the model, the controller also selects a view and passes the model data to the view. The view then generates required HTML to present that model data. This HTML is then sent over the network to the user who made that request. That's it in this video. Thank you for watching.