Create API With ASP.NET Core - Day 2 - Creating API In ASP.NET Core

Introduction

This article of the series “Web API with ASP.NET Core” will focus on creating Web API with ASP.NET Core. In the last article of the series, we learned about ASP.NET Core basics and how to set up an empty solution and play with request pipeline and middleware. In this article, we’ll discuss less theory and try to create an API. We’ll make use of ASP.NET Core MVC Middleware to build the API. We’ll cover in details on how to return resources, data and how to talk to API via HTTP request in this article. We can use the same source code as we got at the completion of last article of the series.

Middleware

To build the API, we’ll add a middleware in HTTP request pipeline, and we can do that by adding the middleware in Configure() method of Startup class. To do this, we need to add the service to the container. In the earlier version of .NET, we used to build services via Web API in ASP.NET. For creating an application with user interface that is used by the end-user, we used ASP.NET MVC. When we talk about ASP.NET Core, we do not have a separate Web API framework now.

ASP.NET Core

The functionalities of MVC and Web API are now combined in one framework i.e. ASP.NET Core MVC. Its purpose is to build web applications that use APIs and MVC approach. To create an API, we need to configure the middleware and add that to the request pipeline.

RoadMap

We’ll follow a roadmap to learn and cover all the aspects of Asp.net core in detail. Following is the roadmap or list of articles that will cover the entire series.

  1. Create API with ASP.Net Core (Day 1): Getting Started and ASP.NET Core Request Pipeline
  2. Create API with ASP.Net Core (Day 2): Create an API and return resources in ASP.NET Core
  3. Create API with ASP.Net Core (Day 3): Working with HTTP Status Codes and returning sub resources in ASP.NET Core API
  4. Create API with ASP.Net Core (Day 4): Working with Serializer Settings and Content Negotiation in ASP.NET Core API
  5. Create API with ASP.Net Core (Day 5): Understanding Resources in ASP.NET CORE API
  6. Create API with ASP.Net Core (Day 6): Inversion of Control and Dependency Injection in ASP.NET CORE API
  7. Create API with ASP.Net Core (Day 7): Getting Started with Entity Framework Core
  8. Create API with ASP.Net Core (Day 8): Entity Framework Core in ASP.NET CORE API
MVC Pattern

MVC stands for Model View Controller. MVC is basically an architectural design pattern to define user interfaces. It encourages loose coupling and separation of concern with better testability. It consists of three parts.

ASP.NET Core

The Model takes care of the business logic. In some cases, when the MVC Pattern is only used at the top level of application’s architecture, in that case model doesn’t contain the logic, but a component of application layer such as business layer handles it. In some implementations, use of View model is made to retrieve and store data. The View is the UI layer, it takes responsibility to show the data in a well-structured format with a rich UI for e.g. in the form of HTML. The controller takes care of the communication between view and the model, and also makes decision based on user inputs. In terms of dependencies of these components, the controller and the view depend upon model and the controller to some extent also depends upon the view. So a controller makes a decision to choose the view to be displayed to user based on user input and provide the data from the model to the view in case needed. But when we talk about building an API, we should see how this structure maps to our need. So in the terminology of MVC, View is basically the data that we get as response that is it represents our resources or data in the form of JSON.

ASP.NET Core

In our case, we expect that a request will come from any other user application having a user interface that just wants to access our service; when request comes, an action on our controller will be invoked, the controller will send the input data, and a model is returned to the View. View in our case would not be an aspx, razor, or html page but will represent result data in JSON format.

ASP.NET Core MVC Middleware

Now, we’ll try to add ASP.NET Core MVC middleware to our application. In the startup class, we can add the middleware, but to proceed with that implementation, first add the AspNetCore.MVC nuGet package to the application as the service is defined in the external dependency named Microsoft.AspNetCore.Mvc NuGet package. Right click on the project and choose “Manage Nuget packages” as shown below.

ASP.NET Core

Now, install the latest stable release of Microsoft.AspNetCore.Mvc package. In our case, it is 1.1.2.

ASP.NET Core

