Vous êtes sur la page 1sur 126

http://bitoftech.

net/2013/11/25/detailed-tutorial-building-asp-net-web-apirestful-service/

Building the Database Model using Entity Framework


Code First
Well be using Entity Framework Code First approach where well define our model
objects using Plain Old CLR Objects POCO. Well be code centeric and start by writing
standard .NET classes which define the domain model objects that are suitable for our API.
Those POCO classes will be responsible to generate our eLearning database.
The eLearning database is simple, we want to be able to define and store Students, and
Tutors. As well we have to define and store Courses and Subjects. We need to allow
each Student to enroll in different Courses.
The image below shows the final result of the database schema, Im listing it early so it will
facilitate the understanding of the POCO classes well build now:

Step 1: Create a new empty Class Library Project


Well start by creating a new empty class library project which will be responsible of all data
management operations (Data Layer). Choose File->New Project->Windows->Class

Library and name your solution eLearning and your class library Learning.Data. You
can choose .NET framework 4 or 4.5.
Step 2: Install Entity framework using NuGet
We need to install Entity framework version 5 or 6 using NuGet package manager or NuGet
package console, the package well install is named EntityFramework. Our solution will
look as below after installing EntityFramework:

Step 3: Creating our Model


As we stated before, we do not have our eLearning database and we need to create it by
writing standard .NET classes that define the domain model objects.
Now add a new folder called Entities then add five classes called Subject, Course,
Tutor, Student, and Enrollment those classes contain just simple properties and will
shape our database:

1 public class Subject


2

public Subject()

Courses = new List<Course>();

7
8

public int Id { get; set; }

public string Name { get; set; }

1
0
1

public ICollection<Course> Courses;


}

1
1

public class Course

public Course()

Enrollments = new List<Enrollment>();

CourseTutor = new Tutor();

CourseSubject = new Subject();

1
6

public int Id { get; set; }

public string Name { get; set; }

public Double Duration { get; set; }

public string Description { get; set; }

8
1

public Tutor CourseTutor { get; set; }

public Subject CourseSubject { get; set; }

2
0
2

public ICollection<Enrollment> Enrollments { get; set; }


}

1
2

public class Tutor

public Tutor()

Courses = new List<Course>();

public int Id { get; set; }

public string Email { get; set; }

public string UserName { get; set; }

public string Password { get; set; }

public string FirstName { get; set; }

public string LastName { get; set; }

public Enums.Gender Gender { get; set; }

8
2
9

public ICollection<Course> Courses;


}

3
0

public class Student

public Student()

Enrollments = new List<Enrollment>();

3
3

public int Id { get; set; }

public string Email { get; set; }

public string UserName { get; set; }

public string Password { get; set; }

public string FirstName { get; set; }

public string LastName { get; set; }

public Enums.Gender Gender { get; set; }

public DateTime DateOfBirth { get; set; }

public DateTime? RegistrationDate { get; set; }

public DateTime? LastLoginDate { get; set; }

3
9
4

public ICollection<Enrollment> Enrollments { get; set; }


}

0
4

public class Enrollment

public Enrollment()

Student = new Student();

Course = new Course();

public int Id { get; set; }

public DateTime EnrollmentDate { get; set; }

public Student Student { get; set; }

public Course Course { get; set; }

6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6

5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5
6
6
6
7
6
8
6
9
7
0
7
1
7
2
7

3
7
4
7
5
7
6
7
7
7
8
7
9
8
0
8
1
8
2
8
3

As you noticed those classes do not derive from any base classes nor have any attributes,
having those standard classes give us more data access flexibility and allow us to focus on the
application needs without worrying about persistence implementation.
Entity framework Code First by default supports an approach called Convention over
Configuration for mapping your POCO classes to database objects (Tables, Table fields data
types, and FK Relations). I find this approach is useful in scenarios where you are building a
demo/simple applications. But in our case we need to override this conventions by providing
custom database mapping rules using Fluent API.
Step 4: Applying Custom Mapping Rules
Once we apply the custom mapping rules we will be able to define datatype for each column,
set null-ability, map FK relationships between tables, and specify PK and Identity columns.

To do this we need to create new folder named Mappers then add five classes which
derives from System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<T>
Classes are: CourseMapper, EnrollmentMapper, StudentMapper, SubjectMapper,
and TutorMapper.

class CourseMapper : EntityTypeConfiguration<Course>

public CourseMapper()

this.ToTable("Courses");

6
7

this.HasKey(c => c.Id);

this.Property(c =>

9 c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
10

this.Property(c => c.Id).IsRequired();

11
12

this.Property(c => c.Name).IsRequired();

13

this.Property(c => c.Name).HasMaxLength(255);

14
15

this.Property(c => c.Duration).IsRequired();

16
17

this.Property(c => c.Description).IsOptional();

18

this.Property(c => c.Description).HasMaxLength(1000);

19
20

this.HasRequired(c => c.CourseSubject).WithMany().Map(s => s.MapKey("SubjectID"));

21

this.HasRequired(c => c.CourseTutor).WithMany().Map(t => t.MapKey("TutorID"));

22
23
24

}
}

25
26

class EnrollmentMapper : EntityTypeConfiguration<Enrollment>

27

28

public EnrollmentMapper()

29

30

this.ToTable("Enrollments");

31
32

this.HasKey(e => e.Id);

33

this.Property(e =>

34 e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
35

this.Property(e => e.Id).IsRequired();

36
37

this.Property(e => e.EnrollmentDate).IsRequired();

38

this.Property(e => e.EnrollmentDate).HasColumnType("smalldatetime");

39
40

this.HasOptional(e => e.Student).WithMany(e => e.Enrollments).Map(s =>

41 s.MapKey("StudentID")).WillCascadeOnDelete(false);
42

this.HasOptional(e => e.Course).WithMany(e => e.Enrollments).Map(c =>

43 c.MapKey("CourseID")).WillCascadeOnDelete(false);
44
45

}
}

46
47

class StudentMapper : EntityTypeConfiguration<Student>

48

49

public StudentMapper()

50

51

this.ToTable("Students");

52
53

this.HasKey(s => s.Id);

54

this.Property(s =>

55 s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
56
57

this.Property(s => s.Id).IsRequired();

58

this.Property(s => s.Email).IsRequired();

59

this.Property(s => s.Email).HasMaxLength(255);

60

this.Property(s => s.Email).IsUnicode(false);

61
62

this.Property(s => s.UserName).IsRequired();

63

this.Property(s => s.UserName).HasMaxLength(50);

64

this.Property(s => s.UserName).IsUnicode(false);

65
66

this.Property(s => s.Password).IsRequired();

67

this.Property(s => s.Password).HasMaxLength(255);

68
69

this.Property(s => s.FirstName).IsRequired();

70

this.Property(s => s.FirstName).HasMaxLength(50);

71
72

this.Property(s => s.LastName).IsRequired();

73

this.Property(s => s.LastName).HasMaxLength(50);

74
75

this.Property(s => s.Gender).IsOptional();

76
77

this.Property(s => s.DateOfBirth).IsRequired();

78

this.Property(s => s.DateOfBirth).HasColumnType("smalldatetime");

79
80

this.Property(s => s.RegistrationDate).IsOptional();

81

this.Property(s => s.RegistrationDate).HasColumnType("smalldatetime");

82
83

this.Property(s => s.LastLoginDate).IsOptional();

84

this.Property(s => s.LastLoginDate).HasColumnType("smalldatetime");

85
86
87

}
}

88
89

class SubjectMapper : EntityTypeConfiguration<Subject>

90

91

public SubjectMapper()

92

93

this.ToTable("Subjects");

94
95

this.HasKey(s => s.Id);

96

this.Property(s =>

97 s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
98

this.Property(s => s.Id).IsRequired();

99
10

this.Property(s => s.Name).IsRequired();

this.Property(s => s.Name).HasMaxLength(255);

10
1
10

}
}

2
10
3
10
4
10

class TutorMapper : EntityTypeConfiguration<Tutor>


