Building N-Tier RESTful API using ASP.NET Web API 2 (Part 1)

Tutorial Introduction

Hi everyone, and welcome in the first part of “Building N-Tier

RESTful API using ASP.NET Web API 2” Tutorial.
In this tutorial you’ll learn how to develop an API using ASP.NET Web API 2, N-Tier Architecture, and a lot of stuff that will help you to get started building your awesome API confidently

Tutorial Parts

  1. Build Your First API using Web API 2
  2. More About HTTP Protocol

Tutorial Pre-Requests

  • Strong knowledge of OOP and C#
  • Experience with Web Development
  • Experience with JavaScript
  • A little knowledge of AngularJS (To build client app at the end of the tutorial)

What you’ll learn in this tutorial

I’m actually planning a lot of stuff and want to make it a complete tutorial so

  • RESTful API architecture
  • ASP.NET Web API 2
  • N-Tier architecture
  • Dependency Injection
  • OData protocol
  • Build a client application with AngularJS and awesome Angular Material for the UI
  • And a lot more..

Source Code:

You can find the code for this tutorial in this GitHub Repository.

Part 1 – Build Your First API using Web API 2

API (Application Programming Interface) is an interface for building HTTP Web Service that can be used to retrieve, create or update data. ASP.NET WEB API is Microsoft’s Implementation of API that enables you to use the capabilities of the .NET Framework to develop a robust API. Web API is not like ASP.NET MVC some people think they’re the same but they aren’t, in ASP.NET MVC you’re building a Web Site you’ll render the html page and pass it directly to the client which in this case a web browser. In Web API you wont be building a website you wont be rendering html page to the client instead you’ll give it “Data” using whatever format JSON, XML, or whatever.

Q- But can’t i return a “Data” to the client using ASP.NET MVC there’s a JSON helper method for example that returns JSON and i also can return XML or whatever?

A- Of course you can but developing an API is not only by returning “Data” so let’s discuss the differences between both and clarify why you should choose Web API instead of ASP.NET MVC to build your API

1- Content Negotiation

In ASP.NET MVC usually you’re returning a View but if you want to return another data type it’s ok so let’s return a JSON

 public class NewsController : Controller
  {
    public ActionResult GetNews()
    {
       return Json(GetAllNews(), JsonRequestBehavior.AllowGet);
    }
  }

Now i’ve created an action to return some news in JSON format but what if a client wants XML format? Should i create an action for every data format (Ofc Not). Or should i create another ActionResult to return Xml and get a parameter in the action indicating whether to return Xml or Json? Or should i read the “Accept” request header and make some if .. else to return the appropriate data format? Before answering these questions let’s see how does Web API address this issue we face.

public class NewsController : ApiController
{
  public IHttpActionResult GetNews()
  {
    return Ok(GetAllNews());
  }
}

In Web Api you don’t specify the data format to return instead you’re more concerned about the response itself whether it’s succeeded, failed, unauthorized, or whatever. We’ll discuss these stuff later in the tutorial. And you’re not concerned about what’s the data format the user will get! instead you configure your API with the data formats you support! for example i want to support Xml and Json format. The request that wants Xml will get Xml response on the other hand if it wants Json it will get Json. Ofc this separation of concerns is a big win of ASP.NET Web API when developing an APIs.

2- OData support

Web API is supporting OData protocol that we’ll use later in our tutorial. It’s a very powerful protocol that allows you to write data queries in the query string that will be translated, executed and returning the data you’re expected as if you wrote a SQL query (Ofc with some limitations compared to SQL). As ASP.NET MVC is not designed for that it doesn’t

3- Based on REST Architecture

As Web API is made for designing RESTful APIs it’s by default supports that. For example routes are mapped by HTTP Verbs (GET, POST, PUT, ..etc) rather than Method Name (GetNews).

4- Authentication

In ASP.NET MVC usually you’re using cookies to place authentication tickets but what if your client was a native mobile app ??