Once installed, all the necessary packages will be added related to ASP.NET MVC. Now in the Startup class in the ConfigureServices method we’ll add the middleware to request pipeline. Just write services.AddMVC() method to add the service. 

  1. // This method gets called by the runtime. Use this method to add services to the container.  
  2. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
  3. public void ConfigureServices(IServiceCollection services)  
  4. {  
  5.   services.AddMvc();  
  6. }   

On to the configure method where we'll now add MVC middleware to the request pipeline. We can call the method app.UseMvc() in this case; we’ll add this after where we added the exception handler in the first article of the series,

So that our exception handler catches the exception before actually delegating the request to MVC middleware and also hadles the MVC related exception and send the correct response. We can now also comment out the code that we introduced to raise the exception.

  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
  2.   {  
  3.     loggerFactory.AddConsole();  
  4.   
  5.     if (env.IsDevelopment())  
  6.     {  
  7.       app.UseDeveloperExceptionPage();  
  8.     }  
  9.     else  
  10.     {  
  11.       app.UseExceptionHandler();  
  12.     }  
  13.   
  14.     app.UseMvc();  
  15.   
  16.     //app.Run(async (context) =>  
  17.     //{  
  18.     //  throw new Exception("Test Dev Exception Page");  
  19.     //});  
  20.   
  21.     //app.Run(async (context) =>  
  22.     //{  
  23.     //  await context.Response.WriteAsync("Hello World!");  
  24.     //});  
  25.   }  

Navigate to project properties and debug tab and change the environment variable to Development (remember? We changed that to production mode in last article).

ASP.NET Core

Now, run the application, and we get a blank page.

ASP.NET Core
Now, open the developer’s tool of the browser by pressing F12. We still see two exceptions there.

ASP.NET Core

We got 404 exception i.e. Not found status. It is obvious as we just added the MVC middleware but did not do any thing else. There is no code to be executed that returns the data, and there is also no routing defined yet. So, let’s create a controller that actually returns the data or resources like Employee information.

Create API Controller to return resources

We’ll now add a new controller to our application, since we are in process of building an Employee API, we’ll name our controller as EmployeesController. We can follow the template based approach to add controller with default action methods, but from learning point of view, we’ll start with a scratch implementation so that we actually know what we are creating and should have full control on our code. So add a new folder in the project and name it Controllers, and add a new class to that Controllers folder and name it EmployeesController.

ASP.NET Core

The EmployeesController should derive from Microsoft.AspNetCore.Mvc.Controller class. 

  1. using Microsoft.AspNetCore.Mvc;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace EmployeeInfo.API.Controllers  
  8. {  
  9.     public class EmployeesInfoController : Controller  
  10.     {  
  11.     }  
  12. }   

Now, we’ll add the action responsible for returning the data. Since we need to return data in JSON format, we can make use of JsonResult class in that case. This will convert the objects that we pass to JsonResult class constructor to a JSON format.

  1. public JsonResult GetEmployees()  
  2.   {  
  3.     return new JsonResult();  
  4.   }  

Since we need to return the list of employees, so ideally we should have an employee entity class, but for now since we don’t have it, let’s create three anonymous objects and return a list of employees.

  1. public JsonResult GetEmployees()  
  2.  {  
  3.    return new JsonResult(new List<object>()  
  4.    {  
  5.      new {employeeid = 01989, Name = "John Patrick"},  
  6.      new {employeeid = 01987, Name= "Michael"},  
  7.      new {employeeid = 01988, Name= "Akhil Mittal"}  
  8.    });  
  9.  }  

When it is required to consume HTTP service so as to fetch the data, we need to send an HTTP request to a URI that delegates the request to the “Get” method of the API. We can send a request from a browser itself or from any tool just for the sake of checking the response of the service. We’ll use Postman for all these request and response tracking operations.

ASP.NET Core

Install Postman to the chrome web browser app and open it.

ASP.NET Core

So, let's open up Postman. In Postman, we can create our requests. First run the application and then create a request Uri to fetch the list of employees as http://localhost:2542/api/employees, select GET method and click Send button to send the request, As a response we do not get the list of employees but a status with 404 not found as shown in following image.

ASP.NET Core