{
public TutorMapper()
{
this.ToTable("Tutors");

5
10
6

this.HasKey(s => s.Id);


this.Property(s =>

10 s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
7

this.Property(s => s.Id).IsRequired();

10
8
10
9

this.Property(s => s.Email).IsRequired();


this.Property(s => s.Email).HasMaxLength(255);
this.Property(s => s.Email).IsUnicode(false);

11
0
11
1

this.Property(s => s.UserName).IsRequired();


this.Property(s => s.UserName).HasMaxLength(50);
this.Property(s => s.UserName).IsUnicode(false);

11
2

this.Property(s => s.Password).IsRequired();

11

this.Property(s => s.Password).HasMaxLength(255);

3
11

this.Property(s => s.FirstName).IsRequired();

this.Property(s => s.FirstName).HasMaxLength(50);

11
5

this.Property(s => s.LastName).IsRequired();

11

this.Property(s => s.LastName).HasMaxLength(50);

6
11

this.Property(s => s.Gender).IsOptional();

7
11
8
11
9
12
0
12
1
12
2
12
3
12
4
12
5
12
6
12
7
12

}
}

8
12
9

By looking at the code above you will notice that we are configuring each POCO class
property (Datatype, Null-ability, PK and identity columns, and FK relations). Those
configuration will be reflected on the database tables we are building. For more details about
mapping/configuring fluent API you can visit thislink.
The relationships between eLearning database tables are simple and described as the below:

Each Course has a Subject.

Each Tutor can tech multiple Courses.

Each Student can enroll in multiple Courses. So well have Many-to-Many table
to persist the relation called Enrollment.

Step 5: Creating Context Class to Handle Database Persistence


Now we need to add new class named LearningContext which derives from class
System.Data.Entity.DbContext:

1 public class LearningContext : DbContext


2
3

{
public LearningContext() :

4
5

base("eLearningConnection")
{

Configuration.ProxyCreationEnabled = false;

Configuration.LazyLoadingEnabled = false;

8
9

Database.SetInitializer(new MigrateDatabaseToLatestVersion<LearningContext,

1 LearningContextMigrationConfiguration>());
0

1
1

public DbSet<Course> Courses { get; set; }

public DbSet<Enrollment> Enrollments { get; set; }

public DbSet<Student> Students { get; set; }

public DbSet<Subject> Subjects { get; set; }

public DbSet<Tutor> Tutors { get; set; }

1
4

protected override void OnModelCreating(DbModelBuilder modelBuilder)

modelBuilder.Configurations.Add(new StudentMapper());

modelBuilder.Configurations.Add(new SubjectMapper());

modelBuilder.Configurations.Add(new TutorMapper());

modelBuilder.Configurations.Add(new CourseMapper());

modelBuilder.Configurations.Add(new EnrollmentMapper());

1
8

base.OnModelCreating(modelBuilder);

1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2

}
}

7
2
8

The LearningContext class is responsible for three tasks which they are:
1. Exposing our POCO classes as public DbSet properties, this means that every POCO
class is transferred to a database table.
2. Overriding OnModelCreating procedure which is used to apply custom mapping
rules for each POCO class by adding the new configurations to
the DbModelBuilder configurations.
3. In LearningContext class constructor we have implemented two things:

Disabled the ProxyCreationEnabled and LazyLoadingEnabled properties which


they are enabled by default. The Lazy Loading property enables loading the subobjects of model up front, in our case we want to load them on demand. The Proxy
Creation property is used in conjugation with Lazy Loading property, so if is set to
false the LearningContext wont load sub-objects unless Include method is called.

Configured the initialization and migration strategy of the database to migrate to latest
version if a model has changed (i.e. new property has been added). To implement this
we need to add new class called LearningContextMigrationConfiguration which
derives from class
System.Data.Entity.Migrations.DbMigrationsConfiguration<TContext>. The code
listing as below:

1 class LearningContextMigrationConfiguration : DbMigrationsConfiguration<LearningContext>


2

public LearningContextMigrationConfiguration()

this.AutomaticMigrationsEnabled = true;

this.AutomaticMigrationDataLossAllowed = true;

7
8
9
1
0
1

1
1 #if DEBUG
2 protected override void Seed(LearningContext context)
1 {
3 new LearningDataSeeder(context).Seed();
1 }
4 #endif
1
5

1
6
1
7

The LearningContextMigrationConfiguration class is responsible for two tasks which they


are:
1. In the constructor of the class we set the property AutomaticMigrationsEnabled to
true which means that we need EF to handle the automatic migration for us without
caring about DB Versioning. As well we set the
property AutomaticMigrationDataLossAllowed to true, this is dangerous to set in
production environment. If it was set to false an exception will be thrown if data loss
may occur as part of an automatic migration, but for our series it is fine to keep it to
true.
2. Overriding the Seed procedure which is used to seed our database with initial data,
this procedure gets called every time our application starts, Ive created a class called
LearningDataSeeder which responsible to seed the database, I wont list it is code
here but you can browse it on GitHub or by downloading the source code for the API.

Till this point weve implemented all the code needed to configure and create our eLearning
database depending on model objects weve defined, we can stop at this point and consider
our data layer completed, but we want to enhance it more and implement Repository
Pattern which facilitates data access and manipulation once we start building the Web API.
So in the next post well implement the Repository Pattern for our data access layer.

Applying the Repository Pattern for the Data Access


Layer
Applying Repository Pattern is useful to isolate domain objects from the details of database
access layer. It will act as an abstraction layer over the mapping layer where query
constructions and database objects manipulation take place. As well the Repository will act
like in-memory domain object collection where objects can be added or removed from the
Repository as they are removed from a simple collection of objects, moreover the Repository
will be responsible to execute the appropriate operations behind the scenes.
Before we dig into the Repository implementation lets list the use cases needed to be
implemented in our Web API, this for sure will help us in building the right Repository
methods and operations:

Listing all available subjects, and listing single subject by querying ID.

Listing all available courses including the sub-models (Subject, and Tutor).

Getting single course by querying ID including the sub-models(Subject, Tutor, and


Enrolled Students)

Listing all available students including all sub-models (Enrolled in Courses, Course
Subject, and Tutor)

Get summary of all available students.

List all enrolled students in specific course by querying course ID.

List all classes for a certain student by querying Username.

Get certain student by querying Username.

Authenticate students by validating Username and Password.

Enroll an authenticated student in a course.

CRUD operations for Students.

CRUD operations for Courses.

Building the Repository Pattern


We need to add new Interface named ILearningRepository to implement all the use cases
listed above:

1 public interface ILearningRepository


2

IQueryable<Subject> GetAllSubjects();

Subject GetSubject(int subjectId);

5
6

IQueryable<Course> GetCoursesBySubject(int subjectId);

7
8

IQueryable<Course> GetAllCourses();

Course GetCourse(int courseId, bool includeEnrollments = true);

bool CourseExists(int courseId);

0
1

IQueryable<Student> GetAllStudentsWithEnrollments();

IQueryable<Student> GetAllStudentsSummary();

1
2

IQueryable<Student> GetEnrolledStudentsInCourse(int courseId);

Student GetStudentEnrollments(string userName);

Student GetStudent(string userName);

Tutor GetTutor(int tutorId);

1
5

bool LoginStudent(string userName, string password);

1
6

bool Insert(Student student);

bool Update(Student originalStudent, Student updatedStudent);

bool DeleteStudent(int id);

1
8

int EnrollStudentInCourse(int studentId, int courseId, Enrollment enrollment);

1
9

bool Insert(Course course);

bool Update(Course originalCourse, Course updatedCourse);

bool DeleteCourse(int id);

2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0

bool SaveAll();
}

3
1
3
2
3
3
3
4

The methods in the interface above covers all the operations needed in our Web API, note
how we are returning IQueryable<T> for any method returns a collection of objects, this will
facilitate the pagination, sorting, and results ordering in our Web API because IQueryable will
give us deferred execution and fully support for LINQ-to-SQL. In other words IQueryable
result will save us from returning too many unwanted rows from the database.
Now we need to add new class called LearningRepository which will implement the
interface ILearningRepository. Ill list partial implementation of the class here. Well be
able to see the full implementation by browsing the code on GitHub or by downloading the
source.

1 public class LearningRepository : ILearningRepository


2

private LearningContext _ctx;

public LearningRepository(LearningContext ctx)

6
7

_ctx = ctx;
}

8
9

public IQueryable<Subject> GetAllSubjects()

0
1

return _ctx.Subjects.AsQueryable();
}

1
1
2
1
3
1

/*Rest of methods implementation goes here....*/


}

4
1
5

You can notice that the constructor of the class LearningRepository accepts the database
context object LearningContext and there is a private member _ctx which is used to
interact with all DbSet objects without instantiating it. That design pattern is called
Dependency Injection, in simple words it means that objects do not create other objects on
which they rely to do their work. Instead, they get the objects that they need from an outside
source.
So in our situation the class LearningRepository depends on class LearningContext, but
it wont create an instance from it to complete its work, instead we will inject this object to it
using an external DI framework called Ninject. Well cover this deeply in the coming parts. If
you are new to Dependency Injection design pattern, I recommend you to read my
previous blog post about it.
Until this point our data access layer is complete and ready to be used with our Web API, so
lets jump to the next post where well start working on Web API.

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:

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 well
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, well 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:

1
2 public static class WebApiConfig
3

public static void Register(HttpConfiguration config)

config.Routes.MapHttpRoute(

name: "Courses",

routeTemplate: "api/courses/{id}",

defaults: new { controller = "courses", id = RouteParameter.Optional }

);

0
1

}
}

What weve 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/coursesor /api/courses/5 will be routed using this
route. If we didnt specify that id is optional then the URI /api/courses wont 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 weve 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


Well 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). Lets implement this as the code below:

public class CoursesController : ApiController

public List<Course> Get()

ILearningRepository repository = new LearningRepository(new LearningContext());

6
7

return repository.GetAllCourses().ToList();

9
1

public Course GetCourse(int id)

ILearningRepository repository = new LearningRepository(new LearningContext());

1
1

return repository.GetCourse(id);

2
1
3
1
4
1

}
}

5
1
6

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: Im using JSON view plugin on Firefox to issue GET request and return data in JSON
format.

1 [{
2

"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": []

1 },
6 {
1

"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": []

2 }]
7
2
8
2
9
3
0
3
1
3

2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4

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 theModel 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 shouldnt 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 well cover how to fix those flaws in our Web API.

Implement Model Factory, Dependency Injection and


Configuring Formatters
In the previous post we have highlighted the flaws in current implementation of Courses
controller, in this post well be fixing those flaws.

Configuring Formatters
Web API provides media-type formatters for both JSON and XML. The framework inserts
these formatters into the pipeline by default. Clients can request either JSON or XML in the
Accept header of the HTTP request. In order to configure the JSON formatter we need to
implement the code below in class WebApiConfig:

public static class WebApiConfig


1
{
2
public static void Register(HttpConfiguration config)
3
{
4
5
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
6
jsonFormatter.SerializerSettings.ContractResolver = new
7
CamelCasePropertyNamesContractResolver();
8
}
9
}

What we did here that we looked at the built in formatters of type JSON, then we changed the
contract resolver of the serialization settings to use Camel Case resolver. Now all JSON
objects properties return in camel case.
Implement Dependency Injection using Ninject
If Dependency Injection concept is new to you, I recommend to read my previous post about
it.
Now to prepare our code for dependency injection we need to add new Base API controller
class named BaseApiController to folder Controllers. This class will derive from
APIController class and its constructor accepts the Repository Interface
ILearningRepository as parameter, were planing to implement
DI Constructor Injection Pattern. The code will look as below:

1
2
3
4
5 public class BaseApiController : ApiController
6

private ILearningRepository _repo;

8
9

public BaseApiController(ILearningRepository repo)

_repo = repo;

1
1

protected ILearningRepository TheRepository

get

return _repo;

1
5

}
}

1
6
1
7

Now our CoursesController will derive from the BaseApiController, we need to use now
Ninject as DI framework to do the heavy lifting for us and resolve the dependencies between
our components, to install Ninject use NuGet package Manager and install the following
packages:

Ninject

Ninject.Web.Common

WebApiContrib.IoC.Ninject

Update (2014-04-21) Thanks to Thando Toto and Francesco to point out the issue related for
no generating the file NinjectWebCommon by default, this is due some changes done on
Ninject packages used here, so in order to follow along with dependency injection part we
need to install the same assemblies with the right version used in this tutorial, so open NuGet
Package Manager Console (View -> Other Windows -> Package Manager Console) and
install the following packages along the right version used in this tutorial:

Install-Package Ninject -Version 3.0.1.10

Install-Package Ninject.Web.Common -Version 3.0.0.7

Install-Package WebApiContrib.IoC.Ninject -Version 0.9.3

After we install those package successfully a new file named NinjectWebCommon is added
to the App_Start folder, this file is responsible of the heavy lifting to configure the
dependencies in our project, now we need to specify the dependencies between our
components. As you remember in this post, when we created the LearningRepository its
constructor accepts the database context object LearningContext so the
LearningRepository class depends on the database context to work, we need register this in
Ninject Kernel.
So to configure Web API to use DI we need to add the following code to the class
NinjectWebCommon:

1 public static class NinjectWebCommon


2

3
4

private static IKernel CreateKernel()

5
6
7
8
9
1
0

var kernel = new StandardKernel();

kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);

kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

2
1

//Suport WebAPI Injection

GlobalConfiguration.Configuration.DependencyResolver = new

1 WebApiContrib.IoC.Ninject.NinjectResolver(kernel);
4
1

RegisterServices(kernel);

return kernel;

6
1

private static void RegisterServices(IKernel kernel)

kernel.Bind<LearningContext>().To<LearningContext>().InRequestScope();

kernel.Bind<ILearningRepository>().To<LearningRepository>().InRequestScope();

1
9

}
}

2
0
2
1
2
2

As you notice we are configuring Ninject to have a single instance of database context object
shared by all objects created via the kernel for that HTTP request. This is good technique for

sharing objects that are expensive to create. you can read more about Ninject Object
Scopes here.
Implement the Model Factory Pattern
The Model Factory Pattern will help us in shaping and controlling the response returned to
the client, so what we will do here is to create a simplified model for each domain object
model (entity) we have in the database. i.e. Course entity will map to CourseModel,
Tutor entity will map to TutorModel taking in consideration the relations between
models (Each course is taught by a Tutor and related to a Subject) etc
To implement this we need to add new folder named Models and add four classes
named SubjectModel, TutorModel, CourseModel, and EnrollmentModel. Those are
only simple POCO classes which will be used to return the data to the client, the code for
classes will be as below:

1 public class SubjectModel


2

public int Id { get; set; }

public string Name { get; set; }

6
7

public class TutorModel

public int Id { get; set; }

public string Email { get; set; }

public string UserName { get; set; }

public string FirstName { get; set; }

public string LastName { get; set; }

public Data.Enums.Gender Gender { get; set; }

2
1

3
1

public class CourseModel

public int Id { get; set; }

public string Url { get; set; }

public string Name { get; set; }

public double Duration { get; set; }

public string Description { get; set; }

public TutorModel Tutor { get; set; }

public SubjectModel Subject { get; set; }

8
1

9
2

public class EnrollmentModel

public DateTime EnrollmentDate { get; set; }

public CourseModel Course { get; set; }

2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9

