Parameter Binding

by Sachin Singh


Posted on Saturday, 23 May 2020

Tags: Parameter Binding in Web API FromBody and FromUri attributes in web api use of [FromUri] attribute use of [FromBody] attribute

A web API method may or may not contain parameters for example consider the below example.


   namespace ParameterBinding.Controllers
   {
    public class EmployeeController : ApiController
      {
        public HttpResponseMessage Get()
        {
            try
            {
                using(TestDBContext db=new TestDBContext() ){

                    var emps = db.Employees.ToList();
                    if(emps!=null){
                        return Request.CreateResponse(HttpStatusCode.OK, emps);
                    }
                    return Request.CreateErrorResponse(HttpStatusCode.NoContent,"No employee found");
                }

            }
            catch
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError,"an Error occured");
            }
        }

        public HttpResponseMessage Post(Employee employee)
        {
            try
            {
                using (TestDBContext db = new TestDBContext())
                {
                    db.Employees.Add(employee);
                    db.SaveChanges();

                    var message = Request.CreateResponse(HttpStatusCode.Created, employee);
                    message.Headers.Location = new Uri(Request.RequestUri + "/" +
                        employee.Id.ToString());

                    return message;
                }
            }
            catch (Exception ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
            }
        }

        public void Put(int id, Employee employee)
        {
            using (TestDBContext db = new TestDBContext())
            {
                Employee emp = db.Employees.FirstOrDefault(e => e.Id == id);

                emp.Name = employee.Name;
                emp.Salary = employee.Salary;
                db.SaveChanges();
             }
         }
       }
    }

Here,
  • The First method is parameter-less which returns all the employees from the database, so the client does not need to pass any data while issuing the request.
  • The second method has a complex type parameter and expects employee object to process the request, it actually saves employee information into the database, so the client needs to pass Employee data while issuing the request.
  • The third method has two parameters, the first parameter is of primitive type(int) and the second parameter is a complex type (Employee), the method updates the Employee's information into the database, so the client has to pass an Employee's Id and other data which has to update.

In short, whenever a request is issued to update, create or delete a resource on the server, the required data is also sent.

Now, the client has two options to pass the data while issuing the request.
  1. In the URI as routed data or query string.
  2. In the request body.

Let's issue a post request to add an employee into the database.

Post Request
Post Request
Post Request
Parameter Binding

As you can see ,the employee data is being passed in the request body. On the server side ,method parameters gets mapped with the incoming data without any external work.

Similarly ,look at the PUT request. Here the Id is being passed as routed data and employee's data in the request body. But ,on the server side the Id and Employee's data get easily mapped to method parameters.

Post Request
Put Request
Put Request
Parameter Binding

So ,we can conclude that web api maps the data in the request to the method parameters in the controller. This process is called as Parameter Binding.

Web API uses default convention for binding parameters.
  1. If a parameter is a primitive type like int, bool, double, etc, web API tries to get the value from the URI(either from the Routed data or query string).
  2. If the parameter is a complex type like Employee, Customer, etc then web API tries to get the value from the request body.

Now again take a look at the Put method
  • It has two parameters Id and Employee, Id is of primitive type while Employee is a complex type.
  • While issuing the request the id value is specified in the URI as routed data and employee data is specified in the request body.
That is why web api successfully mapped the data from the request to the method parameters.

Now let's do the opposite meaning pass the Id in the request body and Employee data as query string in the URI and test what happens.

Put Request
Put request

we are getting the error, Method Not Allowed.

Put Request
Error

This means web api fails in mapping parameters, when we don't pass the parameter's value as per web api expectation.

Can't we change the default Parameter Binding Process

we can change the default parameter binding process by using [FromUri] and [FromBody] attributes.
  1. [FromBody] - the attribute forces web api to get the value from the request body.
  2. [FromUri]- the attribute forces web api to get the value from URI (Either from routed data or querystring)

so , modify the put method like below.


      public void Put([FromBody]int id,[FromUri]Employee employee)
        {
            using (TestDBContext db = new TestDBContext())
            {
                Employee emp = db.Employees.FirstOrDefault(e => e.Id == id);

                emp.Name = employee.Name;
                emp.Salary = employee.Salary;
                db.SaveChanges();
            }
        }

Notice in the example above
  1. We have decorated id parameter with [FromBody] attribute, this forces Web API to get it from the request body
  2. We have decorated employee parameter with [FromUri] attribute, this forces Web API to get employee data from the URI (i.e Route data or Query String)

Remember, when we were passing the value of id in the request body and Employee's data in the form of the query string in the URI, we were getting errors. But after decorating the method parameters with appropriate attributes if we re-issue the same request as below.

Here is the request from Fiddler
  1. Notice, Employee data is being sent in the URI using the query string parameters
  2. The id is being sent in the request body .

Put Request
Put request

Now, issue the request, you will find that the update succeeds as expected.