Web API Controller
Web API Controller
We created Web API with MVC project in the previous section where it
generated a simple controller. Here, you will learn about Web API Controller
in detail.
namespace MyWebAPI.Controllers
{
public class ValuesController : ApiController
{
// GET: api/student
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/student/5
public string Get(int id)
{
return "value";
}
// POST: api/student
public void Post([FromBody]string value)
{
}
// PUT: api/student/5
public void Put(int id, [FromBody]string value)
1
{
}
// DELETE: api/student/5
public void Delete(int id)
{
}
}
}
As you can see in the above example, ValuesController class is derived from
ApiController and includes multiple action methods whose names match with
HTTP verbs like Get, Post, Put and Delete.
The following figure illustrates the significance of Web API controller and action
methods.
2
Web API Controller Overview
If you want to write methods that do not start with an HTTP verb then you
can apply the appropriate http verb attribute on the method such as HttpGet,
HttpPost, HttpPut etc. same as MVC controller.
namespace MyWebAPI.Controllers
{
public class ValuesController : ApiController
{
[HttpGet]
public IEnumerable<string> Values()
{
return new string[] { "value1", "value2" };
3
}
[HttpGet]
public string Value(int id)
{
return "value";
}
[HttpPost]
public void SaveNewValue([FromBody]string value)
{
}
[HttpPut]
public void UpdateValue(int id, [FromBody]string value)
{
}
[HttpDelete]
public void RemoveValue(int id)
{
}
}
}
The following table lists possible action method names for each HTTP method:
4
HTTP Method Possible Web API Action Method Name
GET Get()
get()
GET()
GetAllStudent()
*any name starting with Get *
POST Post()
post()
POST()
PostNewStudent()
*any name starting with Post*
PUT Put()
put()
PUT()
PutStudent()
*any name starting with Put*
PATCH Patch()
patch()
PATCH()
PatchStudent()
*any name starting with Patch*
DELETE Delete()
delete()
DELETE()
DeleteStudent()
*any name starting with Delete*
The following figure illustrates the overall request/response pipeline.
5
Configure Web API
Web API supports code based configuration. It cannot be configured in
web.config file. We can configure Web API to customize the behavior of Web
API hosting infrastructure and components such as routes, formatters, filters,
DependencyResolver, MessageHandlers, ParamterBindingRules, properties,
services etc.
We created a simple Web API project in the Create Web API Project section.
Web API project includes default WebApiConfig class in the App_Start folder
and also includes Global.asax as shown below.
Global.asax
public class WebAPIApplication : System.Web.HttpApplication
{
6
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
//other configuration
}
}
WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Property Description
IncludeErrorDetailPolicy Gets or sets a value indicating whether error details should be included in error messa
ParameterBindingRules Gets the collection of rules for how parameters should be bound.
7
Property Description
Properties Gets the properties associated with this Web API instance.
Routes Gets the collection of routes configured for the Web API.
1. Convention-based Routing
2. Attribute Routing
Convention-based Routing
In the convention-based routing, Web API uses route templates to determine
which controller and action method to execute. At least one route template
must be added into route table in order to handle various HTTP requests.
When we created Web API project using WebAPI template, it also added
WebApiConfig class in the App_Start folder with default route as shown below.
8
}
In the above WebApiConfig.Register()
method, config.MapHttpAttributeRoutes() enables attribute routing which we will
learn later in this section. The config.Routes is a route table or route collection
of type HttpRouteCollection. The "DefaultApi" route is added in the route table
using MapHttpRoute() extension method. The MapHttpRoute() extension method
internally creates a new instance of IHttpRoute and adds it to an
HttpRouteCollection. However, you can create a new route and add it into a
collection manually as shown below.
// define route
IHttpRoute defaultRoute = config.Routes.CreateRoute("api/{controller}/{id}",
new { id = RouteParameter.Optional },
null);
// Add route
config.Routes.Add("DefaultApi", defaultRoute);
}
}
The following table lists parameters of MapHttpRoute() method.
Parameter Description
Now, let's see how Web API handles an incoming http request and sends the
response.
9
GET http://localhost:1234/api/values/ HTTP/1.1
User-Agent: Fiddler
Host: localhost: 60464
Content-Type: application/json
If Web API framework does not find matched routes for an incoming request
then it will send 404 error response.
The following table displays which action method and controller will be
executed on different incoming requests.
10
Request URL Request HTTP Method
http://localhost:1234/api/course GET Get
http://localhost:1234/api/product POST Pos
http://localhost:1234/api/teacher PUT Put
Note:
Web API also supports routing same as ASP.NET MVC by including action method
name in the URL.
Configure Multiple Routes
We configured a single route above. However, you can configure multiple
routes in the Web API using HttpConfiguration object. The following example
demonstrates configuring multiple routes.
// school route
config.Routes.MapHttpRoute(
name: "School",
routeTemplate: "api/myschool/{id}",
defaults: new { controller="school", id = RouteParameter.Optional }
constraints: new { id ="/d+" }
);
// default route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
In the above example, School route is configured before DefaultApi route. So
any incoming request will be matched with the School route first and if
incoming request url does not match with it then only it will be matched with
DefaultApi route. For example, request url is http://localhost:1234/api/myschool is
matched with School route template, so it will be handled by SchoolController.
11
Note: The reason to use api in the route template is just to avoid confusion between
MVC controller and Web API controller. You can use any pattern based on your app
architecture.
Attribute Routing
Attribute routing is supported in Web API 2. As the name implies, attribute
routing uses [Route()] attribute to define routes. The Route attribute can be
applied on any controller or action method.
Parameter Binding
In the previous section we learned how Web API routes HTTP request to a
controller and action method. Here, we will learn how Web API binds HTTP
request data to the parameters of an action method.
Action methods in Web API controller can have one or more parameters of
different types. It can be either primitive type or complex type. Web API binds
action method parameters either with URL's query string or with request body
depending on the parameter type. By default, if parameter type is of .NET
primitive type such as int, bool, double, string, GUID, DateTime, decimal or
any other type that can be converted from string type then it sets the value
12
of a parameter from the query string. And if the parameter type is complex
type then Web API tries to get the value from request body by default.
The following table lists the default rules for parameter binding.
Let's see how Web API get values of action method parameters from HTTP
request.
}
}
As you can see above Get action method includes id parameter of int type.
So, Web API will try to extract the value of id from the query string of
requested URL, convert it into int and assign it to id parameter of Get action
method. For example, if an HTTP request
is http://localhost/api/student?id=1 then value of id parameter will be 1.
Followings are valid HTTP GET Requests for the above action method.
http://localhost/api/student?id=1
http://localhost/api/student?ID=1
13
Note:
Query string parameter name and action method parameter name must be the same
(case-insensitive). If names do not match then values of the parameters will not be
set. The order of the parameters can be different.
}
}
As you can see above, Get method includes multiple primitive type
parameters. So, Web API will try to extract the values from the query string
of request URL. For example, if an HTTP request
is http://localhost/api/student?id=1&name=steve then value of id parameter
will be 1 and name will be "steve".
Followings are valid HTTP GET Requests for the above action method.
http://localhost/api/student?id=1&name=steve
http://localhost/api/student?ID=1&NAME=steve
http://localhost/api/student?name=steve&id=1
Note:
Query string parameter names must match with the name of an action method
parameter. However, they can be in different order.
14
Example: Post Method with Primitive Parameter
public class StudentController : ApiController
{
public Student Post(id id, string name)
{
}
}
As you can see above, Post() action method includes primitive type
parameters id and name. So, by default, Web API will get values from the
query string. For example, if an HTTP POST request
is http://localhost/api/student?id=1&name=steve then the value of id will be
1 and name will be "steve" in the above Post() method.
Now, consider the following Post() method with complex type parameter.
}
}
The above Post() method includes Student type parameter. So, as a default
rule, Web API will try to get the values of stud parameter from HTTP request
body.
Following is a valid HTTP POST request in the fiddler for the above action
method.
15
Parameter Binding
Web API will extract the JSON object from the Request body above and
convert it into Student object automatically because names of JSON object
properties matches with the name of Student class properties (case-
insensitive).
}
}
16
The above Post method includes both primitive and complex type parameter.
So, by default , Web API will get the id parameter from query string and
student parameter from the request body.
Following is a valid HTTP POST request in the fiddler for the above action
method.
Parameter Binding
Note:
Post action method cannot include multiple complex type parameters because at
most one parameter is allowed to be read from the request body.
Parameter binding for Put and Patch method will be the same as Post method
in Web API.
Use [FromUri] attribute to force Web API to get the value of complex type
from the query string and [FromBody] attribute to get the value of primitive
type from the request body, opposite to the default rules.
Example: FormUri
public class StudentController : ApiController
{
17
public Student Get([FromUri] Student stud)
{
}
}
In the above example, Get method includes complex type parameter with
[FromUri] attribute. So, Web API will try to get the value of Student type
parameter from the query string. For example, if an HTTP GET
request http://localhost:xxxx/api/student?id=1&name=steve then Web API
will create Student object and set its id and name property values to the value
of id and name query string.
Note:
Name of the complex type properties and query string parameters must match.
Example: FromUri
public class StudentController : ApiController
{
public Student Post([FromUri]Student stud)
{
}
}
As you can see above, we have applied [FromUri] attribute with the Student
parameter. Web API by default extracts the value of complex type from
request body but here we have applied [FromUri] attribute. So now, Web API
will extract the value of Student properties from the query string instead of
request body.
The same way, apply [FromBody] attribute to get the value of primitive data
type from the request body instead of query string, as shown below.
Example: FromBody
public class StudentController : ApiController
{
public Student Post([FromBody]string name)
{
}
}
Following is a valid HTTP POST request in the fiddler for the above action
method.
18
Parameter Binding
Note:
FromBody attribute can be applied on only one primitive parameter of an action
method. It cannot be applied on multiple primitive parameters of the same action
method.
The Web API action method can have following return types.
1. Void
2. Primitive type or Complex type
3. HttpResponseMessage
4. IHttpActionResult
19
Void
It's not necessary that all action methods must return something. It can have void return type.
For example, consider the following Delete action method that just deletes the student from the
data source and returns nothing.
20
return id;
}
return student;
}
}
As you can see above, GetId action method returns an integer and GetStudent action method
returns a Student type.
21
Complex Return Type in Response
HttpResponseMessage
Web API controller always returns an object of HttpResponseMessage to the hosting
infrastructure. The following figure illustrates the overall Web API request/response pipeline.
As you can see in the above figure, the Web API controller returns HttpResponseMessage object.
You can also create and return an object of HttpResponseMessage directly from an action method.
The advantage of sending HttpResponseMessage from an action method is that you can configure
a response your way. You can set the status code, content or error message (if any) as per your
requirement.
if (stud == null) {
return Request.CreateResponse(HttpStatusCode.NotFound, id);
}
23
Web API Response in Fiddler
IHttpActionResult
The IHttpActionResult was introduced in Web API 2 (.NET 4.5). An action method in Web API 2
can return an implementation of IHttpActionResult class which is more or less similar to
ActionResult class in ASP.NET MVC.
You can create your own class that implements IHttpActionResult or use various methods
of ApiController class that returns an object that implement the IHttpActionResult.
if (stud == null)
{
return NotFound();
}
return Ok(stud);
}
In the above example, if student with specified id does not exists in the database then it will return
response with the status code 404 otherwise it sends student data with status code 200 as a
24
response. As you can see, we don't have to write much code because NotFound() and Ok() method
does it all for us.
The following table lists all the methods of ApiController class that returns an object of a class
that implements IHttpActionResult interface.
25
};
return Task.FromResult(response);
}
}
Now, you can return TextResult object from the action method as shown below.
if (String.IsNullOrEmpty(name))
{
return NotFound();
}
Media Type
Media type (aka MIME type) specifies the format of the data as type/subtype
e.g. text/html, text/xml, application/json, image/jpeg etc.
For example, if a client wants response data in JSON format then it will send
following GET HTTP request with Accept header to the Web API.
26
The same way, if a client includes JSON data in the request body to send it to
the receiver then it will send following POST HTTP request with Content-Type
header with JSON data in the body.
{
id:1,
name:'Steve'
}
Web API converts request data into CLR object and also serialize CLR object
into response data based on Accept and Content-Type headers. Web API
includes built-in support for JSON, XML, BSON, and form-urlencoded data. It
means it automatically converts request/response data into these formats
OOB (out-of the box).
return insertedStudent;
}
}
As you can see above, the Post() action method accepts Student type
parameter, saves that student into DB and returns inserted student with
generated id. The above Web API handles HTTP POST request with JSON or
XML data and parses it to a Student object based on Content-Type header
27
value and the same way it converts insertedStudent object into JSON or XML
based on Accept header value.
In the above figure, Accept header specifies that it expects response data in
XML format and Content-Type specifies that the student data into request
body is in the JSON format. The following is the response upon execution of
the above request.
28
Request-Response Data Format
The same way, you can specify different request & response format using
accept and content-type headers and Web API will handle them without any
additional changes.
The following HTTP POST request sends data in XML format and receives data
in JSON format.
29
The above HTTP POST request will get the following response upon execution.
Web API
Response
Thus, Web API handles JSON and XML data by default. Learn how Web API
formats request/response data using formatters in the next section.
Filters are actually attributes that can be applied on the Web API controller or one or more action
methods. Every filter attribute class must implement IFilter interface included in
System.Web.Http.Filters namespace. However, System.Web.Http.Filters includes other interfaces
and classes that can be used to create filter for specific purpose.
The following table lists important interfaces and classes that can be used to create Web API filters.
30
As you can see, the above table includes class as well as interface for some of the filter types.
Interfaces include methods that must be implemented in your custom attribute class whereas filter
class has already implemented necessary interfaces and provides virtual methods, so that they can
be overridden to add extra logic. For example, ActionFilterAttribute class includes methods that
can be overridden. We just need to override methods which we are interested in, whereas if you
use IActionFilter attribute than you must implement all the methods.
Visit MSDN to know all the classes and interfaces available in System.Web.Http.Filters.
Let's create simple LogAttribute class for logging purpose to demonstrate action filter.
First, create a LogAttribute class derived from ActionFilterAttribute class as shown below.
31
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext
actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>>
continuation)
{
Trace.WriteLine(string.Format("Action Method {0} executing at {1}",
actionContext.ActionDescriptor.ActionName, DateTime.Now.ToShortDateString()), "Web
API Logs");
result.Wait();
return result;
}
32
First, create a new Web API project in Visual Studio 2013 for Web express
edition.
Open Visual Studio 2013 for Web and click on File menu -> New
Project.. This will open New Project popup as shown below.
In the New Project popup, select Web template under Visual C#. Enter
project name WebApiDemo and the location where you want to create the
project. Click OK to continue. This will open another popup to select a project
template. Select Web API project as shown below.
33
Select Web API Project Template
Here, we are not going to use any authentication in our demo project. So,
click on Change Authentication button to open Authentication popup and
select No Authentication radio button and then click OK as shown below.
34
Change Authentication
35
Web API Project
As you can see, a new WebApiDemo project is created with all necessary files.
It has also added default ValuesController. Since, we will be adding our new
Web API controller we can delete the default ValuesController.
36
Create Entity Data Model
Select Data in the left pane and select ADO.NET Entity Data Model in the
middle pane and enter the name of a data model and click Add. This will open
Entity Data Model Wizard using which you can generate Entity Data Model for
an existing School database. The scope of the topic is limited to Web API so
we have not covered how to generate EDM. Learn about it here.
EntityFramework will generate following data model after completing all the
steps of Entity Data Model Wizard.
37
Generated Entities in the EDM Designer
Entity Framework also generates entities and context classes as shown below.
38
.edmx in the Project
39
Create Web API Controller
In the Add Scaffold popup, select Web API in the left pane and select Web
API 2 Controller - Empty in the middle pane and click Add. (We select
Empty template as we plan to add action methods and Entity Framework by
ourselves.)
This will open Add Controller popup where you need to enter the name of
your controller. Enter "StudentController" as a controller name and
click Add as shown below.
40
namespace MyMVCApp.Controllers
{
public class StudentController : ApiController
{
}
}
We will implement GET, POST, PUT and DELETE action methods in this
controller in the subsequent sections.
Add Model
We will be accessing underlying database using Entity Framework (EF). As you
have seen above, EF creates its own entity classes. Ideally, we should not
return EF entity objects from the Web API. It is recommended to return DTO
(Data Transfer Object) from Web API. As we have created Web API project
with MVC, we can also use MVC model classes which will be used in both MVC
and Web API.
Here, we will return Student, Address and Standard from our Web API. So,
create StudentViewModel, AddressViewModel and StandardViewModel in the
Models folder as shown below.
41
Models
Model Classes
public class StudentViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
42
}
Now, let's implement Get methods to handle various HTTP GET requests in
the next section.
In this section we will implement Get action methods in our Web API controller
class that will handle HTTP GET requests.
As per the Web API naming convention, action method that starts with a work
"Get" will handle HTTP GET request. We can either name it only Get or with
any suffix. Let's add our first Get action method and give it a name
GetAllStudents because it will return all the students from the DB. Following
an appropriate naming methodology increases readability and anybody can
understand the purpose of a method easily.
43
.Select(s => new StudentViewModel()
{
Id = s.StudentID,
FirstName = s.FirstName,
LastName = s.LastName
}).ToList<StudentViewModel>();
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
}
As you can see in the above example, GetAllStudents() method returns all the
students using EF. If no student exists in the DB then it will return 404
NotFound response otherwise it will return 200 OK response with students
data. The NotFound() and Ok() methods defined in the ApiController returns 404
and 200 response respectively.
In the database, every student has zero or one address. Suppose, you want
to implement another GET method to get all the Students with its address
then you may create another Get method as shown below.
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
44
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
}
The above web API example will compile without an error but when you
execute HTTP GET request then it will respond with the following multiple
actions found error.
45
Web API Error
This is because you cannot have multiple action methods with same number
of parameters with same type. Both action methods above do not include any
parameters. So Web API does not understand which method to execute for
the HTTP GET request http://localhost:64189/api/student .
public StudentController()
{
}
46
FirstName = s.FirstName,
LastName = s.LastName,
Address = s.StudentAddress == null || includeAddress ==
false ? null : new AddressViewModel()
{
StudentId = s.StudentAddress.StudentID,
Address1 = s.StudentAddress.Address1,
Address2 = s.StudentAddress.Address2,
City = s.StudentAddress.City,
State = s.StudentAddress.State
}
}).ToList<StudentViewModel>();
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
}
As you can see, GetAllStudents action method includes parameter
includeAddress with default value false. If an HTTP request contains
includeAddress parameter in the query string with value true then it will return
all students with its address otherwise it will return students without address.
47
Access Web API GET Method in the Browser
48
Access Web API GET Method in the Browser
Action method
49
public StudentController()
{
}
if (students == null)
{
return NotFound();
}
return Ok(students);
}
if (student == null)
{
return NotFound();
50
}
return Ok(student);
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
51
Address1 = s.StudentAddress.Address1,
Address2 = s.StudentAddress.Address2,
City = s.StudentAddress.City,
State = s.StudentAddress.State
},
Standard = new StandardViewModel()
{
StandardId = s.Standard.StandardId,
Name = s.Standard.StandardName
}
}).ToList<StudentViewModel>();
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
}
Now, the above Web API will handle following HTTP GET requests.
Similarly you can implement Get methods to handle different HTTP GET
requests in the Web API.
52
The following figure shows HTTP GET response of above request in Fiddler.
Next, implement Post action method to handle HTTP POST request in the Web
API.
The HTTP POST request is used to create a new record in the data source in
the RESTful architecture. So let's create an action method in
our StudentController to insert new student record in the database using
Entity Framework.
The action method that will handle HTTP POST request must start with a word
Post. It can be named either Post or with any suffix e.g. POST(), Post(),
PostNewStudent(), PostStudents() are valid names for an action method that
handles HTTP POST request.
The following example demonstrates Post action method to handle HTTP POST
request.
53
if (!ModelState.IsValid)
return BadRequest("Invalid data.");
ctx.SaveChanges();
}
return Ok();
}
}
As you can see above, we named action method as PostNewStudent. You can
give any name as per your requirement but it must start with the word "Post".
The PostNewStudent() action method includes parameter
of StudentViewModel type which includes all the information about new
student.
Note:
This is just a demo project. However, you can return newly created student object
with Id in the response.
Now, you can send HTTP POST request using Fiddler as shown below and see
the response.
54
Execute HTTP POST request in Fiddler
Next, implement Put action method to handle HTTP PUT request in the Web
API.
The HTTP PUT method is used to update an existing record in the data source
in the RESTful architecture.
The following example demonstrates Put action method to handle HTTP PUT
request.
55
{
public StudentController()
{
}
if (existingStudent != null)
{
existingStudent.FirstName = student.FirstName;
existingStudent.LastName = student.LastName;
ctx.SaveChanges();
}
else
{
return NotFound();
}
}
return Ok();
}
}
As you can see above, Put action method includes a parameter
of StudentViewModel. It then creates new student entity using
passed StudentViewModel object and then changes the state to be modified.
Now, you can send HTTP PUT request using Fiddler as shown below and see
the response.
56
Execute PUT request in Fiddler
Next, implement Delete action method to handle HTTP DELETE request in the
Web A
The HTTP DELETE request is used to delete an existing record in the data
source in the RESTful architecture.
57
{
public StudentController()
{
}
ctx.Entry(student).State = System.Data.Entity.EntityState.Deleted;
ctx.SaveChanges();
}
return Ok();
}
}
As you can see above, Delete action method includes an id parameter of int
type because it just needs an id to delete a record. It fetches an existing
student from the database that matches with the specified id and then marks
its status as deleted. This will delete a student from the database.
Now, you can send HTTP DELETE request using Fiddler as shown below and
view the response.
Thus you can create Get, Post, Put and Delete methods to implement HTTP
GET, POST, PUT and DELETE requests respectively.
58
Consume Web API for CRUD operation
In the previous section, we created Web API with Get, Post, Put and Delete methods that handles
HTTP GET, POST, PUT and DELETE requests respectively. Here, we will see how to consume
(access) Web API for CRUD operation.
Web API can be accessed in the server side code in .NET and also on client side using JavaScript
frameworks such as jQuery, AnguarJS, KnockoutJS etc.
Here, we will consume our Web API (created in the previous section) in the following
environments:
The following figure illustrates consuming Web API in client side framework using AJAX.
59
Consume Web API
at Client Side
Learn how to consume Get, Post, Put and Delete methods of Web API in ASP.NET MVC and
Angular in the next coming sections.
Share
Tweet
Share
Whatsapp
60
Address2 = s.StudentAddress.Address2,
City = s.StudentAddress.City,
State = s.StudentAddress.State
}
}).ToList<StudentViewModel>();
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
}
The above GetAllStudents() action method will handle HTTP GET
request http://localhost:64189/api/student and will return a list of students. We
will send this HTTP request in the ASP.NET MVC controller to get all the student
records and display them in the MVC View. The view will look like below.
61
Student List View
The following is a Web API + MVC project structure created in the previous
sections. We will add necessary classes in this project.
62
Web API Project
Step 1:
First of all, create MVC controller class called StudentController in the Controllers
folder as shown below. Right click on the Controllers folder > Add.. >
select Controller..
63
Example: MVC Controller
public class StudentController : Controller
{
// GET: Student
public ActionResult Index()
{
return View();
}
}
Step 2:
We need to access Web API in the Index() action method using HttpClient as
shown below. Learn about HttpClient in detail here.
students = readTask.Result;
}
else //web api sent error response
{
//log response status here..
students = Enumerable.Empty<StudentViewModel>();
64
Step 3:
Now, we need to add Index view. Right click in the Index action method and
select Add View.. option. This will open Add View popup as shown below.
Now, select List as template and StudentViewModel as Model class as below
(we already created StudentViewModel in the previous section).
Add
View in ASP.NET MVC
Click Add to add Index view in the Views folder. This will generate following
Index.cshtml.
Index.cshtml
@model IEnumerable<WebAPIDemo.Models.StudentViewModel>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
65
<th>
@Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
@Html.DisplayNameFor(model => model.LastName)
</th>
<th></th>
</tr>
</table>
Remove Details link from the View because we will not create Details page
here.
Now, run the application and you will see list of students in the browser as
shown below.
66
Student List View
Display Error
We have successfully displayed records in the view above but what if Web API
returns error response?
Index.cshtml
@model IEnumerable<WebAPIDemo.Models.StudentViewModel>
67
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
@Html.DisplayNameFor(model => model.LastName)
</th>
<th></th>
</tr>
</table>
In the above view, we have added @Html.ValidationSummary(true, "", new { @class
= "text-danger" }) in the last row of the table. This is to display error message
if Web API returns error response with the status other than 200 OK.
Please notice that we have added model error in the Index() action method in
StudentController class created in the step 2 if Web API responds with the
status code other than 200 OK.
68
So now, if Web API returns any kind of error then Student List view will display
the message below.
In the next section, we will consume Post method to create a new record in
the underlying data source by clicking on Create New link in the above view.
We already created Web API with Post method in the Implement Post Method section shown
below.
69
//Get action methods of the previous section
public IHttpActionResult PostNewStudent(StudentViewModel student)
{
if (!ModelState.IsValid)
return BadRequest("Not a valid model");
ctx.SaveChanges();
}
return Ok();
}
}
In the above Web API, PostNewStudent method will handle HTTP POST
request http://localhost:64189/api/student . It will insert new record in the database using
Entity Framework and will return 200 OK response status.
The following is a Web API + MVC project structure created in the previous sections. We will
add necessary classes in this project.
70
Web API Project
We have already created the following StudentViewModel class under Models folder.
Step 1:
First, we need to add action method "create" which will render "Create New Student" view where
user can enter data and submit it. We have already created StudentController class in the previous
section to display student list view. Here, add "create" action method to render "Create New
Student" view shown below.
return View();
}
create.cshtml
@model WebApiDemo.Models.StudentViewModel
@{
ViewBag.Title = "Create New Student - MVC";
Layout = "~/Views/Shared/_Layout.cshtml";
}
72
<h2>Create New Student</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class =
"control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.FirstName, new { htmlAttributes = new
{ @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class
= "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LastName, htmlAttributes: new { @class =
"control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.LastName, new { htmlAttributes = new {
@class = "form-control" } })
@Html.ValidationMessageFor(model => model.LastName, "", new { @class
= "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
In the above view, Html.BeginForm() generates HTML form tag <form>
action="/Student/Create" method="post" </form> which will send post request when user
clicks on the create button.
Now, run the project and navigate to http://localhost:64189/student/create . It will display the
simple data entry view as shown below.
73
Create New Student View
As soon as the user enters student data and clicks on the Create button in the above view, it will
send Post request to the Student MVC controller. To handle this post request add HttpPost action
method "create" as shown below.
return View();
}
[HttpPost]
public ActionResult create(StudentViewModel student)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/student");
//HTTP POST
74
var postTask = client.PostAsJsonAsync<StudentViewModel>("student",
student);
postTask.Wait();
return View(student);
}
}
As you can see in the above HttpPost action method create(), it uses HttpClient to send HTTP
POST request to Web API with StudentViewModel object. If response returns success status then
it will redirect to the list view. Visit HttpClient section to learn more about it.
75
Create a New Student
Now, on the click of create button above, it will insert a new record in the DB and redirect to the
list view as shown below.
76
Redirect to Student List View
Also, the above create view will display an error message if Web API sends error response as
shown below.
77
Display Error Message
So in this way we can consume Post method of Web API to execute HTTP POST request to create
a new record.
We already created Web API with Put method that handles HTTP PUT request
in the Implement Put Method section as below.
78
public IHttpActionResult Put(StudentViewModel student)
{
if (!ModelState.IsValid)
return BadRequest("Not a valid data");
if (existingStudent != null)
{
existingStudent.FirstName = student.FirstName;
existingStudent.LastName = student.LastName;
ctx.SaveChanges();
}
else
{
return NotFound();
}
}
return Ok();
}
}
We created Student List view in the previous section as below. In the below
view there is an edit link for each record to edit that particular record. We will
handle edit functionality in this section.
79
Student List View
The following is a Web API + MVC project structure created in the previous
sections. We will add necessary classes in this project.
80
Web API Project
Step 1:
In the above Student List view, when user clicks on the Edit link it will send
HTTP GET request http://localhost:64189/student/edit/{id} to the MVC
81
controller. So, we need to add HttpGet action method "Edit" in the
StudentController to render an edit view as shown below.
return View();
}
student = readTask.Result;
}
}
return View(student);
}
}
As you can see above, Edit() action method includes id parameter. This id
parameter will be bound to the query string id parameter. We use this id to
get a student record from the database using HttpClient and pass the student
record in the edit view. Visit HttpClientsection to know more about it.
Step 2:
Create edit view by right clicking in the above Edit action method and
select Add View.. This will open Add View popup as shown below.
82
Add
View in ASP.NET MVC
In the Add View popup, select Edit template and StudentViewModel as a model
class as shown above. Click Add button to generate Edit.cshtml view in the
Views > Student folder as shown below.
Edit.cshtml
@model WebApiDemo.Models.StudentViewModel
@{
ViewBag.Title = "Edit Student - MVC";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit Student</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
<div class="form-group">
@Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class =
"control-label col-md-2" })
83
<div class="col-md-10">
@Html.EditorFor(model => model.FirstName, new { htmlAttributes = new
{ @class = "form-control" } })
@Html.ValidationMessageFor(model => model.FirstName, "", new { @class
= "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.LastName, htmlAttributes: new { @class =
"control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.LastName, new { htmlAttributes = new {
@class = "form-control" } })
@Html.ValidationMessageFor(model => model.LastName, "", new { @class
= "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
In the above view, Html.BeginForm() generates HTML form tag <form>
action="/Student/edit" method="post" </form> which will send post request
when user clicks on the save button.
Now, it will display following Student List view when you run the project by
pressing Ctrl + F5.
84
Student List View
It will display following edit view when you click on the Edit link in the above
view.
85
Edit View
Now, implement HttpPost Edit action method which will be executed when
user clicks on the Save button above.
Step 3:
Add HttpPost action method in StudentController of MVC which will send HTTP
PUT request to Web API to update current record.
86
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/");
//HTTP GET
var responseTask = client.GetAsync("student?id=" + id.ToString());
responseTask.Wait();
student = readTask.Result;
}
}
return View(student);
}
[HttpPost]
public ActionResult Edit(StudentViewModel student)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/student");
//HTTP POST
var putTask = client.PutAsJsonAsync<StudentViewModel>("student", student);
putTask.Wait();
return RedirectToAction("Index");
}
}
return View(student);
}
}
As you can see above, HttpPost Edit action method uses HttpClient to send
HTTP PUT request to the Web API with updated student record.
Visit HttpClient section to learn more about it.
So in this way we can consume Put method of Web API to execute HTTP PUT
request to edit an existing record.
Next, consume Delete method of Web API to delete a record in the data
source.
We have already created Web API with Delete method that handles HTTP
DELETE request in the Implement Delete Method section as below.
ctx.Entry(student).State = System.Data.Entity.EntityState.Deleted;
ctx.SaveChanges();
}
return Ok();
}
}
The following is a Student list view created in the Consuming get method in
MVC section. Here, we will implement delete functionality when user clicks on
the Delete link in the following UI.
88
Student List View
When user clicks on the Delete link in the above UI, it sends HTTP Get
request http://localhost:64189/student/delete/{id} to the Student
controller with the current id parameter. So let's implement delete
functionality by consuming Web API Delete method.
Step 1:
89
Example: Implement HttpGet Delete method
public class StudentController : Controller
{
// GET: Student
public ActionResult Index()
{
IList<StudentViewModel> students = null;
students = readTask.Result;
}
}
return View(students);
}
//HTTP DELETE
var deleteTask = client.DeleteAsync("student/" + id.ToString());
deleteTask.Wait();
return RedirectToAction("Index");
}
}
return RedirectToAction("Index");
}
}
As you can see, Delete() action method above uses HttpClient to send HTTP
DELETE request with the current id parameter. The Web API controller shown
90
in the first code example, will handle this DELETE request and delete the
record from the data source. Visit HttpClient section to learn more about it.
So, in this way you can consume Delete method of Web API in ASP.NET MVC.
Let's see how to consume Web API using HttpClient in the console application.
We will consume the following Web API created in the previous section.
namespace MyWebAPI.Controller
{
public class StudentController : ApiController
{
public IHttpActionResult GetAllStudents(bool includeAddress = false)
{
IList<StudentViewModel> students = null;
91
}
}).ToList<StudentViewModel>();
}
if (students.Count == 0)
{
return NotFound();
}
return Ok(students);
}
ctx.SaveChanges();
}
return Ok();
}
if (existingStudent != null)
{
existingStudent.FirstName = student.FirstName;
existingStudent.LastName = student.LastName;
ctx.SaveChanges();
}
else
{
return NotFound();
}
}
return Ok();
}
92
public IHttpActionResult Delete(int id)
{
if (id <= 0)
return BadRequest("Not a valid studet id");
ctx.Entry(student).State = System.Data.Entity.EntityState.Deleted;
ctx.SaveChanges();
}
return Ok();
}
}
}
Step 1:
Step 2:
Open NuGet Package Manager console from TOOLS -> NuGet Package Manager -> Package
Manager Console and execute following command.
Install-Package Microsoft.AspNet.WebApi.Client
Step 3:
Now, create a Student model class because we will send and receive Student object to our Web
API.
namespace HttpClientDemo
{
class Program
{
static void Main(string[] args)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:60464/api/");
//HTTP GET
var responseTask = client.GetAsync("student");
responseTask.Wait();
First, we have created an object of HttpClient and assigned the base address of our Web API. The
GetAsync() method sends an http GET request to the specified url. The GetAsync() method is
asynchronous and returns a Task. Task.wait() suspends the execution until GetAsync() method
completes the execution and returns a result.
Once the execution completes, we get the result from Task using Task.result which is
HttpResponseMessage. Now, you can check the status of an http response using
IsSuccessStatusCode. Read the content of the result using ReadAsAsync() method.
Thus, you can send http GET request using HttpClient object and process the result.
94
Send POST Request
Similarly, you can send HTTP POST request using PostAsAsync() method of HttpClient and
process the result the same way as GET request.
The following example send http POST request to our Web API. It posts Student object as json
and gets the response.
namespace HttpClientDemo
{
class Program
{
static void Main(string[] args)
{
var student = new Student() { Name = "Steve" };
95
Method Name Description
GetByteArrayAsync Sends a GET request to the specified Uri and returns the response body as a byte array in an asynch
GetStreamAsync Sends a GET request to the specified Uri and returns the response body as a stream in an asynchron
GetStringAsync Sends a GET request to the specified Uri and returns the response body as a string in an asynchrono
PostAsync Sends a POST request to the specified Uri as an asynchronous operation.
PostAsJsonAsync Sends a POST request as an asynchronous operation to the specified Uri with the given value serial
PostAsXmlAsync Sends a POST request as an asynchronous operation to the specified Uri with the given value seriali
PutAsync Sends a PUT request to the specified Uri as an asynchronous operation.
PutAsJsonAsync Sends a PUT request as an asynchronous operation to the specified Uri with the given value serializ
PutAsXmlAsync Sends a PUT request as an asynchronous operation to the specified Uri with the given value serializ
DeleteAsync Sends a DELETE request to the specified Uri as an asynchronous operation.
There are many IoC containers available for dependency injection such as
Ninject, Unity, castleWidsor, structuremap etc. Here we will use Ninject for
dependency injection.
The following is our sample Web API that uses instance of a class that
implements IRepository.
Example: Repository
public interface IRepository
{
IList<Student> GetAll();
96
}
First of all, you need to install Ninject library for Web API using NuGet. To do
this, right click on your project in the solution explorer -> click on Manage
NuGet packages... This will open NuGet popup. Now search for
webapicontrib in the search box as shown below.
As you can see, this will list all the IoC containers for Web API. Select
WebApiContrib.IoC.Ninject and click Install.
97
Web API Configuration
98
In order to use dependency injection with Web API, we need to create a
resolver class that implements IDependencyResolver interface. Here, we have
created NinjectResolver class in Infrastructure folder in our Web API project
as shown below.
Example: DI Resolver
public class NinjectResolver : IDependencyResolver
{
private IKernel kernel;
99
}
}
Now, we need to configure NijectResolver with Web API in the WebApiConfig
class as shown below.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
As you can see above, HttpConfiguration.DependencyResolver is set to
NinjectResolver. So now, Web API will use NinjectResolver class to create the
objects it needs.
IIS Hosting
Self Hosting
IIS Hosting
Web API can be hosted under IIS, in the same way as a web application. You
have learned to create a Web API in the previous section. As you have seen
there, a Web API is created with ASP.NET MVC project by default. So, when
you host your MVC web application under IIS it will also host Web API that
uses the same base address.
Self Hosting
100
You can host a Web API as separate process than ASP.NET. It means you can
host a Web API in console application or windows service or OWIN or any other
process that is managed by .NET framework.
First of all, create a console project in Visual Studio 2012 for Desktop (or latter
version).
101
Open NuGet Manager
In the Manage NuGet Packages window, select Online option in left pan and
search for web-api. This will list all the packages for Web API. Now, look
for Microsoft ASP.NET Web API 2.2 Self Host package and click Install.
102
Install Web API Self Host Package
Click on Accept button in the License Acceptance window.
103
Accept License Agreement
This will install the package into your project.
104
Install Web API self Hosting Package
Now write the following code in the Main() method of Program class.
105
Example: MessageHandler
class MyWebAPIMessageHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken cancellationToken)
{
var task = new Task<HttpResponseMessage>(() => {
var resMsg = new HttpResponseMessage();
resMsg.Content = new StringContent("Hello World!");
return resMsg;
});
task.Start();
return task;
}
}
Thus, you can create simple console application and host simple Web API that
returns "Hello World!" to every request.
Response in Browser
106
Example: Web API Controller
public class HomeController : ApiController
{
public string Get() {
return "Hello World!";
}
Now, run the console application by pressing Ctrl + F5. Open the browser and
enter http://localhost:1234/api or http://localhost:1234/api?name=steve and see the
result as shown below.
107
Web API Response
108