3
0
3
1
3
2
3
3
3
4

Now we need to use those classes to create the response for the client, we need a single class
which is responsible for creating those models, so well add a class named ModelFactory
as the code below:

public class ModelFactory

public ModelFactory()

5
6

7
8

public CourseModel Create(Course course)

return new CourseModel()

Id = course.Id,

Name = course.Name,

Duration = course.Duration,

Description = course.Description,

Tutor = Create(course.CourseTutor),

Subject = Create(course.CourseSubject)

1
4

};
}

1
5

public TutorModel Create(Tutor tutor)

return new TutorModel()

Id = tutor.Id,

Email = tutor.Email,

UserName = tutor.UserName,

FirstName = tutor.FirstName,

LastName = tutor.LastName,

Gender = tutor.Gender

0
2

};
}

1
2

public SubjectModel Create(Subject subject)

return new SubjectModel()

Id = subject.Id,

Name = subject.Name

2
5

};
}

2
6

public EnrollmentModel Create(Enrollment enrollment)

return new EnrollmentModel()

EnrollmentDate = enrollment.EnrollmentDate,

Course = Create(enrollment.Course)

};

3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4

}
}

6
4
7
4
8
4
9
5
0
5
1

What weve done above is simple, weve overloaded the function named Create, so it
accepts domain object input i.e. Course and returns a new model of type CourseModel.
Notice how we can control the object graph and the chaining of objects and sub-objects i.e
(CourseModel -> TutorModel, and CourseModel -> SubjectModel).
By doing this weve fixed two important flaws we have identified in the previous post which
they are:

Self referencing when returning chain ob objects.

Controlling the fields returned to the client. (i.e. TutorModel is not returning the
password fields in the response).

Using the Model Factory in CoursesController and coming controllers well talk about is
fairly simple, thanks for the BaseApiController where all controllers will derive from it.
Open BaseApiController and add the code below:

public class BaseApiController : ApiController

3
4

private ModelFactory _modelFactory;

5
6
7
8
protected ModelFactory TheModelFactory
9
{
1
get
0
{
1
if (_modelFactory == null)
1
{
1
_modelFactory = new ModelFactory();
2
}
1
return _modelFactory;
3
}
1
}
4
}
1
5
1
6

What we done here is adding read only property which is responsible to create an instance of
the model factory class.
Before introducing changes to the CoursesController we need to fix the last two flaws in
the previous implementation which they are:

Link each resource returned to a URI.

Returning HTTP status codes when returning single resource.

Fix the flaw in Linking each resource returned to a URI:


Returning URI for each resource is simple, thanks to the Model Factory pattern we
implemented, so for example if we want to add URI to identify Course resource we need to
do the following:

1. Pass an instance of HttpRequestMessage to the ModelFactory constructor in


order to create object of type System.Web.Http.Routing.UrlHelper which is
responsible to formulate the URI link for this resource based on the Route Name we
configured in class WebApiConfig.
2. Pass Request object of type System.Net.Http.HttpRequestMessage in class
BaseApiController to ModelFactory constructor.
3. Add new property named URL to the CourseModel which will contain the URI
for this resource.
Code listing as the below respecting points sequence:

1 public class ModelFactory


2

private System.Web.Http.Routing.UrlHelper _UrlHelper;

4
5

public ModelFactory(HttpRequestMessage request)

_UrlHelper = new System.Web.Http.Routing.UrlHelper(request);

8
9

}
}

1 public class BaseApiController : ApiController


2
3

{
private ModelFactory _modelFactory;

4
5

protected ModelFactory TheModelFactory

7
8
9
1
get
0
{
1
if (_modelFactory == null)
1
{
1
_modelFactory = new ModelFactory(Request);
2
}
1
return _modelFactory;
3
}
1
}
4
}
1
5
1
6

1 public class ModelFactory


2

public CourseModel Create(Course course)

return new CourseModel()

Url = _UrlHelper.Link("Courses", new { id = course.Id }),

Id = course.Id,

/*Other CourseModel properties remain the same*/

};

0
1
1

}
}

1
2

There is a nice plural sight learning course produced by Shawn Wildermuth which discuss
deeply this Model Factory Pattern. I recommend watching this course.
Fix the flaw in returning HTTP status codes when returning single resource
Web API framework contains class named HttpResponseMessage which can be used to
return HTTP status code and data if needed, it is a good practice to return
HttpResponseMessage objects because it gives us the flexibility to set response code and
actual content, you will notice in the code below that well be returning object of type
HttpResponseMessage for action GetCourse(int id) instead of returning the
actualCourse domain object.
In the code listing below well implement all the fixes weve discussed:

1 public class CoursesController : BaseApiController


2
3

{
public CoursesController(ILearningRepository repo)

: base(repo)

7
8

public IEnumerable<CourseModel> Get()

IQueryable<Course> query;

0
1

query = TheRepository.GetAllCourses();

1
1

var results = query

.ToList()

.Select(s => TheModelFactory.Create(s));

3
1

return results;

1
5

public HttpResponseMessage GetCourse(int id)

try

var course = TheRepository.GetCourse(id);

if (course != null)

return Request.CreateResponse(HttpStatusCode.OK,

9 TheModelFactory.Create(course));
2

else

return Request.CreateResponse(HttpStatusCode.NotFound);

2
2

catch (Exception ex)

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

5
2
6
2
7
2
8
2
9

}
}

3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
3
9
4
0
4
1

Weve introduced multiple changes to CoursesController which they are:

Injected the ILearningRepository inside CoursesController constructor.

Using the model factory to create CourseModel and sub models TutorModel and
SubjectModel.

Returning HTTP status codes for action GetCourse(int id), so if the course was not
found well return 404, in case of an exception well return 400 (Bad request) along

with the exception message, and if the course is found well return 200 (OK) along
with a serialized representation of CourseModel object found.
To test the new changes lets issue a GET request the URI http://localhost:
{your_port}/api/courses, and notice how each resource returned has a URL property, as well
we have shaped the response returned and controlled the object graph to overcome circular
reference serialization issue.

1 [{
2

"id": 1,

"url": "http://localhost:8323/api/courses/1",

"name": "History Teaching Methods 1",

"duration": 5,

"description": "The course will talk in depth about: History Teaching Methods 1",

"tutor": {

"id": 1,

"email": "Ahmad.Joudeh@outlook.com",

"userName": "AhmadJoudeh",

"firstName": "Ahmad",

"lastName": "Joudeh",

"gender": 0

},

"subject": {

"id": 1,

"name": "History"

4 },
1 {
5

"id": 2,

"url": "http://localhost:8323/api/courses/2",

"name": "History Teaching Methods 2",

"duration": 4,

"description": "The course will talk in depth about: History Teaching Methods 2",

"tutor": {

"id": 1,

"email": "Ahmad.Joudeh@outlook.com",

"userName": "AhmadJoudeh",

"firstName": "Ahmad",

"lastName": "Joudeh",

"gender": 0

},

"subject": {

"id": 1,

"name": "History"

3
2 }]
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3

3
3
4
3
5
3
6
3
7
3
8

So in the next post well cover how to implement the HTTP verbs (POST,PUT, and
DELETE).

Implement HTTP actions POST, PUT, and DELETE In


Web API
In this post well continue implementing the other HTTP actions for CoursesController,
then discuss briefly what well implement in StudentsController.
Create new Course using HTTP Post action
Well add new method named Post(CourseModel courseModel) to CoursesController as
the implementation below:

1 public HttpResponseMessage Post([FromBody] CourseModel courseModel)


2
3

{
try

var entity = TheModelFactory.Parse(courseModel);

6
7

if (entity == null) Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not

8 read subject/tutor from body");


9
1

if (TheRepository.Insert(entity) && TheRepository.SaveAll())

return Request.CreateResponse(HttpStatusCode.Created,

1 TheModelFactory.Create(entity));
1

else

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not save to

1 the database.");
4

catch (Exception ex)

6
1

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

7
1
8
1
9
2
0
2
1
2
2
2

}
}

In the above implementation weve to note four things:

Method named is Post, so the clients needs to issue HTTP Post request.

The method accepts parameter of type CourseModel, in Web API parameters with
complex types are deserialized from the request body. So the client has to send a
serialized representation of a CourseModel object in JSON format.

Weve returned proper HttpResponseMessange for all possible scenarios that might
happen when we execute this operation. In case the resource is created successfully,
server should return HTTP response 201(Resource Created) along with the resource
created. It is very important to return the resource created in response message
because it will contain CourseId generated at the server.

Weve introduced method named Parse in ModelFactory class which is


responsible to parse the CourseModel back to the Course domain model object
which can be added to our repository. You can use GitHub to browse the latest version
of ModelFactory and BaseApiController classes in order to check the changes
introduced to apply Parse function.

To test this we need to open fiddler and choose the Composer tab, well issue a POST request
to the URI:http://localhost:{your_port}/api/courses/ The request will look as the image
below:

In this HTTP POST request we need to note the following:

The content-type header is set to application/json because we are sending JSON


data in request body.

The accept header is set to application/json because we are returning response in


JSON format.

The request body contains deserialized JSON data of the complex CourseModel, as
we mentioned before, each course has a tutor and related to subject, so sending the Ids
for subject and tutor is enough because the TheModelFactory.Parse function is
responsible to retrieve those objects from database and build valid domain object
model which can be used with our repository.

If this POST request executed successfully at the server, and the a new course is created well
receive status code 201 (Resource Created) in response header along with the new course
created on the server in response body. You can check the image blow:

Update existing Course using HTTP PUT action


Well add new method named Put(int Id, CourseModel courseModel) to
CoursesController, as the implementation below:

1 [HttpPatch]
2

[HttpPut]

public HttpResponseMessage Put(int id, [FromBody] CourseModel courseModel)

try

7
8

var updatedCourse = TheModelFactory.Parse(courseModel);

9
1

if (updatedCourse == null) Request.CreateErrorResponse(HttpStatusCode.BadRequest,

0 "Could not read subject/tutor from body");


1
1

var originalCourse = TheRepository.GetCourse(id, false);

1
2

if (originalCourse == null || originalCourse.Id != id)

return Request.CreateResponse(HttpStatusCode.NotModified, "Course is not found");

else

updatedCourse.Id = id;

6
1

if (TheRepository.Update(originalCourse, updatedCourse) && TheRepository.SaveAll())

return Request.CreateResponse(HttpStatusCode.OK,

8 TheModelFactory.Create(updatedCourse));
1

else

return Request.CreateResponse(HttpStatusCode.NotModified);

1
2

catch (Exception ex)

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

2
4
2
5
2
6
2
7
2
8
2
9

}
}

3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7

In the above implementation weve to note the below:

Method named PUT, so the clients needs to issue HTTP PUT request, but weve
added HttpPatch attribute to the Put method, so client can issue PUT or PATCH
request and both will be executed using Put method. The difference between Put and
Patch that if we want to update all fields of the CourseModel we need to use PUT, if
we want to update partial fields we need to use PATCH, in our implementation we do
not need to distinguish between those two actions.

Put method accepts two parameters, the Id of the updated resource which is set in
URI, and theupdated CourseModel which represents complex type deserialized in
the request body.

Weve returned proper HttpResponseMessange for all possible scenarios that might
happen when we execute this operation. In case the resource is updated successfully,
server should return HTTP response 200 (OK) along with the resource created. If the
resource is not modified the server should return HTTP response 304 (Not modified).

To test this we need to use fiddler and choose the Composer tab, well issue a PUT request to
the URI: http://localhost:{your_port}/api/courses/33 The request will look as the image
below:

In this HTTP PUT request we need to note the following:

The content-type header is set to application/json because we are sending JSON


data in request body.

The accept header is set to application/json because we are returning response in