And a lot more of differences and issues, with all the respect to ASP.NET MVC it’s a great platform i believe but great for what it’s great for (Building Websites) not APIs. So now let’s go through and create our first News API using ASP.NET Web API 2

Create First ASP.NET Web API

1- Open Visual Studio and Create New Project
2- Choose Web then ASP.NET Web Application. I’ll set NewsApi as the solution name i’ll use throughout this tutorial.
3- Choose the empty template and select Web API reference.
4- Hello Web API. as you can see everything seems normal and nothing different let’s discuss the project parts.

As you can see it seems like ASP.NET MVC project we’ve Web.config file that includes the configurations and package.config that includes our installed nuget packages

Global.asax that initialize our web application like in ASP.NET MVC (Will we need it? No) we’ll see how and why we’ll get rid of it.

WebApiConfig.cs Hmm that’s a new friend let’s see what it contains. But where’s the rest of files that’s created by default to our App_Start folder like BundleConfig.cs the answer here is (What’re you going to bundle?) there’s no scripts no css files it’s only an API that returns “Data”.

5- Exploring WebApiConfig.cs

This file is used to hold all the initial configuration to your API. Initially it includes the Routing Configurations. And if you look closer you’ll see a little difference between it and ASP.NET MVC. In ASP.NET MVC the route template is “{controller}/{action}/{id}” here it’s “api/{controller}/{id}”. Oh where is the action? how’s the routing engine will figure out what’s the correct action to map if all the routes going to the same url?. As we discussed earlier it will map them by HTTP Verb instead of Action Name and we shall see this later. Now let’s setup our environment.

6- Open Package Manager Console and type “Install-Package EntityFramework”

I’ll use Entity Framework Code First to create our database if you need some information about it i recommend you visit this website. Now let’s create our Model

Let’s go to Model folder and create 2 classes which are “Author” and “Article” as following

public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Article> Articles { get; set; }
}

public class Article
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public DateTime DatePosted { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

We’ll use these classes to initialize our Database now let’s create our DbContext and seed it with some data

public class NewsDbContext : DbContext
{
  public NewsDbContext()
  {
    Database.SetInitializer(new NewsDbInitializer());
  }
  public DbSet<Author> Authors { get; set; }
  public DbSet<Article> Articles { get; set;}
}

public class NewsDbInitializer : CreateDatabaseIfNotExists<NewsDbContext>
{
  protected override void Seed(NewsDbContext context)
  {
    List<Author> authors = new List<Author>();
    for (var c = 0; c < 100; c++)
    {
      Author author = new Author()
       {
         Name = "Author " + c,
         Articles = new List<Article>()
       };
      int numberOfArticles = new Random().Next(3, 10);
      for(var j = 0 ; j <= numberOfArticles ; j++)
      {
        author.Articles.Add(new Article()
         {
           Title = "New Article Title",
           Body = "New Article Body",
           DatePosted = DateTime.Now
         });
      }
      authors.Add(author);
    }
    context.Authors.AddRange(authors);
    base.Seed(context);
  }
}

Now i’ve created our NewsDbContext and NewsDbInitializer to initialize and seed our database with mock data. Now the database is ready so let’s create a controller that do some CRUD operations. But first we need to create View Models that’s responsible for transfering data from and to the client. Now create a folder and name it ViewModels and create 2 classes AuthorViewModel and ArticleViewModel as following

public class AuthorViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}
public class ArticleViewModel
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
    public DateTime DatePosted { get; set; }
    public int AuthorId { get; set; }
    public string AuthorName { get; set; }
}

Well great now let’s create AuthorsController in Controllers Folder as following

public class AuthorsController : ApiController
{
  public async Task<IHttpActionResult> Get()
  {
    using (NewsDbContext ctx = new NewsDbContext())
    {
      var authors = await ctx.Authors.Select(o => new AuthorViewModel()
        {
         Id = o.Id,
         Name = o.Name
        }).ToListAsync();
      return Ok(authors);
    }
  }
}

