Quantcast
Channel: ASP.Net Web API – Bit of Technology
Viewing all articles
Browse latest Browse all 37

Building ASP.Net Web API RESTful Service – Part 3

$
0
0

This is the third part of of Building ASP.Net Web API RESTful Service Series. The topics we’ll cover are:

Getting started with ASP.Net Web API

Now we are ready to start building our Web API, as I stated before we can use ASP.Net Web API with MVC projects, Web Forms, or as stand alone web service. In our case we will use an empty MVC 4 template, to do this right-click on solution “eLearning” Choose Add->New Project->Web->ASP.NET MVC 4 Web Application and name your Web API “Learning.Web”->Select Empty Template. Your solution will be as the below image:

eLearningSolution2

Before talking about Web API configuration and how we can build our URIs to consume the resources, we need to understand the relation between the HTTP verb and the resource we’ll consume, as example we will consider the “Course” domain model object as the resource, the below table lists the usage of HTTP verbs with “Course” resource.

Action HTTP Verb Relative URI
Get all courses GET /api/courses
Get single course GET /api/courses/id
Add new course POST /api/coursesNew course is sent in POST body
Update existing course PUT or PATCH /api/courses/idUpdated course is sent in POST body
Delete course DELETE /api/courses/id

Step 1: Configuring first route (Courses Route)

In order to configure this route, the MVC 4 empty template we have just used has by default a class named “WebApiConfig” inside the “App_Start” folder, this class is called at the application start event in “Global.asax” and it is responsible to configure routing for Web API, we’ll be visiting and modifying this class multiple times to configure our Web API routes.

By default there will be a route named “DefaultApi”, we need to delete this route and replace it with route below:


public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
	       config.Routes.MapHttpRoute(
               name: "Courses",
               routeTemplate: "api/courses/{id}",
               defaults: new { controller = "courses", id = RouteParameter.Optional }
           );
	}
     }

What we’ve done here is simple, we added new route named “Courses”, and mapped this route to a URI template “api/courses/{id}”, and assigned two default values to it which they are the name of controller it will use “Courses”, and set the “id” parameter to be optional. Now the relative URI in the form /api/courses or /api/courses/5 will be routed using this route. If we didn’t specify that id is optional then the URI /api/courses won’t be valid.

Step 2: Adding First Controller (Courses Controller)

Controller in Web API is a class that handles HTTP requests from the client, now we have to add a controller which will handle all HTTP verbs issued against URI /api/courses, to do this right-click on Controllers folder->Select Add->Name the controller “CoursesController” and choose “Empty API Controller” Template.

The controller we’ve added derives from “ApiController”, It is important to name the controller as we mentioned before “CoursesController” because Web API controller selection is implemented in a way which looks for all classes derives from “ApiController” then match the first part of the class name Courses with the defaults route controller property we defined in class “WebApiConfig”.

Step 3: Action Selection inside Controllers

We’ll start by adding support for the two GET actions we defined in the table above, getting all courses, and getting single course by id.

Action selecting in Web API controllers is smart; if we created two methods Get() and GetCourse(int id), then issued a GET request to the URL /api/courses/5
the method GetCourse(int id) will be selected and executed; because by convention its starts with “Get” and the URI contains an “id” segment in the path. The same applies for other HTTP verbs (POST, PUT, DELETE). Let’s implement this as the code below:


public class CoursesController : ApiController
    {
        public List<Course> Get()
        {
            ILearningRepository repository = new LearningRepository(new LearningContext());

            return repository.GetAllCourses().ToList();
        }

        public Course GetCourse(int id)
        {
            ILearningRepository repository = new LearningRepository(new LearningContext());

            return repository.GetCourse(id);
        }
     }

So if we made GET request to the URI http://localhost:{your_port}/api/courses the action Get() will be selected and executed and part of the response will be as below:

Note: I’m using JSON view plugin on Firefox to issue GET request and return data in JSON format.

[
    {
        "Id": 1,
        "Name": "History Teaching Methods 1",
        "Duration": 5,
        "Description": "The course will talk in depth about: History Teaching Methods 1",
        "CourseTutor": {
            "Courses": [ ],
            "Id": 1,
            "Email": "Ahmad.Joudeh@outlook.com",
            "UserName": "AhmadJoudeh",
            "Password": "EFZWOFEO",
            "FirstName": "Ahmad",
            "LastName": "Joudeh",
            "Gender": 0
        },
        "CourseSubject": {
            "Courses": [ ],
            "Id": 1,
            "Name": "History"
        },
        "Enrollments": [ ]
    },
    {
        "Id": 2,
        "Name": "History Teaching Methods 2",
        "Duration": 4,
        "Description": "The course will talk in depth about: History Teaching Methods 2",
        "CourseTutor": {
            "Courses": [ ],
            "Id": 1,
            "Email": "Ahmad.Joudeh@outlook.com",
            "UserName": "AhmadJoudeh",
            "Password": "EFZWOFEO",
            "FirstName": "Ahmad",
            "LastName": "Joudeh",
            "Gender": 0
        },
        "CourseSubject": {
            "Courses": [ ],
            "Id": 1,
            "Name": "History"
        },
        "Enrollments": [ ]
    }
]

Now if we try to issue another GET request to the URI http://localhost:{your_port}/api/courses/5 in order to select a single course, the action GetCourse(int id) will be selected and executed, but an exception will be thrown when trying to serialize the object graph we return from method GetCourse. the exception message will read “Self referencing loop detected for property ‘Course’ with type ‘Learning.Data.Entities.Course’. Path ‘Enrollments[0]‘.”. In other words this method is trying to return chain of related objects which they reference each other (Course>Enrollment>Course>Enrollment>etc…).

So what we have implemnted in “CoursesController” till this moment is insufficient, the below points lists what are the lacking parts:

  • Self referencing when returning chain of objects. This can be solved using a design pattern called the Model Factory.
  • We are returning all the fields from the domain model object and leaking sensitive information to the client, for example if you take a look on “Tutor” object you will notice that we are returning the “password” field which shouldn’t be leaked to API consumer. This can be solved using the Model Factory pattern.
  • Each resource returned in the response should be linked to a URI, this will simplify resources query for the client. This can be solved using the Model Factory pattern.
  • We should return HTTP status code when returning single resource, i.e if the resource was not found we should return 404 in response header, if it was found we should return 200 OK, etc…, this can be solved by returning HttpResponseMessage object.
  • Inside each method we are instantiating our repository, this operation is expensive as it includes opening connection to the database, we need to implement Dependency Injection pattern, this can be solved by using Ninject DI framework.
  • The format for JSON response objects are in Pascal Case i.e. “FirstName”, and most probably our API will be consumed in client using JavaScript, it is easier for JS developers to work with properties formatted in Camel Case “firstName”. this can be solved by configuring JSON formatters of the response.

So in the next post we’ll cover how to fix those flaws in our Web API.

Source code is available on GitHub.



Viewing all articles
Browse latest Browse all 37

Trending Articles