JSON format.

The request body contains deserialized JSON data of the updated CourseModel.

If this PUT request executed successfully at the server, and the course is updated well
receive status code 200 (OK) in response header along with the updated course on the server
in response body.
Delete Course using HTTP DELETE action
Well add new method named Delete(int Id) to CoursesController, as the implementation
below:

1 public HttpResponseMessage Delete(int id)


2

try

var course = TheRepository.GetCourse(id);

6
7

if (course == null)

9
1

return Request.CreateResponse(HttpStatusCode.NotFound);
}

0
1

if (course.Enrollments.Count > 0)

return Request.CreateResponse(HttpStatusCode.BadRequest, "Can not delete course,

2 students has enrollments in course.");


1

3
1

if (TheRepository.DeleteCourse(id) && TheRepository.SaveAll())

return Request.CreateResponse(HttpStatusCode.OK);

else

6
1
7
1
8
1
9
2
0
2
1
{
2
return Request.CreateResponse(HttpStatusCode.BadRequest);
2
}
2
3
}
2
catch (Exception ex)
4
{
2
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.Message);
5
}
2
}
6
2
7
2
8
2
9
3
0
3
1

In the above implementation weve to note the below:

Method named DELETE, so the clients needs to issue HTTP DELETE request.

Delete method accepts the Id parameter of the deleted course, Id is set in URI, and
the request body is empty.

Weve returned proper HttpResponseMessange for all possible scenarios that might
happen when we execute this operation. In case the resource is deleted successfully,
server should return HTTP response 200 (OK). If the deletion of the resource failed
server should return HTTP response 400 (Bad request) with explanation content why
the request failed to process.

To test this we need to use fiddler and choose the Composer tab, well issue a DELETE
request to the URI: http://localhost:{your_port}/api/courses/33 Notice that the body of the
request is empty, the request will look as the image below:

Adding Students Controller to the Project


The new controller StudentsController will be responsible to do CRUD operations on
Students. The controller will be responsible for executing the actions below:

List all available students by sending GET request to URI: http://localhost:


{your_port}/api/students/

List single student by sending GET request to URI: http://


{your_port}/api/students/HasanAhmad Note that we are identifying resource by
passinguserName not Id here. This method is secured using basic authentication, so
resource owner only can query his detailed information once he
provide userName and password. Well cover this in details once we talk about
Securing Web API.

Add new student by sending POST request to URI: http://localhost:


{your_port}/api/students/

Update existing student by sending PUT/PATCH request to URI: http://localhost:


{your_port}/api/students/{userName}

Delete student by sending DELETE request to URI: http://localhost:


{your_port}/api/students/{userName}

I wont list the code for StudentsController here as it is some how identical to
CoursesController, you canbrowse it on GitHub. I will just list the new route configuration
weve added to the WebApiConfig class.

config.Routes.MapHttpRoute(

name: "Students",

routeTemplate: "api/students/{userName}",

defaults: new { controller = "students", userName = RouteParameter.Optional }

);

So in the next post well cover how to implement Resources Association.

Implement Resources Association


In this post well be covering the relationship between resources which is called Resources
Association, for example there is a relation between each Course and Students i.e. each
course has multiple students enrolled in it. So we can build an absolute URI in the

form:api/courses/courseid/students/{userName}, so if we want to list all students enrolled


in course id 5 our GET request will be as: api/courses/5/students/. If we want to enroll
student his username is TaiseerJoudeh in course id 5 well issue POST request to the URI:
api/courses/5/students/TaiseerJoudeh and so on.
To implement this we need add new route in WebApiConfig class named Enrollments as
the code below:

1 config.Routes.MapHttpRoute(
2

name: "Enrollments",

routeTemplate: "api/courses/{courseId}/students/{userName}",

defaults: new { controller = "Enrollments", userName = RouteParameter.Optional }

);

Notice how is courseId parameter is not optional and userName parameter is optional.
Now weve to add new controller named EnrollmentsController, well support two HTTP
verbs, GET to list all students in specific class, and POST to enroll student in specific calls,
youll notice that weve implemented pagination for GET method, well cover this topic in
the next post. The controller code listed as the below:

1 public class EnrollmentsController : BaseApiController


2
3

{
public EnrollmentsController(ILearningRepository repo)

: base(repo)

7
8

public IEnumerable<StudentBaseMode> Get(int courseId, int page = 0, int pageSize = 10)

IQueryable<Student> query;

0
1

query = TheRepository.GetEnrolledStudentsInCourse(courseId).OrderBy(s =>

1 s.LastName);
1
2

var totalCount = query.Count();

1
3

System.Web.HttpContext.Current.Response.Headers.Add("X-InlineCount",

1 totalCount.ToString());
4
1

var results = query

.Skip(pageSize * page)

.Take(pageSize)

.ToList()

.Select(s => TheModelFactory.CreateSummary(s));

7
1

return results;

8
1

9
2

public HttpResponseMessage Post(int courseId, [FromUri]string userName,

0 [FromBody]Enrollment enrollment)
2

try

2
2

if (!TheRepository.CourseExists(courseId)) return

3 Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not find Course");


2
4

var student = TheRepository.GetStudent(userName);

if (student == null) return Request.CreateErrorResponse(HttpStatusCode.BadRequest,

5 "Could not find Student");

2
6

var result = TheRepository.EnrollStudentInCourse(student.Id, courseId, enrollment);

2
7

if (result == 1)

return Request.CreateResponse(HttpStatusCode.Created);

else if (result == 2)

return Request.CreateResponse(HttpStatusCode.NotModified, "Student already

3 enrolled in this course");


1

3
2

return Request.CreateResponse(HttpStatusCode.BadRequest);

3
3

catch (Exception ex)

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

3
6
3
7
3
8
3
9
4
0
4
1
4

}
}

2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7

In the POST method notice how were using FromUri and FromBody attribute to indicate
from where were getting the values of the request, well get the userName from the URI

and the enrollment object from Request Body. The enrollment object will contain the
enrollment data only, we could send the CourseID and StudentID as well, but it makes
more sense to get both values from the URI.
To test the POST request well use fiddler to issue a POST request, we want to enroll student
TaiseerJoudeh in course with ID=5, the request will be as the image below:

As weve learned before, we will return HTTP status code as a result for this POST operation,
if the request is successful we will return 201 (Resource Created), if the student already
enrolled in this class well return status code 304 (Not modified).
In the next post well talk about pagination for large results, using manual pagination, and
how we return pagination meta-data.

Implement Resources Pagination

In this post well discuss the different ways to implement results pagination, well implement
manual pagination then format the response in two different ways (having pagination metadata in an envelope, and in pagination header).
It is well known that overwhelming your server with a query which returns hundreds of
thousand of records is a bad thing, when we are designing an API, we should consider
returning the results of our GET methods in paginated way, i.e. providing 10 results on each
request, and giving the API consumer the ability to navigate through results, specify the size
of the page, and which page he wants.
Manual Pagination and Envelopes
Well modify the CoursesController to use pagination instead of returning the whole
courses at once.
Lets see the code below:

1 public Object Get(int page = 0, int pageSize = 10)


2

IQueryable<Course> query;

4
5

query = TheRepository.GetAllCourses().OrderBy(c => c.CourseSubject.Id);

var totalCount = query.Count();

var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

8
9

var urlHelper = new UrlHelper(Request);

var prevLink = page > 0 ? urlHelper.Link("Courses", new { page = page - 1 }) : "";

var nextLink = page < totalPages - 1 ? urlHelper.Link("Courses", new { page = page + 1 })

1 : "";
1
1

var results = query

.Skip(pageSize * page)

1
3
1
4
1
5
1
6
1
7

.Take(pageSize)

.ToList()

.Select(s => TheModelFactory.Create(s));

1
9

return new

TotalCount = totalCount,

TotalPages = totalPages,

PrevPageLink = prevLink,

NextPageLink = nextLink,

Results = results

};

3
2

4
2
5
2
6
2
7
2
8

What weve done here is simple, weve introduced the below to CoursesController

Added two new optional parameters to the GET method with default values, those
optional parameters are translated to query string values, i.e. if we want to request the
second page of courses our GET request will be on the form: http://localhost:
{your_port}/api/courses/?page=1 Notice we didnt specify the pageSize parameter
and it took the default values 10. Sample of response will be on the form below:

1{
2
3

"totalCount": 33,

"totalPages": 4,

"prevPageLink": "http://localhost:8323/api/courses?page=0&pageSize=10",

"nextPageLink": "http://localhost:8323/api/courses?page=2&pageSize=10",

"results": [ /* Array containts the results*/ ]

8
9}

The method GetAllCourses in our Repository returns IQueryable response, which


is perfect because till this moment the query is represented in memory and didnt
execute against SQL server, so paging and order by for query are executing correctly.

Were using envelope to wrap our response, this envelope contains pagination metadata inside the JSON response such as: totalCount, totalPages, prevPageLink,
nextPageLink. It is important to return the total records count and total pages so API
consumer will be able to bind results and apply pagination on grid easily.

Returning the pagination meta-data in the response body is a common technique, there is
nothing wrong about it as everything is visible for the developer, the draw back of this
approach is that API consumer will dig into the response to extract data he was originally
asking for and maybe ignoring all the pagination meta data we returned if he do not need to
use it. So the other cleaner way to return pagination meta-data is to include them in response
header, so well keep the response body for the results only and well add new header called
X-Pagination which contains all pagination meta-data.

Manual Pagination and Pagination Headers


Well modify StudentsController to use headers to return pagination meta-data, in this
approach API consumer can use this header if he is interested in the pagination meta-data,
other wise he can just ignore this header and read the results of the query directly from
response body.
Applying this is fairly simple, the pagination technique we used in CoursesControrler will
be used the same here, except for returning the pagination meta-data in new header. Take a
look on the code below:

1 public IEnumerable<StudentBaseModel> Get(int page = 0, int pageSize = 10)


2
3

{
IQueryable<Student> query;

4
5

query = TheRepository.GetAllStudentsWithEnrollments().OrderBy(c => c.LastName);

6
7

var totalCount = query.Count();

var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

9
1

var urlHelper = new UrlHelper(Request);

var prevLink = page > 0 ? urlHelper.Link("Students", new { page = page - 1, pageSize =

1 pageSize }) : "";
1

var nextLink = page < totalPages - 1 ? urlHelper.Link("Students", new { page = page + 1,

1 pageSize = pageSize }) : "";


2
1

var paginationHeader = new

TotalCount = totalCount,

TotalPages = totalPages,

PrevPageLink = prevLink,

NextPageLink = nextLink

};

6
1

System.Web.HttpContext.Current.Response.Headers.Add("X-Pagination",

Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));

1
8

var results = query

.Skip(pageSize * page)

.Take(pageSize)

.ToList()

.Select(s => TheModelFactory.CreateSummary(s));

2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1

return results;
}

3
2

Notice how we added a new header to the response collection headers which contains a
serialized JSON object containing all pagination meta-data.
In the next post well talk briefly about web API security and how we can implement Basic
authentication.

Securing Web API


