Posted on 5/23/2020 10:38:07 AM by Admin

Parameter Binding

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 employee from the database, so the client do 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 an 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 have 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 simple 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 querystring in the URI ,we were getting error. But after decorating the method parameters with appropriate attribute if we re-issue the same request like below.

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

Put Request
Put request

When we execute the request the update succeeds as expected.