That means that the MVC framework so far does not know how to map the requested URI i.e. api/employees to the Get method or GetEmployees method. Here comes the concept of routing. Let’s explore that in detail.

Routing in ASP.NET MVC Core

The purpose of routing is to match the Uri request to the particular method of the controller. MVC framework takes the responsibility of parsing the received request and map it to controllers and respective actions. Routing could be done in two ways - the first is convention based and the second is attribute based routing.

Convention based routing

For convention based routing, we need to follow certain conventions as shown below,

  1. app.UseMvc(config => {  
  2.         config.MapRoute(  
  3.         name: "Default",  
  4.         template: "{controller}/{action}/{id?}",  
  5.         defaults: new { controller = "Home", action = "Index" }  
  6.         );  
  7.       });  

This is similar to what we use to use in earlier versions of .net with MVC or Web API. In this case we need to pass the configuration in app.UseMvc method to follow the convention based routing. This would map the URI employees/index to the index method on a controller named Employees controller. These are tradidional ways of routing more suitable for typical MVC application where view have to be returned. For API based applications, this conventional based routing is not preferred and recommended, but instead attribute based routing is recommended.

Attribute based routing

Attribute based routing allows us to decorate our controller and actions with the attributes that we want, therefore giving more control over the routing operations. These attributes are provided with a template and Uri is then matched through that template to the specific action/method of the controller.

The most common functionalities of an API are create, read, update and delete operations.

ASP.NET Core

For reading the resources the suitable HTTP method is “GET”, so in the code at action level, we use HttpGet attribute on the code that is responsible for reading and returning the resources. For e.g. api/employees will return all the employees and api/employees/01989 will return the employee with employee id 01989.

POST is specified by HttpPost attribute at action level. It is responsible for creating a resource or persisting a resource. For e.g. api/employees Uri could be used to create an employee resource.

PUT and PATCH are used for update URI’s, both are used at action level. There is a minor difference between both of the Http methods. When PUT is used, it means it is used for a complete update; i.e., all the fields coming in the request will overwrite the existing ones, HTTP attribute for PUT is HttpPut. In case of PATCH it is HttpPatch, PATCH means partial update, unlike PUT , it does not do a complete update, but a partial one; i.e., a few fields can also get updated if we use PATCH.

The last one is DELETE , and HTTP attribute is HttpDelete. It is as the name says, used for deleting URI’s for things like  api/employees/01989 and will delete the employee having id 01989.

There is one more attribute that does not map to any specific HTTP attribute and that is called, “Route” attribute. This attribute is used at controller level to provide a common template to be prefixed to all action level attributes. For example if we know that our API Uri starts from “api/employees”, the Route attribute could be used at controller level with “api/employees” as a template value for all actions, so we can skip providing this particular value to all the actions.

Returning Resources via Routing

Now in the earlier section we were trying to get the resource via URI. Now we know how routing works, so just add the routing attribute to our action and see how  it works. Since we need to get the employees, we’ll use HttpGet attribute over the action. Place [HttpGet("api/employees")] over the action.

  1. using Microsoft.AspNetCore.Mvc;  
  2. using System.Collections.Generic;  
  3.   
  4. namespace EmployeeInfo.API.Controllers  
  5. {  
  6.   public class EmployeesInfoController : Controller  
  7.   {  
  8.     [HttpGet("api/employees")]  
  9.     public JsonResult GetEmployees()  
  10.     {  
  11.       return new JsonResult(new List<object>()  
  12.       {  
  13.         new {employeeid = 01989, Name = "John Patrick"},  
  14.         new {employeeid = 01987, Name= "Michael"},  
  15.         new {employeeid = 01988, Name= "Akhil Mittal"}  
  16.       });  
  17.     }  
  18.   }  
  19. }  

Compile the application, run it and then again request the resource via URI from postman.

ASP.NET Core

This time we get the desired result i.e. the list of employees from our action. Hence it is proved that the routing and action both are working fine. So we have a working API now J.