In this post well talk about securing our eLearning API, till this moment all requests sent
from client to the API are done over HTTP protocol (http://) and the communication is not
encrypted, but in this post well implement authentication feature in StudentsController so
well be sending Username and Password for authenticating students. It is well known that
transmitting confidential information should be done usingsecure HTTP (https://).
Enforce HTTPS for Web API
We can enforce HTTPS on the entire Web API by configuring this on IIS level, but in some
scenarios you might enforce HTTPS on certain methods where we transmit confidential
information and use HTTP for other methods.
In order to implement this we need to use Web API filters; basically filters will allow us to
execute some code in the pipeline before the execution of code in controller methods. This
new filter will be responsible to examine if the URI scheme is secured, and if it is not secure,
the filter will reject the call and send response back to the client informing him that request
should be done over HTTPS.
Well add a new filter which derives from AuthorizationFilterAttribute, this filter contains
an overridden method called OnAuthorization where we can inject a new response in case
the request is not done over HTTPS.
Lets add new folder named Filters to project root then add new class named
ForceHttpsAttribute which derives from
System.Web.Http.Filters.AuthorizationFilterAttribute

The code for the filter class will be as the below:

1 public class ForceHttpsAttribute : AuthorizationFilterAttribute


2
3

{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext

4 actionContext)
5
6

{
var request = actionContext.Request;

7
8

if (request.RequestUri.Scheme != Uri.UriSchemeHttps)

var html = "<p>Https is required</p>";

0
1

if (request.Method.Method == "GET")

actionContext.Response = request.CreateResponse(HttpStatusCode.Found);

actionContext.Response.Content = new StringContent(html, Encoding.UTF8,

1 "text/html");
3
1

UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);

httpsNewUri.Scheme = Uri.UriSchemeHttps;

httpsNewUri.Port = 443;

5
1

actionContext.Response.Headers.Location = httpsNewUri.Uri;

else

actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);

actionContext.Response.Content = new StringContent(html, Encoding.UTF8,

1 "text/html");

9
2
0
2
1
2
2
2
3
2

4
2

5
2

}
}

6
2
7
2
8
2
9
3
0

By looking at the code above we are using actionContext parameter to get the request and
response object from it. What we are doing here is examining the URI scheme of the request,
so if it is not secure (http://) we need to return small html message in the response body
informing client to send the request again over https.
As well we are differentiating between the GET method, and other methods (POST, PUT,
DELETE); because in case the client initiated a GET request to existing resource over http we
need to construct the same request again using https scheme and use 443 SSL port then inject
this secure URI in response location header. By doing this the client (browser) will
initiate automatically another GET request using https scheme .

In case of non GET requests, we will return 404 status code (Not Found) and small html
message informing client to send the request again over https.
Now if we want to enforce this filter over the entire Web API we need to add this filter
globally in WebAPIConfig class as the code below:

1 public static void Register(HttpConfiguration config)


2

3
4

config.Filters.Add(new ForceHttpsAttribute());
}

But if we want to enforce HTTPS for certain methods or certain controllers we can add this
filter attribute ForceHttps as the below:

1
2 //Enforce HTTPS on the entire controller
3

[Learning.Web.Filters.ForceHttps()]

public class CoursesController : BaseApiController

//Enforce HTTPS on POST method only

[Learning.Web.Filters.ForceHttps()]

public HttpResponseMessage Post([FromBody] CourseModel courseModel)

1
0
1
1

}
}

Authenticate Users using Basic Authentication


Until this moment all methods in our API are public, and any user on the internet is able to
request any resource, but in real life scenario this is not correct, specific data should be
accessed by specific people, so we need to authenticate requests on certain resources. A good
candidates in our sample API for clients authentications are:
1. Clients who make a GET request to the URI http://{your_port}/api/students/
{userName}. This means that if a client issue a request to GET detailed information
about student with username TaiseerJoudeh, then he needs to provide the username
and password for this resource in the request to authenticate him self. As well we
wont allow authenticated user TaiseerJoudeh to GET detailed information for
another resource because he is not the resource owner and he shouldnt be able to see
his detailed information such as Email, Birth date, classes enrolled in, etc
2. Clients who make a POST request the URI http://
{your_port}/api/courses/2/students/{userName}. This method is used to enroll
specific student in specific class, it makes sense to authenticate requests here because
if student with username KhaledHassan wants to enroll in course with Id 2, then he
needs to authenticate himself by providing username and password. Otherwise anyone
will be able to enroll any student in any class.
In our scenario well use the Basic Authentication to authenticate users requesting the above
two resources, to do so we need to add new Web API filter which will be responsible to read
authorization data from request header, check if the authentication type is basic, validate
credentials sent in the authorization headers, and finally authenticate user if all is good.
Otherwise it will return a response with status code 401 (Unauthorized) and it wont return
the resource.
Before digging into the code, lets talk a little bit about basic authentication.

What is Basic Authentication?


It provides a mean to authenticate the sender of the request before actually processing the
HTTP request. This will protect the server against Denial of service attacks (DoS). The way it
works that the client who is initiating the HTTP request provides a username and password
which is base64-encoded and placed in the HTTP header as string on the form

username:password, the recipient of the message (server) is expected to first authenticate


the credentials and process the request further only when the authentication is successful.
As the username and password are only base64-encoded and to avoid passwords are exposed
to others,Basic Authentication should be always used over SSL connection (HTTPS).
To apply this in our API lets add new class named LearningAuthorizeAttribute which
derives from System.Web.Http.Filters.AuthorizationFilterAttribute

1 public class LearningAuthorizeAttribute : AuthorizationFilterAttribute


2

3
4

[Inject]

public LearningRepository TheRepository { get; set; }

6
7

public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext

8 actionContext)
9

//Case that user is authenticated using forms authentication

//so no need to check header for basic authentication.

if (Thread.CurrentPrincipal.Identity.IsAuthenticated)

1
2

return;
}

1
3

var authHeader = actionContext.Request.Headers.Authorization;

1
4

if (authHeader != null)

if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&

!String.IsNullOrWhiteSpace(authHeader.Parameter))

var credArray = GetCredentials(authHeader);

var userName = credArray[0];

var password = credArray[1];

8
1

if (IsResourceOwner(userName, actionContext))

//You can use Websecurity or asp.net memebrship provider to login, for

//for he sake of keeping example simple, we used out own login functionality

if (TheRepository.LoginStudent(userName, password))

var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName),

2 null);
2

Thread.CurrentPrincipal = currentPrincipal;

return;

2
6
2

HandleUnauthorizedRequest(actionContext);
}

7
2

private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue

8 authHeader)
2

9
3

//Base 64 encoded string

var rawCred = authHeader.Parameter;

var encoding = Encoding.GetEncoding("iso-8859-1");

var cred = encoding.GetString(Convert.FromBase64String(rawCred));

3
2

var credArray = cred.Split(':');

3
3

return credArray;

4
3

private bool IsResourceOwner(string userName,

5 System.Web.Http.Controllers.HttpActionContext actionContext)
3

var routeData = actionContext.Request.GetRouteData();

var resourceUserName = routeData.Values["userName"] as string;

7
3

if (resourceUserName == userName)

return true;

return false;

4
1

private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext

4 actionContext)
2

actionContext.Response =

3 actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
4
4

actionContext.Response.Headers.Add("WWW-Authenticate",

"Basic Scheme='eLearning' location='http://localhost:8323/account/login'");

5
4
6
4
7
4
8
4

}
}

9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
6
4
6
5

6
6
6
7
6
8
6
9
7
0
7
1
7
2
7
3
7
4
7
5
7
6
7
7

In the code above weve overridden method OnAuthorization and implemented the below:
1. Getting the authorization data from request headers
2. Making sure that authorization header scheme is set to basic authentication and
contains base64-encoded string.
3. Converting the base64-encoded string to a string on the form username:password
and get the username and password.

4. Validating that username sent in authentication header is the same for username in
URI to ensure that resource owner only able to view his details.
5. Validating the credentials against our database.
6. If the credentials are correct we set the identity for current principal, so in sub
subsequent requests the user already authenticated.
7. If the credentials are incorrect the server sends an HTTP response with a 401 status
code (Unauthorized), and a WWW-Authenticate header. Web clients (browser) handle
this response by requesting a user ID and password from client.
Now to apply basic authentication on the two methods we mentioned earlier, all we need to
do is to add this attribute LearningAuthorizeAttribute to those methods as the code below:

public class StudentsController : BaseApiController

[LearningAuthorizeAttribute]

public HttpResponseMessage Get(string userName)

6
7
8

}
}

1 public class EnrollmentsController : BaseApiController


2

[LearningAuthorizeAttribute]

public HttpResponseMessage Post(int courseId, [FromUri]string userName,

5 [FromBody]Enrollment enrollment)
6

7
}
8
}

Now we need to test authentication by sending GET request to URI: http://localhost:


{your_port}/api/students/TaiseerJoudeh using two different clients, Firefox and Fiddler.
Testing user Firefox:
Well issue get request using the browser and the response returned will be 401 because we
didnt provide username and password and Authentication Required prompt will be
displayed asking for the username and password. By providing the the correct credentials
well receive status code 200 along with complete JSON object graph which contains all
specific data for for this user. For any sub subsequent request for the same resource the code
will not check credentials because we have created principal for this user and he is already
authenticated.
Testing using Fiddler:
By using fiddler we need to create the base64-encoded string which contains the
username:password and send it along with the authorization header, to generate this string
we will use http://www.base64encode.org/ as the image below:

Note that this is not encryption at all, so as we stated earlier, using Basic Authentication
should be done over SSL only.
Now we will use the encoded string to pass it in authorization header Authorization: Basic
VGFpc2VlckpvdWRlaDpZRUFSVkZGTw== the request will be as the image below:

The response code will be 200 OK and will receive the specific data for this authenticated
user.
In the next post well talk about versioning Web API and how we can implement different
techniques to implement versioning.

Preparing Web API for Versioning


Once you publish your successful API, consumers will start depending on it and your
exposed data will be used and integrated with other data in different ways, but it is known
that change is inevitable and new requirements and changes will evolve, if you are lucky you
will be able to adopt those changes without introducing any breaking changes for existing
clients, but this is not the case always.
So careful thinking about ASP.Net Web API versioning strategy before digging into
implementation is crucial. In our case, our API needs to change and we have to start building
different versions from our API to handle those changes without affecting existing
consumers. We need to run the new version concurrently with older version of the API to give
consumers enough time to migrate to the latest version, in some cases multiple versions of the
API can live forever side by side.
There are multiple ways to version your API, each way has it is own pros and cons, in this
post and the coming one well cover versioning by URI, query string, custom header, and by
accept header.
Introducing a change and preparing our API
In our case and for keeping things simple well introduce a breaking change on GET method
in the StudentsController so well return FullName and CoursesDuration in response
body instead of FirstName and LastName properties.
The simplest way I found in versioning your API is to create an identical controller of
StudentsController and name it StudentsV2Controller, notice the suffix V2 in controller
name, well depend on this part to select the appropriate controller based on API version.

Now in this controller well introduce our breaking changes on GET method and we keep
other HTTP verbs the same as we didnt introduce any change on them.
Special thanks goes to Shawn Wildermuth for describing this simple yet effective
technique for API versioning in his plural sight course.
Currently the JSON response for GET method in StudentsController as below:

1
2
3
4
[{
5
"id": 2,
6
"url": "http://localhost:8323/api/students/HasanAhmad",
7
"firstName": "Hasan",
8
"lastName": "Ahmad",
9
"gender": 0,
1
"enrollmentsCount": 4
0
},
1
{
1
"id": 3,
1
"url": "http://localhost:8323/api/students/MoatasemAhmad",
2
"firstName": "Moatasem",
1
"lastName": "Ahmad",
3
"gender": 0,
1
"enrollmentsCount": 4
4
}]
1
5
1
6

Now we want to achieve the below JSON response when calling the GET method in our new
StudentsV2Controller:

1
2
3
4
[{
5
"id": 2,
6
"url": "http://localhost:8323/api/students/HasanAhmad",
7
"fullName": "Hasan Ahmad",
8
"gender": 0,
9
"enrollmentsCount": 4,
1
"coursesDuration": 13
0
},
1
{
1
"id": 3,
1
"url": "http://localhost:8323/api/students/MoatasemAhmad",
2
"fullName": "Moatasem Ahmad",
1
"gender": 0,
3
"enrollmentsCount": 4,
1
"coursesDuration": 16
4
}]
1
5
1
6

