Section 8: Creating a Controller
Introduction:
A controller is a "Processing Unit" of an ASP .Net application. It will receive a request from the client, forward it to the business logic (processor), then return the results back to the Views.
Controllers are classes derived from System.Web.Mvc.Controller; controller's public methods are called Action methods; these actions are the APIs of the service. These APIs can be configured for different HTTP methods (Get, Post, Put, etc,.), protect it from unauthorized access, and many more.
For instance, if I have www.chaiandwine.com\Product\Get\1. This request will be handled by the ProductController, and Get is its Action method.
Also, every controller should end with a keyword - "Controller". For example, if we have to create a controller for our Hotel model, we should name it as HotelController.
Note that the Controller methods cannot be overloaded and it cannot be a static method.
A controller's Action method will return ActionResult. ActionResult is a base class and it derives many other classes as follows:
- View - We will return the view when we want to return HTML. We are returning a View page here, and this is a more frequently used return type.
- JSON - This is the second most frequently used and we return a JSON structure here. Usually used by client-server applications.
- RedirectToAction - When we want to redirect to another Action method, we use this. For example, we have a Create action method. After the Creation of an item, we want to list the items. hence, we will redirect to the List action method.
- File - if we want to return a downloadable file, we use this.
- Content - This will return a text result. If we return just a string or an integer from our Action method, it will be typecasted to this method.
In the above example, I had told that if I enter www.chaiandwine.com\Product\Get\1 in the browser. This request will be handled by the ProductController, and Get is its Action method. There should be a way to map this from the URL to the controller. This mapping method is called Routing. There are different types of routing, and I will be using the Attribute Routing here. In Attribute Routing, we will be mapping the URL to the controllers and actions by adding Attributes. You will see this in the below implementation.
Implementation:
In our previous section, we have added a few simple operations (CRUD) for the Hotel model using the Repository and UnitofWork. However, the client can access the Hotel data only through a controller.
Design:
- Create a class that is derived from Controller.
- Add public method. This method is an action method.
- Return an ActionResult from the controller.
- Add Routing attributes.
To add a new controller,
a. Right-click on a Controller folder and select 'Add->Controller' as shown in the below screen.
c. Add the below code for the controller.
namespace LearningMVC.Controllers
{
[Route("api/[controller]")]
public class HotelController : Controller
{
private readonly IUnitOfWork _unitOfWOrk;
public HotelController(IUnitOfWork unitOfWOrk)
{
_unitOfWOrk = unitOfWOrk;
}
[HttpGet]
public IActionResult GetAllHotels()
{
var obj = _unitOfWOrk.Hotel.GetAll();
return Ok(obj);
}
}
}
The Route attribute will tell the controller how the request to the service has to be routed or handled. When we write [Route("api/[controller]")], we are saying that any request with api/[controller] should be rerouted to the Hotel Controller. [HttpGet] will tell the controller that if the request is for HTTP's Get methods, then call this method.
Testing
Let us now test the code which we have implemented so far. Since we don't have the client ready, we will use a testing tool - Postman. Google for Postman and install the latest version. Using Postman we can post a request to our service; this request will be routed to our controller, then to our Action method. From the Action method, it has to call the GetAll method. GetAll method is implemented using the IRepository and Unit of Work pattern; this method should return the list of hotels from the Database. Please note that our Database is empty. Hence, we will populate the database manually.
To populate the data, Launch SQL Server Management Studio, Select the Hotel Database, Right-click on the database, and select Edit Top 200 Rows.
Start the service now. To Start or Launch, just hit f5. You would see the following screen when the service starts.
Finally, launch the Postman, enter the URL as below(port may be different than mine. Please use the appropriate port. You would see it in the chrome browser when you launch the service). Hit Click, and you would see the data showing up.
Although we are getting the data, we are not doing it right. This is because we are showing all the properties of the Models to the client (Postman). We are not using the concept of DTOs.
When we get the list of Hotels using _unitOfWOrk.Hotel.GetAll(); we will get all the properties of the Hotel Model. We need to convert this Hotel Model to HotelDto.
To convert one object to another, we have Automapper.
If we have to use any interface in our controller, we need to inject it through the controller's constructor. This concept called constructor dependency injection and we will cover it later.
To inject the Automapper interface, add the below code.
namespace LearningMVC.Controllers
{
[Route("api/[controller]")]
public class HotelController : Controller
{
private readonly IUnitOfWork _unitOfWOrk;
private readonly IMapper _myMapper;
public HotelController(IUnitOfWork unitOfWOrk, IMapper myMapper)
{
_unitOfWOrk = unitOfWOrk;
_myMapper = myMapper;
}
[HttpGet]
public IActionResult GetAllHotels()
{
var HotelsObj = _unitOfWOrk.Hotel.GetAll();
var HotelsDtoObj = new List<HotelDTO>();
foreach (var HotelObj in HotelsObj)
{
HotelsDtoObj.Add(_myMapper.Map<HotelDTO>(HotelObj));
}
return Ok(HotelsDtoObj);
}
}
}
Rebuild the solution and relaunch the service. Again, post the request in the Postman. You would see the below screen:
Adding Another Get method:
We have implemented the Get method as above. Let us add one more Get method which will return a Hotel for the ID of the hotel passed.
[HttpGet("{hotelId:int}")]
public IActionResult GetHotel(int hotelId)
{
var HotelObj = _unitOfWOrk.Hotel.Get(hotelId);
if(null== HotelObj)
{
return NotFound();
}
var HotelDtoObj = _myMapper.Map<HotelDTO>(HotelObj);
return Ok(HotelDtoObj);
}
You would have noticed that this Get method has a parameter; hence, in the [HttpGet("{hotelId:int}")] attribute, we provide the parameter, hotelId.
This parameter is used to search for the hotel. If the hotel is not available in the DB we would return the NotFound error.
To invoke this API, we should send the request as below in the postman. We are passing the ID in the URL; the ID in the below example is 3.
There are various ways of passing the parameter to the Action method. The method we are using is passing the parameter using the URL. Other methods include passing the parameter using the Query Param, passing the parameters using the Request Header, and passing the parameters using the Request Body.
Outroduction:
Even though this section is lengthy, this covers the very important concept of an ASP .Net application. We have learned how to create a controller, action methods, and routing. In this example, we have created an Action method for the HTTP Get method. We can create an Action method for other HTTP methods and see this in our next section.
⎘ Under Development