The controller typically contains other methods that map to CRUD operations and we want each of our actions to have a consistent URI. If we know that all out actions will have “api/employees” as an attribute, we can make use of Route attribute at controller level and provide this part of Uri there as shown below,

  1. using Microsoft.AspNetCore.Mvc;  
  2. using System.Collections.Generic;  
  3.   
  4. namespace EmployeeInfo.API.Controllers  
  5. {  
  6.   [Route("api/employees")]  
  7.   public class EmployeesInfoController : Controller  
  8.   {  
  9.     [HttpGet()]  
  10.     public JsonResult GetEmployees()  
  11.     {  
  12.       return new JsonResult(new List<object>()  
  13.       {  
  14.         new {employeeid = 01989, Name = "John Patrick"},  
  15.         new {employeeid = 01987, Name= "Michael"},  
  16.         new {employeeid = 01988, Name= "Akhil Mittal"}  
  17.       });  
  18.     }  
  19.   }  
  20. }  

In this case by default with the Get Http Verb in the request, our get method will be called and return the result. Run the application and send the request from postman again to check if this is working or not.

ASP.NET Core

In most cases, one would work with model classes, POCOs, or DTOs, that are then serialized to JSON. We’ll see now how we can improve this implementation.

Dealing with Model Classes

In this section we’ll try to avoid returning JSON directly and anonymous objects. So we’ll create a model/entity class for Employee. Add a new folder named Models to the project and add a class named EmployeeDto. Add properties like ID, Name, Designation and Salary to that EmployeeDto class. One can also add the calculated fields property to the DTO class for e.g. the details of the companies he has worked in the past.

ASP.NET Core

EmployeeDto Class

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5.   
  6. namespace EmployeeInfo.API.Models  
  7. {  
  8.   public class EmployeeDto  
  9.   {  
  10.     public int Id { get; set; }  
  11.     public string Name { get; set; }  
  12.     public string Designation { get; set; }  
  13.     public string Salary { get; set; }  
  14.   
  15.     public int NumberOfCompaniesWorkedWith { get; set; }  
  16.   
  17.   }  
  18. }  

There is an important point here that what is returned from or accepted by an API is not the same as the models used by the underlying data store. For now, we’ll work with in-memory data, as focus is on API only.Therefore the in-memory data store will simply work on these DTO classes that we are creating. In the later articles of the series we’ll see how we can use Entity Framework core to work with database and objects. Since now we need to return the data, so we’ll create an in-memory data repository containing list of employees. Later we can always use database to fetch the data from and use Entity Framework for communication.

So add a new class named EmployeesDataStore and create a property names Employees i.e. a list of Employee DTO. And add some dummy data to it.

ASP.NET Core

Create a static property on our EmployeesDataStore, and name that Current, it will return the instance of EmployeesDataStore. Since it is a static property and instance remains in memory, we can continue to work on the similar data until we start the application again. Note that this is not the encouraged approach, but we are temporarily following it to understand the topic.

EmployeesDataStore.cs 

  1. using EmployeeInfo.API.Models;  
  2. using System.Collections.Generic;  
  3.   
  4. namespace EmployeeInfo.API  
  5. {  
  6.   public class EmployeesDataStore  
  7.     {  
  8.     public static EmployeesDataStore Current { get; } = new EmployeesDataStore();  
  9.     public List<EmployeeDto> Employees { get; set; }  
  10.   
  11.     public EmployeesDataStore()  
  12.     {  
  13.       //Dummy data  
  14.       Employees = new List<EmployeeDto>()  
  15.             {  
  16.                 new EmployeeDto()  
  17.                 {  
  18.                      Id = 1,  
  19.                      Name = "Akhil Mittal",  
  20.                      Designation = "Technical Manager",  
  21.                      Salary="$50000"  
  22.                 },  
  23.                 new EmployeeDto()  
  24.                 {  
  25.                      Id = 2,  
  26.                      Name = "Keanu Reaves",  
  27.                      Designation = "Developer",  
  28.                      Salary="$20000"  
  29.                 },  
  30.                  new EmployeeDto()  
  31.                 {  
  32.                      Id = 3,  
  33.                      Name = "John Travolta",  
  34.                      Designation = "Senior Architect",  
  35.                      Salary="$70000"  
  36.                 },  
  37.                   new EmployeeDto()  
  38.                 {  
  39.                      Id = 4,  
  40.                      Name = "Brad Pitt",  
  41.                      Designation = "Program Manager",  
  42.                      Salary="$80000"  
  43.                 },  
  44.                    new EmployeeDto()  
  45.                 {  
  46.                      Id = 5,  
  47.                      Name = "Jason Statham",  
  48.                      Designation = "Delivery Head",  
  49.                      Salary="$90000"  
  50.                 }  
  51.             };  
  52.   
  53.     }  
  54.   }  
  55. }  