Now lets copy and paste the existing controller StudnetsController and rename the new
one to StudentsV2Controller, we need to change the GET implementation as the code
below:

1 public IEnumerable<StudentV2BaseModel> Get(int page = 0, int pageSize = 10)


2
3

{
IQueryable<Student> query;

4
5

query = TheRepository.GetAllStudentsWithEnrollments().OrderBy(c => c.LastName);

6
7

var totalCount = query.Count();

var totalPages = Math.Ceiling((double)totalCount / pageSize);

9
1

var urlHelper = new UrlHelper(Request);

var prevLink = page > 0 ? urlHelper.Link("Students", new { page = page - 1, pageSize =

1 pageSize }) : "";
1

var nextLink = page < totalPages - 1 ? urlHelper.Link("Students", new { page = page + 1,

1 pageSize = pageSize }) : "";


2
1

var paginationHeader = new

TotalCount = totalCount,

TotalPages = totalPages,

PrevPageLink = prevLink,

NextPageLink = nextLink

};

6
1

System.Web.HttpContext.Current.Response.Headers.Add("X-Pagination",

Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));

1
8

var results = query

.Skip(pageSize * page)

.Take(pageSize)

.ToList()

0
2
1
2
2
2
3
2
4
2
5
.Select(s => TheModelFactory.CreateV2Summary(s));
2
6
return results;
2
}
7
2
8
2
9
3
0
3
1
3
2

The code above is almost the same as the GET method in StudentsController, the only
change we did is returning a new response type StudentV2BaseModel by calling the new
method CreateV2Summary in the ModelFactory class. The code below lists the new Data
Model StudentV2BaseModel and the new function CreateV2Summary. Note
that V2 suffix in the model name and function name are not mandatory to implement
versioning, you can name those anything you want.

1 public class StudentV2BaseModel


2

public int Id { get; set; }

public string Url { get; set; }

public string FullName { get; set; }

public Data.Enums.Gender Gender { get; set; }

public int EnrollmentsCount { get; set; }

public double CoursesDuration { get; set; }

1
0

public class ModelFactory

public StudentV2BaseModel CreateV2Summary(Student student)

return new StudentV2BaseModel()

Url = _UrlHelper.Link("Students", new { userName = student.UserName }),

Id = student.Id,

FullName = string.Format("{0} {1}", student.FirstName, student.LastName),

Gender = student.Gender,

EnrollmentsCount = student.Enrollments.Count(),

CoursesDuration = Math.Round(student.Enrollments.Sum(c => c.Course.Duration))

};

1
7
1
8
1
9
2

}
}

0
2
1
2
2
2
3
2
4
2
5

Now we have prepared our Students resource to be versioned, in the next post we will start
implementing different techniques for versioning

Different techniques to Implement Versioning


In this post well discuss four different techniques for API versioning, well start with the
most common one which is versioning using URI, then well cover versioning using query
string, custom header, and finally using accept header.
Web API Versioning using URI
Including the version number in the URI considers the most common way of versioning, so
we can consume a resource by calling http://localhost:{your_port}/api/v1/students/ (client
wants to use version 1 of the API) or http://localhost:{your_port}/api/v2/students/ (client
wants to use version 2 of the API).
The advantage of this technique that clients know which version they are using. To
implement this we need to add two new routes inside the Register method in
WebApiConfig class as the code below:

1
2 config.Routes.MapHttpRoute(
3

name: "Students",

routeTemplate: "api/v1/students/{userName}",

defaults: new { controller = "students", userName = RouteParameter.Optional }

);

7
8 config.Routes.MapHttpRoute(
9

name: "Students2",

routeTemplate: "api/v2/students/{userName}",

defaults: new { controller = "studentsV2", userName = RouteParameter.Optional }

);

Notice in the code above how we added two new routes and mapped each route with it is
corresponding controller. i.e. Route named Students2 is by default mapped to controller
studentsV2. In future if we want to add version V3 then we need to add new route to
select the appropriate controller, this might get messy over time.
The drawbacks for this technique that it is not compliance with REST specification because
the URI will keep changing by time, as well we need to keep maintaining new routes once we
introduce a new version.
Before we jump and discuss the implementation of the other three techniques we need to take
a look on how Web API selects the appropriate controller based on the information sent with
the request.
Web API uses a method named SelectController in classDefaultHttpControllerSelector,
this method accept HttpRequestMessage object which contains a key/value pair of route
data including controllername which is defined in class WebApiConfig. Based on this
information and by doing reflection on all classes which derives from ApiController class,
Web API can match the controller name with the appropriate class, if there is a duplicate or
class is not found, then an exception will be thrown.
To override this default implementation we need to add new class named
LearningControllerSelector which derives from class

Http.Dispatcher.DefaultHttpControllerSelector, then we need to override the method


SelectController, lets take a look on the code below:

1 public class LearningControllerSelector : DefaultHttpControllerSelector


2

private HttpConfiguration _config;

public LearningControllerSelector(HttpConfiguration config)

5
6

: base(config)
{

7
8

_config = config;
}

9
1

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)

var controllers = GetControllerMapping(); //Will ignore any controls in same name even if

1 they are in different namepsace


1
2

var routeData = request.GetRouteData();

1
3

var controllerName = routeData.Values["controller"].ToString();

1
4

HttpControllerDescriptor controllerDescriptor;

1
5

if (controllers.TryGetValue(controllerName, out controllerDescriptor))

6
1

var version = "2";

7
1
8

var versionedControllerName = string.Concat(controllerName, "V", version);

HttpControllerDescriptor versionedControllerDescriptor;

if (controllers.TryGetValue(versionedControllerName, out

2 versionedControllerDescriptor))
0

return versionedControllerDescriptor;

2
2

return controllerDescriptor;

3
2

return null;

4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3
3
3
4
3

}
}

5
3
6
3
7
3
8
3
9

What we have done here is:


1. Getting a dictionary of all classes (API Controllers) which derives from
ApiController class by calling method GetControllerMapping().
2. Retrieving the route data from the request request.GetRouteData() then looking for
the controller name in this request.
3. Trying to get an object of type HttpControllerDescriptor based on the controller
name we retrieved from the request. The HttpControllerDescriptor objects will
contain information that describes the selected controller.
4. If we found the controller, then we will try to find a versioned controller on the form
ControllerNameV2 using the same technique we used in the previous step. We will
cover now how we will get the version number, but for now we can fix it to 2.
Now we need to use this custom Controller Selector weve implemented instead of the
default one, we can do this by adding the code below inside Register method in class
WebApiConfig

config.Services.Replace(typeof(IHttpControllerSelector), new
1
LearningControllerSelector((config)));

Now we will implement versioning by sending the version number with the request object:

Web API Versioning using Query String


Versioning API by query string is straight forward, we will add query parameter such as ?
v=2 to the URI, the request will be as: http://localhost:{your_port}/api/students/?v=2
We will assume that clients who didnt provide the version in query string want the oldest
version (v=1).
To implement this well add method named GetVersionFromQueryString which accepts the
Request object where we can read query string from it and decide which version client
wants. Method will be added to class LearningControllerSelector

1
2
3
private string GetVersionFromQueryString(HttpRequestMessage request)
4
{
5
var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
6
7
var version = query["v"];
8
9
if (version != null)
1
{
0
return version;
1
}
1
1
return "1";
2
1
}
3
1
4

Weve to call this method inside method SelectController to read the version number and
select the appropriate controller. The only drawback for this technique is that URI will keep
changing by time and this is not compliance with REST specifications.
API Versioning by Custom Header
Now will try another approach where the version is set in the header request not as a part of
the URI, we will add our custom header named X-Learning-Version and set the version
there. Well assume that clients who didnt provide the header value are requesting the oldest
version of the API (Version 1), to implement this we need to add new function named
GetVersionFromHeader to LearningControllerSelector class as the code below:

private string GetVersionFromHeader(HttpRequestMessage request)

const string HEADER_NAME = "X-Learning-Version";

4
5

if (request.Headers.Contains(HEADER_NAME))

var versionHeader = request.Headers.GetValues(HEADER_NAME).FirstOrDefault();

if (versionHeader != null)

return versionHeader;

1
1
2
1
3
1
4

return "1";
}

1
5

Basically what we have done here is simple, we hard-coded the custom header name, and
checked if the headers collection contains this name, if so we tried to get the value from this
header.
To test this out we need to issue GET request using fiddler as the image below, note how we
added the new header X-Learning-Version to request header collection:

The only drawback for this technique is that we are introducing new custom header to the
headers collection, we can version by headers using the Accept Header without introducing
new custom header as well see in fourth technique below.
API Versioning using Accept Header
In this approach well version by using the Accept header. Out GET request accept header
will be on form: Accept:application/json; version=2.
Well assume that clients who didnt provide the version value in accept header are requesting
the oldest version of the API (Version 1), to implement this we need to add new function
named GetVersionFromAcceptHeaderVersion to LearningControllerSelector class as the
code below:

private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)

var acceptHeader = request.Headers.Accept;

4
5

foreach (var mime in acceptHeader)

if (mime.MediaType == "application/json")

var version = mime.Parameters

