Using Custom Action Names in ASP.NET Web API

Introduction

By default Web API action methods use the same HTTP method name that they are serving. For example, to deal with the HTTP GET method the Web API has the Get() action method. However, you may want to customize these action method names for the sake of better readability. There are several ways in which you can customize these action method names. This article discusses them with an example of each.

Creating a Sample Web API

To illustrate how Web API action method names can be customized you will first build a simple Web API that performs CRUD operations on the Customers table of the Northwind database. So, begin by creating a new ASP.NET MVC 4 project by selecting the Web API project template. Then add ADO.NET Entity Framework Data Model for the Customers table. The following figure shows the Customers data model class in the Visual Studio designer.

The Customers data model class
The Customers data model class

Although the Customers table contains many columns, you will use only four in this example, viz. CustomerID, CompanyName, ContactName and Country.

Next, change the default Web API controller name from ValuesController to CustomerController and add the following action methods to it:

namespace WebAPICustomNamesDemo.Controllers
{
    public class CustomerController : ApiController
    {
        NorthwindEntities db = new NorthwindEntities();

        public IEnumerable<Customer> Get()
        {
            var data = from c in db.Customers
                       orderby c.CustomerID
                       select c;
            return data.ToList();
        }

        public Customer Get(string id)
        {
            var data = from c in db.Customers
                       where c.CustomerID==id
                       select c;
            return data.SingleOrDefault();
        }

        public string Post(Customer obj)
        {
            db.Customers.Add(obj);
            db.SaveChanges();
            return "Customer added successfully!";
        }

        public string Put(string id, Customer obj)
        {
            var data = from c in db.Customers
                       where c.CustomerID == id
                       select c;
            Customer temp = data.SingleOrDefault();
            temp.CompanyName = obj.CompanyName;
            temp.ContactName = obj.ContactName;
            temp.Country = obj.Country;
            db.SaveChanges();
            return "Customer updated successfully!";
        }

        public string Delete(string id)
        {
            var data = from c in db.Customers
                       where c.CustomerID == id
                       select c;
            Customer temp = data.SingleOrDefault();
            db.Customers.Remove(temp);
            db.SaveChanges();
            return "Customer deleted successfully!";
        }
    }
}

The above action methods perform CRUD operations as listed below:

  • Get() : The Get() method returns all the Customers from the Customers table as a generic List.
  • Get(id) : The Get(id) method returns a single Customer object for the specified CustomerID.
  • Post() : The Post() method inserts a new Customer in the Customers table.
  • Put() : The Put() method updates an existing Customer from the database whose CustomerID matches the specified id.
  • Delete() : The Delete() method deletes a Customer record from the database based on the specified CustomerID.

To test the Customer Web API, you also need to create a view that invokes these action methods via jQuery $.ajax(). So, right click on the Index() action method of the HomeController class and select Add View. The following figure shows how the Index view looks:

The Index View
The Index View

As you can see the Index view consists of a drop-down list and a few textboxes. Selecting a CustomerID from the drop-down list shows its details in the textboxes. You can then perform insert, update or delete operations on the data. The following code shows the jQuery code that is responsible for making Ajax calls.

        $(document).ready(function () {

            //select all
            var options = {};
            options.url = "/api/customer";
            options.type = "GET";
            options.contentType = "application/json";
            options.success = function (customers) {
                for (var i = 0; i < customers.length; i++) {
                    $("#customeridlist").append("<option>" + customers[i].CustomerID + "</option>");
                }
            };
            options.error = function (err) { alert(err.statusText); };
            $.ajax(options);

            //select by id
            $("#customeridlist").change(function () {
                var options = {};
                options.url = "/api/customer/" + $("#customeridlist").val();
                options.type = "GET";
                options.contentType = "application/json";
                options.success = function (customer) {
                    $("#companyname").val(customer.CompanyName);
                    $("#contactname").val(customer.ContactName);
                    $("#country").val(customer.Country);
                };
                options.error = function (err) { alert(err.statusText); };
                $.ajax(options);
            });

            //insert
            $("#insert").click(function () {
                var options = {};
                options.url = "/api/customer";
                options.type = "POST";
                options.data = JSON.stringify({
                    "CustomerID": $("#customerid").val(),
                    "CompanyName": $("#companyname").val(),
                    "ContactName": $("#contactname").val(),
                    "Country": $("#country").val()
                });
                options.dataType = "json";
                options.contentType = "application/json";
                options.success = function (msg) {
                    alert(msg);
                };
                options.error = function (err) { alert(err.statusText); };
                $.ajax(options);
            });


            //update
            $("#update").click(function () {
                var options = {};
                options.url = "/api/customer/" + $("#customeridlist").val();
                options.type = "PUT";
                options.data = JSON.stringify({
                    "CompanyName": $("#companyname").val(),
                    "ContactName": $("#contactname").val(),
                    "Country": $("#country").val()
                });
                options.dataType = "json";
                options.contentType = "application/json";
                options.success = function (msg) {
                    alert(msg);
                };
                options.error = function (err) { alert(err.statusText); };
                $.ajax(options);
            });

            //delete
            $("#delete").click(function () {
                var options = {};
                options.url = "/api/customer/" + $("#customeridlist").val();
                options.type = "DELETE";
                options.contentType = "application/json";
                options.success = function (msg) {
                    alert(msg);
                };
                options.error = function (err) { alert(err.statusText); };
                $.ajax(options);
            });

        });