Now, we can move to our controller and modify the implementation. Instead of anonymous properties in the json list, we directly call now EmployeesDataStore Current property and Employees from there.

  1. using Microsoft.AspNetCore.Mvc;  
  2. using System.Collections.Generic;  
  3.   
  4. namespace EmployeeInfo.API.Controllers  
  5. {  
  6.   [Route("api/employees")]  
  7.   public class EmployeesInfoController : Controller  
  8.   {  
  9.     [HttpGet()]  
  10.     public JsonResult GetEmployees()  
  11.     {  
  12.       return new JsonResult(EmployeesDataStore.Current.Employees);  
  13.     }  
  14.   }  
  15. }  

Now, run the application and again request the response from post man.

ASP.NET Core
ASP.NET Core

So, we get all the employee details as we specified in the DataStore class.

Now we can also create new actions, for example,  to return a single entity. Add a new action named GetEmployee, since this is also a Get, we decorate it with HttpGet attribute. The URl should be then “api/employees” i.e. the default one + the id of the employee that is to be fetched, [HttpGet("api/employees/{id}")], but since “api/employees” is the part of default route , we can skip that as it will automatically be appended to the action route. The id is the parameter passed via URI and it has to be the parameter to action as well to fetch the required employee with ID.

  1. [HttpGet("{id}")]  
  2. public JsonResult GetEmployee(int id)  
  3. {  
  4.   return new JsonResult(EmployeesDataStore.Current.Employees.FirstOrDefault(emp => emp.Id == id));  
  5. }  

In the above action method, we find that particular employee from the list of employee data store whose id matches with the passed id parameter. Now compile the project. Run the application and fire a GET request from postman, but with a different URI now i.e. http://localhost:2542/api/employees/1

ASP.NET Core

With http://localhost:2542/api/employees/2

ASP.NET Core

So, we get only one employee from the list of employees, and the id of the employee is 1 as passed through the URI. So Routing template matches the correct route to the action and then invokes the action.

Now imagine a scenario, where you fire a request with non-existing route or employee for e.g. http://localhost:2542/api/companies, we get the following 404 response i.e. Not Found, which is perfectly fine.

ASP.NET Core

If we remember from the previous implementation, we got 500 internal server errors. So, these codes are basically HTTP status codes that are, in this case, automatically returned by the framework.

And if we try to get and employee that does not exist for e.g. http://localhost:2542/api/employees/8, we get 200 OK results with null result data.


ASP.NET Core

The framework itself doesn't return a 404 just because our URI can be routed. But returning null is the incorrect result. So if the employee doesn’t exist we should also ideally get 404 responses from the code or API. We should return correct status codes in every case. We’ll cover status codes and a lot more in next article of the series. Stay tuned.

Conclusion

In this article, we learned about the MVC pattern and how conventional Web API and MVC is different from what we have in ASP.NET Core MVC. We started by knowing what MVC pattern is, Model-View-Controller. The Model takes care of the business logic of the application data. The View signifies the area that displays data, which, in case of an API, is typically in JSON format returned from APIs and the Controller handles the Communication between View and Model. This pattern enables us to write a code which is re-usable and testable. We learned to add MVC middleware and how we can use an HttpGet to get data from our API. We learned how routing takes care of request URIs and maps to our actions of the controller. We learned how to create an API from scratch and how to deal with entity objects and return resources. In the next article, we’ll cover topics like HTTP Status Codes, returning sub resources, serializer strings and content negotiation.

Source Code on Github
References
  • https://www.asp.net/core
  • https://www.pluralsight.com/courses/asp-dotnet-core-api-building-first

Up Next
    Ebook Download
    View all
    Learn
    View all