.Where(v => v.Name.Equals("version",

0 StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
1
1

if (version != null)

return version.Value;

return "1";

return "1";

5
1
6
1
7
1
8
1
9
2

In the code above we are looping on all header values collection and examining if the media
type is application/json, if this is the case then we get the value of the parameter named
version.
To test this out we need to issue GET request using fiddler as the image below, note how we
added version parameter to the Accept header:

This is more standard way of API versioning because we didnt add new custom header, and
we didnt version the API by changing the URI.
If you have plural sight subscription; I highly recommend watching this course where Shawn
Wildermuth covers another ways for API versioning.
In the next post well talk about resources cashing using Entity Tags.

Caching resources using CacheCow and ETag

In this post well discuss how we can implement resource caching by using an open source
framework for HTTP caching on the client and server, this framework is called CacheCow. It
is created by Ali Kheyrollahi, well cover in this post the server side caching.
API Source code is available on GitHub.
Using resource caching will enhance API performance, reduce the overhead on the server,
and minimize the response size.
The form of caching we want to achieve here called Conditional Requests, the idea is pretty
simple; the client will ask the server if it has an updated copy of the resource by sending
some information about the cached resources it holds using a request header called ETag,
then the server will decide weather there is an updated resource that should be returned to the
client, or the client has the most recent copy, so if the client has the most recent copy the
server will return HTTP status 304 (Not modified) without the resource content (empty
body). By using Conditional Requests the client will send HTTP requests always to the server
but the added value here that the server will only return full response 200 (OK) including
resource content within the body only if the client has stale copy of the resource.

So what is ETag (Entity Tag)?


ETag is a unique key (string) generated at the server for particular resource, you can think of
it as check-sum for a resource that semantically changes when the resource has updated.
ETag has two types, weak, and strong. The value of weak ETag is prefixed by W, i.e. ETag:
W/53fsfsd322 and the strong ETag is not prefixed with anything, i.e. ETag: 534928jhfr4.
usually Weak ETags indicates that the cached resource is useful to be used for short time (In
memory caching) and the strong ETag means that the resource caching is implemented using
persistence storage and the content of the both resources (client and server) are identical byte
for byte.

How ETags work?


By looking on the illustration below we will notice that at the beginning the client initiate
HTTP GET request asking for the course with Id: 4 assuming that that this resource has not
requested before, then the server will respond by returning the resource in the response body
along with a generated ETag in the response header.

Now the client wants to request the same resource again (Course id: 4) by sending another
HTTP GET, assuming that the client is interested in using caching, then the GET request
initiated will include a header called If-None-Match with the value of the ETag for this
resource, once the server receives this request it will read the ETag value and compare it with
the ETag value saved on the server, if they are identical then the server will send HTTP status
304 (Not modified) without the resource content (empty body) and the client will know that it
has the most recent copy of the resource.
For HTTP GET and DELETE we can use the header If-None-Match, but when updating a
resource and we want to use ETags we have to send the header If-Match with the HTTP
PUT/PATCH request, so the server will examine the ETag and if they are different; the server
will respond with HTTP Status 412 (Precondition Failed) so the client knows that there is a
fresher version of the resource on the server and the update wont take place until the client
has the same resource version on the server.

Configuring Web API to use CacheCow

After we had a brief explanation of how conditional requests and ETags work lets implement
this feature in our Web API.
Now we need to Install CacheCow server from NuGet, so open NuGet package manager
console and type Install-Package CacheCow.Server -Version 0.4.12 this will install two
dlls, the server version and common dll.
Configuring CacheCow is pretty easy, all we need to do is to create Cache Handler and inject
it into the Web API pipeline, this this handler will be responsible to inspect each request and
response coming to our API by looking for ETags and Match headers and do the heavy lifting
for us.
To implement this open the file WebApiConfig.cs and at the end of the file add the below
line of codes:

1 //Configure HTTP Caching using Entity Tags (ETags)


2 var cacheCowCacheHandler = new CacheCow.Server.CachingHandler();
3 config.MessageHandlers.Add(cacheCowCacheHandler);

Till this moment we have configured our API to use In-memory caching; this is the default
configuration for CacheCow, this will be fine if you have a single server or for demo
purposes, but in case of load balancers and web farms, the cache state should be persisted for
the whole farm in single place and all web servers should be aware of this cache. In this case
we need to configure CaschCow to use persistence medium (SQL Server, MongoDB,
MemCache). But before moving to persistence store let we test the in-memory caching.

Cache Cow in-memory caching:


To test this we need to open fiddler and choose the Composer tab, well issue a GET request
to the URI: http://localhost:{your_port}/api/courses/4 The request will look as the image
below:

In this GET request we need to note the following:

The HTTP status response is 200 OK which means that server returned the resource
content in the response body.

New two headers are added to the response which they are eTag and Last-Modified,
we are interested here on the eTag value and well get rid off the Last-Modified
header later on as well send conditional requests using eTag only.

The value of the eTag is weak (Prefixed with W) because we are using in-memory
caching for now, in other words if we restarted IIS or shutdown its worker process all
eTag values the client saving are useless.

Now after receiving the eTag header value, the client is responsible to send this value along
with any subsequent requests for the same resource, the client will use the header If-NoneMatch when sending the request and the server will respond by HTTP status 304 with empty
response body if the requested resource has not changed, other wise it will return 200 OK
with new eTag value and resource content in the response body. To examine this let we open
fiddler and issue GET request to the same resource (Course with Id: 4) as the image below:

In this GET request we need to note the following:

The HTTP status response is 304 Not modified which means that server returned
empty body and the copy of the resource at client side is the latest.

The same eTag header value is returned in the response.

Now lets move to configure CacheCow to use persistence caching medium (SQL Server)
instead of in-memory caching.

Cache Cow persistence caching using SQL Server:


Configuring CacheCow to use SQL server is easy we need to install NuGet package which
works with the medium we want to use, in our case SQL server, so open NuGet package
manager console and type: Install-Package CacheCow.Server.EntityTagStore.SqlServer
-Version 0.4.11, this will install the requiered dlls.
Now open the file WebApiConfig.cs again paste the code snippet below:

//Configure HTTP Caching using Entity Tags (ETags)


var connString =
1
System.Configuration.ConfigurationManager.ConnectionStrings["eLearningConnection"].Connecti
2
onString;
3
var eTagStore = new
4
CacheCow.Server.EntityTagStore.SqlServer.SqlServerEntityTagStore(connString);
5
var cacheCowCacheHandler = new CacheCow.Server.CachingHandler(eTagStore);
6
cacheCowCacheHandler.AddLastModifiedHeader = false;
config.MessageHandlers.Add(cacheCowCacheHandler);

What we implemented above is obvious, CacheCow needs to store caching information in


SQL server, so we need to inform which database to use, in our case well put this caching
information in the same database of the API eLearning. Then we need to pass the SQL
server eTagStore instance to the caching handler. As well weve turned off adding last
modified header to the response because we are interested in eTag values only.
If you directly tried to issue any request against our API you will receive 500 error (Internal
Server Error) because as we mentioned before CacheCow needs to store information about
the cached resource on the server, this means it needs a table and some stored procedures to
manipulate this table, so we need run SQL script before we go on. To do this navigate to the
path where you NuGet packages are installed, usually they are on
{projectpath}packagesCacheCow.Server.EntityTagStore.SqlServer.0.4.11scripts, open
the file named script.sql and execute all its content against your local eLearning Database.
After running the script navigate to SQL server explorer and open eLearning database, you
will notice that this script created a table named CacheState and another five stored
procedures mainly used for manipulating this table.
To test this out we need to issue the same GET request as the image below:

As you notice from the above image, the ETag value now is not weak, it is strong because we
persisted it on SQL server, so if we opened the table CacheState you will notice that
CacheCow has inserted new record including the ETag value, Route Pattern, Last Modified
date, and binary hash key as the image below:

Now if the client sends any subsequent requests to the same resource, the same ETag value
will be returned as long as no other clients updated the resource by issuing HTTP
PUT/PATCH on the same resource.
So if the client includes this ETag value within the If-None-Match header then the server will
respond by 304 HTTP status.
Now lets simulate the update scenario, the client will issue HTTP PUT on the resource
(Course with Id 4) including the ETag value in the header If-Match along with the request as
the image below:

In this PUT request we need to note the following:

The HTTP status response is 200 OK which means that client has the most recent
copy of the resource and the update of the resource has took place successfully.

New ETag has been returned in the response because the resource has been changed
on the server, so the client is responsible to save this new ETag for any subsequent
requests for the same resource.

The new ETag value and last modified date has been updated in table CacheStore
for this resource.

Now if we directly tried to issue another PUT request using the old ETag
(8fad5904b1a749e1b99bc3f5602e042b) we will receive HTTP Status 412 (Precondition
Failed) which means that updating the resource has failed because the client doesnt have the
latest version of the resource. Now client needs to issue GET request to get the latest version

of the resource and the new generated ETag (ad508f75c5144729a1563a4363a7a158), lets


test this as the image below:

Thats all for now!


I hope you liked this tutorial, I tried my best to explain all important features of Web API
which allows you to get started and build your RESTful API. You can always get back to the
complete running source code on github.

What is New in ASP.Net Web API 2 Part


1
March 5, 2014 By Taiseer Joudeh 11 Comments
Be Sociable, Share!

inShare2

Share on Tumblr

Email

Asp.Net Web API 2 has been released with the release of Asp.Net MVC 5 since 5 months
ago, Web API 2 can be used with .NET framework 4.5 only, the Web API 2 template is
available by default on VS 2013 and you can install Web Tools 2013.1 for VS 2012 to have
this template as well by visiting this link.
In my previous tutorial on Building ASP.Net Web API RESTful service, Ive covered
different features of the first release of ASP.Net Web API, in this two series post (part 2 can
be found here) I will focus on the main features in version 2, Ill be using the same project
Ive used in the previous tutorial but I will start new Web API 2 project then well implement
and discuss the new features. The source code for the new Web API 2 project can be found on
my GitHub repository.
Note: I will not upgrade the existing eLearning Web API to version 2, but if you are
interested to know how to upgrade version 1 to version 2 then you can follow the steps in
ASP.Net official post here.

What is new in ASP.Net Web API 2?

ASP.Net Web API 2 comes with a couple of nice features and enhancements, the most four
important features in my opinion are:

1. ASP.Net Web API 2 Attribute Routing:


o Web API 2 now supports attribute routing along with the conventional based
routing where we used to define a route per controller inside
WebApiConfig.cs class. Using attribute routing is very useful in situation
that we have a single controller which is responsible for multiple actions, with
version 2 the routes now can be defined directly on the controller or at the
action level.

IHttpActionResult:
o In the first version of Asp.Net Web API we always returned HTTP response
messages for all HTTP verbs using the extension
method Request.CreateResponse and this was really easy, now with version
2 of ASP.Net Web API this is simplified more by introducing a new interface
namedIHttpActionResult, this interface acts like a factory
for HttpResponseMessage with a support for custom responses such as (Ok,
BadRequest,Notfound, Unauthorized, etc).

Cross Origin Resource Sharing Support (CORS):


o Usually webpages from different domain are not allowed to issue AJAX
requests to HTTP Services (API) on other domains due to Same-Origin Policy,
the solution for this was to enable JSONP response. But in ASP.Net Web API 2
enabling CORS support is made easy, once you enable CORS it will allow
JavaScript on webpage to send AJAX requests to another HTTP Service (API)
on a different domain. This can be configured on the entire API, on certain
controller, or even on selected actions.

Enhancement on oData Support.


o Note: Ill not cover this in the current post as Im planing to do dedicated
series of posts on oData support for ASP.Net Web API.

o Multi part series tutorial for Building OData Service using ASP.Net Web
API is published now.

Lets cover the new features in practical example


As stated before and to keep things simple well depend on my previous tutorial eLearning
API concepts to demonstrate those features. All we want to use from the eLearning API is its
data access layer and database model, as well the same repository pattern, in other words wll
use only project eLearning.Data, if you are interested to know how we built the
eLearning.Data project then you can follow along on how we created the database
model here and how we applied the repository pattern here.
Once you have your database access layer project ready then you can follow along with me to
create neweLearning.WebAPI2 project to demonstrate those new features.
I will assume that you have Web Tools 2013.1 for VS 2012 installed on your machine, so you
can use the ASP.NetWeb API 2 template directly which will add the needed assemblies for
ASP.Net Web API2.

Step 1: Create new empty ASP.Net Web API 2 project


Well start by creating a new empty ASP.Net Web API 2 project as the image below, you can
name your project eLearning.WebAPI2, do not forget to choose .NET framework 4.5
version. Once The project is added we need install Entity Framework version 6 using NuGet
package manager or NuGet package console, the package well install is named
EntityFramework. When the package is installed, we need to add a reference for the class
library eLearning.Data which will act as our database repository.

Step 2: Configuring routes

The ASP.Net Web API 2 template we used has by default a class named WebApiConfig
inside the App_Start folder, when you open this class you will notice that there is new
line config.MapHttpAttributeRoutes(); this didnt exists in Web API version one, the
main responsbility for this line of code is to enable Attribute Routing feature in Web API
version 2 where we can define routes on the controller directly. In this tutorial we want to use
routing by attributes only to route all requests, so feel free to delete the default route named
DefaultApi.
The other important change introduced in Web API 2 is how the WebApiConfig file is
registered, go ahead and open class Global.asax and you will notice that there is new line
used for configuring the
routes GlobalConfiguration.Configure(WebApiConfig.Register); this line is
responsible for registering the routes when the global configuration class is initiated and
ready to be called.

Step 3: Adding first controller (Courses Controller)


Now we want to add a Web API Controller which will handle HTTP requests issues against
the URI /api/courses. To do this right-click on Controllers folder->Select Add->Name the
controller CoursesController and choose Empty API Controller Template. Note: It is not
required to name the controller CoursesController as we used in Web API version 1, now
the controllers selection are based on the attributes we define not the routes which used be
configured in class WebApiConfig
Well add support for getting single course by id and getting all courses. There are different
ways to define routing attributes, you can define route prefix on controller level, and you can
define them on action level. As well well cover how we can configure routing to an
exceptional route within the same controller. Below are the scenarios well cover:
1. Define attributes on action level
Lets Implement the code below which add support for handling and HTTP GET request sent
to the URI api/courses/23:

1 public class CoursesController : ApiController


2

[Route("api/courses/{id:int}")]

public HttpResponseMessage GetCourse(int id)

Learning.Data.LearningContext ctx = null;

Learning.Data.ILearningRepository repo = null;

8
9

try

ctx = new Learning.Data.LearningContext();

repo = new Learning.Data.LearningRepository(ctx);

1
1

var course = repo.GetCourse(id, false);

if (course != null)

return Request.CreateResponse(HttpStatusCode.OK, course);

else

return Request.CreateResponse(HttpStatusCode.NotFound);

6
1

catch (Exception ex)

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

finally

ctx.Dispose();

2
1

}
}