Notice that in Web API all controller classes inherits from ApiController unlike Controller in ASP.NET MVC and Actions returns IHttpActionResult instead of the abstract ActionResult class in ASP.NET MVC. Now i’ve created only 1 action method and i’ve named it Get (I’ll discuss why i’ve named it like that later in the next part of the tutorial) it’s responsible for getting a list of all authors in our database. But what’s return Ok(). Well in Web API you’re not concerned here with the data format the user will receive you’re concerned with the response itself so Ok() will return (200 Http Status Code) and i’ll explain what’s status codes and how can we use it in a great way. But what’s the data format will be returned ?. By default Web API supports 2 data formats which are (JSON and XML).

Now let’s use the great tool Postman to test our API you can use your favorite tool.

7- Getting authors data

Notice here the url is http://localhost:15300/api/authors there’s nothing to indicate that we want the Get Action we created. That’s because of the HTTP Verb Look at the left of the url you’ll find that the request is sent as “GET” request. ASP.NET Web API routing by default map the action method name to the equivalent HTTP Verb without any configurations from your side like mark the method with HttpGetAttribute That’s why i’ve named the method Get. Now let’s see how if i decided to get XML instead of JSON. I’ll write Accept header in the request and we should get the data in XML format.

8- Getting data in XML Format

Now it’s obvious. You configure the data formats you want to support (By Default: Xml and Json) and you shouldn’t worry about what will the client recieve.

Now let’s prepare our controller to do CRUD operations to Authors in the API. First we’ll need to create 2 more View Models which are CreateAuthorViewModel and EditAuthorViewModel

public class CreateAuthorViewModel
{
  [Required(AllowEmptyStrings = false)]
  public string Name { get; set; }
}

public class EditAuthorViewModel
{
  [Required]
  public int? Id { get; set; }
 
  [Required(AllowEmptyStrings = false)]
  public string Name { get; set; }
}

Then let’s prepare our AuthorsController

public class AuthorsController : ApiController
{
    public async Task<IHttpActionResult> Get()
    {
      using (NewsDbContext ctx = new NewsDbContext())
      {
        var authors = await ctx.Authors.Select(o => new AuthorViewModel()
          {
            Id = o.Id,
            Name = o.Name
          }).ToListAsync();
        return Ok(authors);
      }
    }
    
public async Task<IHttpActionResult> Get(int id)
{
    using (var ctx = new NewsDbContext())
    {
      var author = await ctx.Authors.FirstOrDefaultAsync(o => o.Id == id);
      if (author == null)
        return NotFound();
      
      var data = new AuthorViewModel()
        {
          Id = author.Id,
          Name = author.Name
        };
      return Ok(data);
     }
  }
  
  public async Task<IHttpActionResult> Post(CreateAuthorViewModel model)
  {
    if (!ModelState.IsValid)
      return BadRequest(ModelState);
    
    using (var ctx = new NewsDbContext())
    {
      var author = new Author()
        {
          Name = model.Name
        };
      
      ctx.Authors.Add(author);
      await ctx.SaveChangesAsync();

      var data = new AuthorViewModel()
        {
          Id = author.Id,
          Name =  author.Name
        };
      return Created(new Uri(Request.RequestUri +"api/authors" + data.Id), data);
    }
  }
  
  public async Task<IHttpActionResult> Put(EditAuthorViewModel model)
  {
    if(!ModelState.IsValid)
      return BadRequest(ModelState);
    
    using (var ctx = new NewsDbContext())
    {
      var author = new Author()
        {
          Id = model.Id.Value,
          Name = model.Name
        };
      
      ctx.Authors.Attach(author);
      ctx.Entry(author).State = EntityState.Modified;
      await ctx.SaveChangesAsync();
      return StatusCode(HttpStatusCode.NoContent);
    }
  }
  
  public async Task<IHttpActionResult> Delete(int id)
  {
    using (var ctx = new NewsDbContext())
    {
      var author = await ctx.Authors.FirstOrDefaultAsync(o => o.Id == id);
      if (author == null)
        return NotFound();
    
      ctx.Authors.Remove(author);
      await ctx.SaveChangesAsync();
      return StatusCode(HttpStatusCode.NoContent);
    }
  }
}