The code shown above essentially handles the click event handlers of the buttons. Inside all the event handlers you make an Ajax call to the Web API using the $.ajax() method. The url property of the options object sets the target URL and the type property sets the HTTP method. Notice that the above code uses URL as /api/customer and depending on the HTTP method (GET, POST, etc.) the appropriate Web API action method is invoked.

Creating Action Methods by Prefixing Them with HTTP Method

In the above example you used Web API action method names such as Get(), Post(), Put() and Delete(). However, these generic names may not convey the intended purpose of the respective method and you may want to make then more readable. Luckily, there is a way to customize them without any additional configuration. Web API framework will invoke the appropriate action method as long as your action method names begin with the HTTP method. For example, instead of Get() method you can use GetCustomers() to serve the GET requests. The following code shows all five action methods modified to use this pattern.

namespace WebAPICustomNamesDemo.Controllers
{
    public class CustomerController : ApiController
    {
        NorthwindEntities db = new NorthwindEntities();

        public IEnumerable<Customer> GetCustomers()
        {
	   ...
        }

        public Customer GetCustomerByID(string id)
        {
  	   ...
        }

        public string PostCustomer(Customer obj)
        {
	   ...
        }

        public string PutCustomer(string id, Customer obj)
        {
	   ...
        }

        public string DeleteCustomer(string id)
        {
	   ...
        }
    }
}

As you can see, the method names are now GetCustomers(), GetCustomerByID(), PostCustomer(), PutCustomer() and DeleteCustomer() respectively. Since all of them begin with the corresponding HTTP method name (Get, Post, Put and Delete), Web API can correctly invoke them.

Using Attributes to Specify HTTP Method and Action Method Mapping

You can change the Web API action method names to anything you want and use certain attributes to map them with the HTTP methods. This technique gives you total control on the action method names. The attributes that you use are [HttpGet], [HttpPost], [HttpPut] and [HttpDelete]. As you might have guessed, these attributes correspond to GET, POST, PUT and DELETE HTTP methods. The following code shows how to use these attributes:

namespace WebAPICustomNamesDemo.Controllers
{
    public class Customer3Controller : ApiController
    {
        NorthwindEntities db = new NorthwindEntities();

        [HttpGet]
        public IEnumerable<Customer> SelectAllCustomers()
        {
	   ...
        }

        [HttpGet]
        public Customer SelectCustomerByID(string id)
        {
	   ...
        }

        [HttpPost]
        public string AddCustomer(Customer obj)
        {
	   ...
        }

        [HttpPut]
        public string ModifyCustomer(string id, Customer obj)
        {
	   ...
        }

        [HttpDelete]
        public string RemoveCustomer(string id)
        {
	   ...
        }
    }
}

As you can see, the action method names nowhere include the HTTP method names but they are decorated with attributes such as [HttpGet] and [HttpPost]. This way , the Web API framework can map HTTP request with the appropriate action method.

Specifying Action Name Using [ActionName] Attribute

So far you never used any action method name in the URL while making the Ajax calls. Depending on the HTTP method, Web API framework automatically invokes the appropriate action method. However, if you wish, you can configure the default routing mechanism to explicitly include the action method names. To do so open the WebAPIConfig.cs file from the App_Start folder and modify it as shown below:

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

As you can see, the routeTemplate now includes the {action} parameter. Once you make this change you will need to use the action names in the URLs.

 //insert
$("#insert").click(function () {
  var options = {};
  options.url = "/api/customer/post";
  options.type = "POST";
  ...
  ...
  $.ajax(options);
});

In the above scenario you can use the [ActionName] attribute on top of action methods to specify some different name that can be used while calling them from the client side script. The following code shows how it can be used:

namespace WebAPICustomNamesDemo.Controllers
{
    public class Customer5Controller : ApiController
    {
        NorthwindEntities db = new NorthwindEntities();

        [ActionName("SelectAll")]
        public IEnumerable<Customer> Get()
        {
	   ...
        }

        [ActionName("SelectByID")]
        public Customer Get(string id)
        {
	   ...
        }

        [ActionName("Add")]
        public string Post(Customer obj)
        {
	   ...
        }

        [ActionName("Modify")]
        public string Put(string id, Customer obj)
        {
	   ...
        }

        [ActionName("Remove")]
        public string Delete(string id)
        {
	   ...
        }
    }
}

As you can see the Web API uses the default action method names but the [ActionName] attribute is used to specify the more meaningful name. From the view you will use these names (SelectAll, SelectByID, Add, Modify and Remove) while calling the Web API.

//insert
$("#insert").click(function () {
  var options = {};
  options.url = "/api/customer/add";
  options.type = "POST";
  ...
  ...
  $.ajax(options);
});

Summary

By default Web APIs use action method names that correspond to the HTTP method they deal with. However, you can customize this default behavior in various ways. You can use attributes such as [HttpGet] and [HttpPost] to map action methods with the corresponding HTTP method. If you configure Web API routing to include action names you can also use [ActionName] attribute to specify an action name.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read