2
2
2
3
2
4
2
5
2
6
2
7
2
}
8
2
9
3
0
3
1
3
2
3
3
3
4

What we have done here is simple, if you look at the highlighted line of code above you will
notice how we defined the route on action level by using
attribute System.Web.Http.Route where we specified the request URI and stated that id
parameter should be integer, if you tried to issue GET request to URI /api/courses/abc you
will get 404 response.

In Web API version 1 we used to define names for routes inside WebApiConfig class, those
names were useful as we used them to link each resource to URI or for results navigation
purpose, in our case we still need to return PrevPageLink and NextPageLink in the
response body when user issue HTTP GET request to URI /api/courses. This still available
in Web API version 2 but defining route names will take place on the attribute level, lets
implement the code below:

1 public class CoursesController : ApiController


2

[Route("api/courses/", Name = "CoursesRoute")]

public HttpResponseMessage Get(int page = 0, int pageSize = 10)

IQueryable<Course> query;

7
8

Learning.Data.LearningContext ctx = new Learning.Data.LearningContext();

9
1

Learning.Data.ILearningRepository repo = new Learning.Data.LearningRepository(ctx);

0
1

query = repo.GetAllCourses().OrderBy(c => c.CourseSubject.Id);

var totalCount = query.Count();

var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

2
1

var urlHelper = new UrlHelper(Request);

var prevLink = page > 0 ? urlHelper.Link("CoursesRoute", new { page = page - 1,

1 pageSize = pageSize }) : "";


4

var nextLink = page < totalPages - 1 ? urlHelper.Link("CoursesRoute", new { page =

1 page + 1, pageSize = pageSize }) : "";


5
1
6

var results = query


.Skip(pageSize * page)

.Take(pageSize)

.ToList();

1
8

var result = new

TotalCount = totalCount,

TotalPages = totalPages,

PrevPageLink = prevLink,

NextPageLink = nextLink,

Results = results

};

2
2

return Request.CreateResponse(HttpStatusCode.OK, result);

3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
3

}
}

3
3
4
3
5
3
6
3
7

In the code above notice how we defined the route name on attribute level, you can
not define route names on Controller level so if you have another actions need route names
then you have to define them on each attribute.
2. Define attributes on controller level
Now instead of repeating the prefix /api/courses on each action, we can add this prefix on
controller level and define the specific route attributes information on each action, the change
is fairly simple as the code below:

1 [RoutePrefix("api/courses")]
2 public class CoursesController : ApiController
3

[Route(Name = "CoursesRoute")]

public HttpResponseMessage Get(int page = 0, int pageSize = 10)

7
8

/*Rest of implementation goes here*/


}

9
1

[Route("{id:int}")]

public HttpResponseMessage GetCourse(int id)

1
1
2
1

/*Rest of implementation goes here*/

3
1

}
}

4
1
5

3. Routing to exceptional route


In some cases you need to route to different URI while you are on the same controller, this
was not possible in Web API version 1 but its very easy to implement in version 2, assume
that we want to get all courses names based on certain subject, our URI have to be on the
form: api/subjects/{subjectid}/courses lets implement this by adding the code below:

1 [Route("~/api/subject/{subjectid:int}/courses")]
2 public HttpResponseMessage GetCoursesBySubject(int subjectid)
3 {
4

Learning.Data.LearningContext ctx = null;

Learning.Data.ILearningRepository repo = null;

IQueryable<Course> query;

7
8

try

ctx = new Learning.Data.LearningContext();

repo = new Learning.Data.LearningRepository(ctx);

1
1

query = repo.GetCoursesBySubject(subjectid);

var coursesList = query.Select(c => c.Name).ToList();

if (coursesList != null)

return Request.CreateResponse(HttpStatusCode.OK, coursesList);

else

return Request.CreateResponse(HttpStatusCode.NotFound);

6
1

catch (Exception ex)

return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);

finally

0
2
1 }
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2

ctx.Dispose();
}

9
3
0
3
1
3
2
3
3

Now how we defined the routing attribute and prefixed it with ~ so Web API will route any
HTTP GET request coming to the URI api/subject/8/courses to this route, this is really nice
feature when you want to introduce exceptional routing in the same controller.
In the next post Ill cover the IHttpActionResult return type as well the support for CORS in
ASP.Net Web API 2.

What is New in ASP.Net Web API 2 Part


2
March 5, 2014 By Taiseer Joudeh 8 Comments
Be Sociable, Share!

inShare

Share on Tumblr

Email

In the previous post weve covered ASP.Net Web API 2 attribute routing, in this post well
complete covering new features, well start by discussing the new response return type
IHttpActionResult then cover the support for CORS.
Source code is available on GitHub.

ASP.Net Web API 2 IHttpActionResult:


As we talked before ASP.Net Web API 2 has introduced new simplified interface
named IHttpActionResult, this interface acts like a factory for HttpResponseMessage, it
comes with custom built in responses such as (Ok, BadRequest, NotFound, Unauthorized,
Exception, Conflict, Redirect).
Lets modify the GetCourse(int id) method to return IHttpActionResult instead of
HttpResponseMessage as the code below:

1 [Route("{id:int}")]
2 public IHttpActionResult GetCourse(int id)
3 {
4

Learning.Data.LearningContext ctx = null;

Learning.Data.ILearningRepository repo = null;

try

ctx = new Learning.Data.LearningContext();

repo = new Learning.Data.LearningRepository(ctx);

1
0

var course = repo.GetCourse(id, false);

if (course != null)

1
2

return Ok<Learning.Data.Entities.Course>(course);
}

else

return NotFound();

catch (Exception ex)

return InternalServerError(ex);

finally

8
1
9 }
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2

ctx.Dispose();
}

Notice how were returning Ok (200 HTTP status code) with custom negotiated content, the
body of the response contains JSON representation of the returned course. As well we are
returning NotFound (404 HTTP status code) when the course is not found.
But what if want to extend the NotFound() response and customize it to return plain text
message in response body? This is straight forward using IHttpActionResult interface as the
below:
Construct our own Action Result:
We want to build our own NotFound(Your custom not found message) action result, so we
need to add a class which implements IHttpActionResult, lets add new file
named NotFoundPlainTextActionResult as the code below:

1 public class NotFoundPlainTextActionResult : IHttpActionResult


2 {
3

public string Message { get; private set; }

public HttpRequestMessage Request { get; private set; }

5
6

public NotFoundPlainTextActionResult(HttpRequestMessage request, string message)

this.Request = request;

this.Message = message;

0
1

public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)

1
2

return Task.FromResult(ExecuteResult());
}

1
3

public HttpResponseMessage ExecuteResult()

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NotFound);

1
5

response.Content = new StringContent(Message);

response.RequestMessage = Request;

return response;

7 }
1
8 public static class ApiControllerExtension
1 {
9

public static NotFoundPlainTextActionResult NotFound(ApiController controller, string

2 message)
0

2
1
2 }
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3

return new NotFoundPlainTextActionResult(controller.Request, message);


}

0
3
1
3
2
3
3

By looking at the code above you will notice that the class
NotFoundPlainTextActionResult implements interface IHttpActionResult, then weve
added our own implementation to the method ExecuteAsync which returns a Task of type
HttpResponseMessage. This HttpResponseMessage will return HTTP 404 status code along
with the custom message well provide in the response body.
In order to be able to reuse this in different controllers we need and new class
named ApiControllerExtension which contains a method returns this customized Not Found
response type.
Now back to our CoursesController we need to change the implementation of the standard
NotFound() to the new one as the code below:

if (course != null)
1

return Ok<Learning.Data.Entities.Course>(course);

else

return

7 eLearning.WebAPI2.CustomIHttpActionResult.ApiControllerExtension.NotFound(this, "Course not


8 found");
}

You can read more about extending IHttpActionResult result by visiting Filip W. post.

ASP.Net Web API 2 CORS Support:


Enabling Cross Origin Resource Sharing in ASP.Net Web API 2 is simple, once it is enabled
any client sending AJAX requests from webpage (on a different domain) to our API will be
accepted.
By default CORS assembly doesnt exist within ASP.NET Web API 2 assemblies so we need
install it from NuGet, so open your NuGet package console, and type the following InstallPackageMicrosoft.AspNet.WebApi.Cors -Version 5.0.0 once the package is
installed open WebApiConfig class and add the following line of code inside the register
method config.EnableCors(); by doing this we didnt enable CORS yet, there are
different levels to enable CORS on ASP.Net Web API, levels are:
1. On controller level
You can now add attribute named EnableCors on the entire controller so by default every
action on this controller will support CORS as well, to do this open file CoursesController
and add the highlighted line of code below:

1 [RoutePrefix("api/courses")]
2 [EnableCors("*", "*", "GET,POST")]
3 public class CoursesController : ApiController
4{
5

//Rest of implementation is here

6}

The EnableCors attribute accept 3 parameters, in the first one you can specify the origin of
the domain where requests coming from, so if you want to allow only domain
www.example.com to send requests for your API; then you specify this explicitly in this
parameter, most of the cases you need to allow * which means all requests are accepted from
any origin. In the second parameter you can specify if you need a certain header to be
included in each request, so you can force consumers to send this header along with each

request, in our case we will use * as well. The third parameter is used to specify which HTTP
verbs this controller accepts, you can put * as well, but in our case we want to allow only
GET and POST verbs to be called from requests coming from different origin.
In case you want to exclude a certain action in the controller from CORS support you can add
the attributeDisableCors to this action, let we assume we want to disable CORS support on
method GetCourse so the code to disable CORS support on this action will be as the below:

1 [Route("{id:int}")]
2 [DisableCors()]
3 public IHttpActionResult GetCourse(int id)
4{
5

//Rest of implementation is here

6}

2. On action level
Enabling CORS on certain actions is fairly simple, all you want to do is adding the attribute
EnableCors on this action, as well EnableCors accepts the same 3 parameters we discussed
earlier. Enabling it on action level will be as the below code:

1 [Route(Name = "CoursesRoute")]
2 [EnableCors("*", "*", "GET")]
3 public HttpResponseMessage Get(int page = 0, int pageSize = 10)
4{
5

//Rest of implemntation is here

6}

3. On the entire API

In some situations where you have many controllers and you want to allow CORS on your
entire API, it is not convenient to visit each controller and add EanbleCors attribute to it, in
this situation we can allow it on the entire API inside the Register method in
Class WebApiConfig, so open your WebApiConfig class and add the code below:

1 //Support for CORS


2 EnableCorsAttribute CorsAttribute = new EnableCorsAttribute("*", "*", "GET,POST");
3 config.EnableCors(CorsAttribute);

By adding this we enabled CORS support for every controller we have in our API, still you
can disable CORS support on selected actions by adding DisableCors attribute on action
level

Vous aimerez peut-être aussi