Click here to Skip to main content
15,867,488 members
Articles / Web Development / ASP.NET

Create API with ASP.NET Core (Day2): Creating API in ASP.NET Core

Rate me:
Please Sign up or sign in to vote.
4.98/5 (29 votes)
8 May 2017CPOL16 min read 39.3K   811   28   21
How to create API with ASP.NET Core

Table of Contents

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 learnt 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 detail how to return resources, data and how to talk to API via HTTP request in this article. We can use the same source code that we got at the completion of the 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, and for creating an application with user interface and that is used by end user, we used ASP.NET MVC. When we talk about it in terms of ASP.NET Core, we do not have a separate Web API framework now.

Image 1

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, Serializer Settings and Content Negotiation in ASP.NET Core API
  4. Create API with ASP.NET Core (Day 4): Understanding Resources in ASP.NET CORE API
  5. Create API with ASP.NET Core (Day 5): Inversion of Control and Dependency Injection in ASP.NET CORE API
  6. Create API with ASP.NET Core (Day 6): Getting Started with Entity Framework Core
  7. Create API with ASP.NET Core (Day 7): 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.

Image 2

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, the 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 it is 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.

Image 3

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 middle ware, but to proceed with that implementation, first add the AspNetCore.MVC nugget 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.

Image 4

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

Image 5

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.

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

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 handles the MVC related exception and sends the correct response. We can now also comment out the code that we introduced to raise the exception.

JavaScript
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
   loggerFactory.AddConsole();

   if (env.IsDevelopment())
   {
      app.UseDeveloperExceptionPage();
   }
      else
   {
      app.UseExceptionHandler();
   }

   app.UseMvc();

   //app.Run(async (context) =>
   //{
   //  throw new Exception("Test Dev Exception Page");
   //});

   //app.Run(async (context) =>
   //{
   //  await context.Response.WriteAsync("Hello World!");
   //});
}

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

Image 6

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

Image 7

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

Image 8

We got 404 exception, i.e., Not found status. It is obvious as we just added the MVC middleware but did not do anything 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 the 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 the 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.

Image 9

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

JavaScript
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EmployeeInfo.API.Controllers
{
    public class EmployeesInfoController : Controller
    {
    }
}

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.

JavaScript
public JsonResult GetEmployees()
{
    return new JsonResult();
}

Since we need to return the list of employees, 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.

JavaScript
public JsonResult GetEmployees()
{
    return new JsonResult(new List<object>()
    {
        new {employeeid = 01989, Name = "John Patrick"},
        new {employeeid = 01987, Name= "Michael"},
        new {employeeid = 01988, Name= "Akhil Mittal"}
    });
}

When it is required to consume HTTP service, 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.

Image 10

Install Postman to the Chrome Web browser app and open it.

Image 11

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 the following image:

Image 12

That means that the MVC Framework till now 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 maps 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:

JavaScript
app.UseMvc(config => {
        config.MapRoute(
        name: "Default",
        template: "{controller}/{action}/{id?}",
        defaults: new { controller = "Home", action = "Index" }
        );
      });

This is similar to what we used 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 traditional ways of routing more suitable for typical MVC application where view will 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.

Image 13

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 example, 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 example, api/employees Uri could be used to create an employee resource.

PUT and PATCH are used for update URIs, 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 complete update, i.e., all the fields coming in 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., 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 delete URIs, for example, api/employees/01989 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 to 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 does it works. Since we need to get the employees, we’ll use HttpGet attribute over the action. Place [HttpGet("api/employees")] over the action.

C#
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace EmployeeInfo.API.Controllers
{
  public class EmployeesInfoController : Controller
  {
    [HttpGet("api/employees")]
    public JsonResult GetEmployees()
    {
      return new JsonResult(new List<object>()
      {
        new {employeeid = 01989, Name = "John Patrick"},
        new {employeeid = 01987, Name= "Michael"},
        new {employeeid = 01988, Name= "Akhil Mittal"}
      });
    }
  }
}

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

Image 14

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?

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 our 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:

C#
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace EmployeeInfo.API.Controllers
{
  [Route("api/employees")]
  public class EmployeesInfoController : Controller
  {
    [HttpGet()]
    public JsonResult GetEmployees()
    {
      return new JsonResult(new List<object>()
      {
        new {employeeid = 01989, Name = "John Patrick"},
        new {employeeid = 01987, Name= "Michael"},
        new {employeeid = 01988, Name= "Akhil Mittal"}
      });
    }
  }
}

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.

Image 15

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.

Image 16

C#
EmployeeDto Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EmployeeInfo.API.Models
{
  public class EmployeeDto
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Designation { get; set; }
    public string Salary { get; set; }

    public int NumberOfCompaniesWorkedWith { get; set; }
  }
}

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 named Employees, i.e., a list of Employee DTO. And add some dummy data to it.

Image 17

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 an encouraged approach, but we are temporarily following it to understand the topic.

EmployeesDataStore.cs:

C#
using EmployeeInfo.API.Models;
using System.Collections.Generic;

namespace EmployeeInfo.API
{
  public class EmployeesDataStore
    {
    public static EmployeesDataStore Current { get; } = new EmployeesDataStore();
    public List<employeedto> Employees { get; set; }