Now let’s test these end points then discuss them. First let’s create an Author and him “Ibrahim Abdel Kareem” then let’s get this author’s data and then let’s update it to be “Ibrahim Abdel Kareem (Hema)” and get it again and then we’ll remove it.
Note: in the following figures try to observe the HTTP Verbs i’ll use and the returned HTTP Status Codes as i’ll discuss it later.

9- Creating an author

Here i’ve used the HTTP Verb Post to create a new Author, i’ve passed the data i want in the request’s body in json format and i got HTTP Status Code (201) which refers to Created. You’ll notice in the Action Method i’ve passed a url to the Created helper method. I’ll discuss why i did this in the next post when i’m going to discuss REST Architecture in more details as well i’ll explain what’s HTTP Status Codes and why we should use them correctly.

10- Retrieving the author we’ve created

Now i sent a GET request to retrieve the author i’ve created. But wait how is the GET request getting a single object of a single author not like before a list of all authors. Yes that’s because of the overloaded Get Action method i’ve created that takes an id as parameter. If you looked at the Url you’ll see /104. This indicates i want the method with the id parameter and i’ve got an HTTP 200 Status code which refers to Ok with the data of the author i’m requesting in the response body

11- Create another author with empty data

Now i’m trying to create another author but i’m passing an empty name in the request body and here’s the data annotations comes to play. I’ve got an HTTP Status Code 400 which refers to Bad Request along with the errors in the response body.

12- Updating the author

Now i’ve sent a PUT request to update the author and i’ve got HTTP Status Code 204 which refers to No Content. As i’ve said this all will be very obvious to you in the next post. but so far it’s an indication of success let’s get more sure by retrieving the author again.

13- Retrieving the author we’ve updated

Notice now the name has been changed. Now let’s delete this author.

14- Deleting the author

Now i’ve sent a DELETE request with the id in the url and i’ve got HTTP Status Code 204 No Content which indicates the success of the operation. Let’s try to retrieve it.

15- Retrieving the deleted author

Oooops! We got HTTP Status Code 404 which refers to Not Found. Usually if you came from MVC background you’ll wonder isn’t 404 indicates that page not found. Yes you’re totally right but here we’re not dealing with pages we’re dealing with resources, That means the API couldn’t find the resource you’re requesting.

Now i’m done for this part of the tutorial. Next i’ll be discussing the REST Architecture.

Hope you enjoyed this part you can find the source code in Github by following this Url.

Advertisements

23 thoughts on “Building N-Tier RESTful API using ASP.NET Web API 2 (Part 1)

  1. Thank you very much, it’s very good, well written and helpful article, waiting the next parts I wish you have time to write about authenticating, authorizing, and securing .desktop clients in web API.

  2. greet blog well done ,thanks for sharing knowledge ,i worked with Api and find two greet nuget
    -first ,to consume any api you will need help for know how to deal with api ,it make your API more comfortable easy to use and helpfully and give good impression with customers .its called Microsoft ASP.NET Web API 2.2 Help Page 5.2.3 , you can add it to your solution from this link
    https://www.nuget.org/packages/Microsoft.AspNet.WebApi.HelpPage/5.2.3
    -second for testing api on easy way it called “WebApiTestClient ” ,you don’t have to write any addition code just add it and add button for testing on help page .you can add to your solution from this link
    https://www.nuget.org/packages/WebApiTestClient/
    – I hope you add on your plan with more explanation ,many thanks for greet article keep going

    • Thanks a lot mahmoud ^^ Well actually in the tutorial i’m focusing on hard-coding stuff rather than using helpers and that’s much better if you understood the concepts and how to do the right things you’ll be able to use these helpers easily 🙂 And ofc i’m planning writing test-cases and a lot of stuff 🙂

  3. Ibrahim: I was expecting “Dependency Injection”, “Javascript” and Angular stuff in this tutorial but article came to an end without these. As you demonstrated earlier that we will learn after this tutorial the mentioned stuff…………….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s