    public EmployeesDataStore()
    {
      //Dummy data
      Employees = new List<employeedto>()
            {
                new EmployeeDto()
                {
                     Id = 1,
                     Name = "Akhil Mittal",
                     Designation = "Technical Manager",
                     Salary="$50000"
                },
                new EmployeeDto()
                {
                     Id = 2,
                     Name = "Keanu Reaves",
                     Designation = "Developer",
                     Salary="$20000"
                },
                 new EmployeeDto()
                {
                     Id = 3,
                     Name = "John Travolta",
                     Designation = "Senior Architect",
                     Salary="$70000"
                },
                  new EmployeeDto()
                {
                     Id = 4,
                     Name = "Brad Pitt",
                     Designation = "Program Manager",
                     Salary="$80000"
                },
                   new EmployeeDto()
                {
                     Id = 5,
                     Name = "Jason Statham",
                     Designation = "Delivery Head",
                     Salary="$90000"
                }
            };
    }
  }
}

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.

JavaScript
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace EmployeeInfo.API.Controllers
{
  [Route("api/employees")]
  public class EmployeesInfoController : Controller
  {
    [HttpGet()]
    public JsonResult GetEmployees()
    {
      return new JsonResult(EmployeesDataStore.Current.Employees);
    }
  }
}

Now run the application and again request the response from postman.

Image 18

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

Now we can also create new actions for e.g. 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.

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

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.

Image 19

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

Image 20

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.

Image 21

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 an employee that does not exist, for e.g., http://localhost:2542/api/employees/8, we get 200 OK results with null result data.

Image 22

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 response from the code or API. We should return correct status codes in every case. We’ll cover status codes and a lot more in the 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 display 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 learnt 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.

            << Previous Article                                                                                     Next Article >>

Source Code on Github

References

Other Series

My series of articles are listed below:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect https://codeteddy.com/
India India
Akhil Mittal is two times Microsoft MVP (Most Valuable Professional) firstly awarded in 2016 and continued in 2017 in Visual Studio and Technologies category, C# Corner MVP since 2013, Code Project MVP since 2014, a blogger, author and likes to write/read technical articles, blogs, and books. Akhil is a technical architect and loves to work on complex business problems and cutting-edge technologies. He has an experience of around 15 years in developing, designing, and architecting enterprises level applications primarily in Microsoft Technologies. He has diverse experience in working on cutting-edge technologies that include Microsoft Stack, AI, Machine Learning, and Cloud computing. Akhil is an MCP (Microsoft Certified Professional) in Web Applications and Dot Net Framework.
Visit Akhil Mittal’s personal blog CodeTeddy (CodeTeddy ) for some good and informative articles. Following are some tech certifications that Akhil cleared,
• AZ-304: Microsoft Azure Architect Design.
• AZ-303: Microsoft Azure Architect Technologies.
• AZ-900: Microsoft Azure Fundamentals.
• Microsoft MCTS (70-528) Certified Programmer.
• Microsoft MCTS (70-536) Certified Programmer.
• Microsoft MCTS (70-515) Certified Programmer.

LinkedIn: https://www.linkedin.com/in/akhilmittal/
This is a Collaborative Group

779 members

Comments and Discussions

 
GeneralMy vote of 5 Pin
D V L15-Jun-17 20:18
professionalD V L15-Jun-17 20:18 
GeneralRe: My vote of 5 Pin
Akhil Mittal15-Jun-17 22:44
professionalAkhil Mittal15-Jun-17 22:44 
GeneralMy vote of 5 Pin
MohitMittal9020-May-17 22:02
MohitMittal9020-May-17 22:02 
GeneralRe: My vote of 5 Pin
Akhil Mittal21-May-17 1:41
professionalAkhil Mittal21-May-17 1:41 
PraiseGreat ! Waiting for next part Pin
MohitMittal9020-May-17 21:44
MohitMittal9020-May-17 21:44 
GeneralRe: Great ! Waiting for next part Pin
Akhil Mittal21-May-17 1:41
professionalAkhil Mittal21-May-17 1:41 
GeneralMy vote of 5 Pin
RaviRanjanKr20-May-17 20:41
professionalRaviRanjanKr20-May-17 20:41 
GeneralRe: My vote of 5 Pin
Akhil Mittal21-May-17 1:40
professionalAkhil Mittal21-May-17 1:40 
PraiseKeeps getting better! Pin
Sung M Kim15-May-17 4:58
professionalSung M Kim15-May-17 4:58 
GeneralRe: Keeps getting better! Pin
Akhil Mittal15-May-17 17:44
professionalAkhil Mittal15-May-17 17:44 
QuestionAPI With Core Pin
Member 800608915-May-17 4:22
Member 800608915-May-17 4:22 
AnswerRe: API With Core Pin
Akhil Mittal15-May-17 17:44
professionalAkhil Mittal15-May-17 17:44 
PraiseGood Article! Pin
Sedney Fan13-May-17 22:22
Sedney Fan13-May-17 22:22 
GeneralRe: Good Article! Pin
Akhil Mittal16-Jul-18 1:05
professionalAkhil Mittal16-Jul-18 1:05 
PraiseMy vote of 5 Pin
Vikas Sharma11-May-17 0:16
professionalVikas Sharma11-May-17 0:16 
Very nice.
GeneralRe: My vote of 5 Pin
Akhil Mittal11-May-17 1:23
professionalAkhil Mittal11-May-17 1:23 
QuestionGreat! Waiting for the next part :-) Pin
dkurok9-May-17 23:15
dkurok9-May-17 23:15 
AnswerRe: Great! Waiting for the next part :-) Pin
Akhil Mittal10-May-17 5:45
professionalAkhil Mittal10-May-17 5:45 
GeneralRe: Great! Waiting for the next part :-) Pin
Semaphoree13-May-17 12:59
Semaphoree13-May-17 12:59 
GeneralMy vote of 5 Pin
udeep kansal8-May-17 22:59
professionaludeep kansal8-May-17 22:59 
GeneralRe: My vote of 5 Pin
Akhil Mittal8-May-17 23:01
professionalAkhil Mittal8-May-17 23:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.