In the first part, we learned how to setup a ASP.NET 4.0 WCF (file-extension less) service and the basics on using jQuery’s $.getJSON() method to call a service implementing the GET method. Now, we are going to review all the HTTP methods commonly found in a RESTful api (GET, POST, PUT, and DELETE). The code below targets the project created in step 1, which I’ll update in my next post. Each HTTP methods/verb is used to describe a process in a CRUD transaction, so I tried to keep things simple by naming accordingly. Everything below was written in Visual Studio 2010 with .NET 4.0.
RESTful HTTP Methods ( GET / POST / PUT / DELETE )
Before we explore the HTTP methods, remember the following rules while building your WCF Services.
- The UriTemplate can only use parameters of type string
- Uri Templates are very flexible and you can build your own standard syntax for your api.
Sample Uri Templates for .svc-less function calls[WebGet(UriTemplate = "Products/{name}")] public Product GetProduct(string name) // URL = "/InventoryService/Products/ProductXYZ" [WebGet(UriTemplate = "Products/Product({name})")] public Product GetProduct(string name) // URL = "/InventoryService/Products/Product(ProductXYZ)" [WebGet(UriTemplate = "Products/API.Service?Product={name}")] public Product GetProduct(string name) // URL = "/InventoryService/Products/API.Service?Product=ProductXYZ" - When passing multiple objects to a service, you must wrap the objects.
** Difference sending 1 object vs 2 objects **// Sending 1 Object (No Wrapping). [WebInvoke(UriTemplate = "Products/API.Service?Product={productName}", Method = "POST")] public string APIGet(string productName, Product product1) // Sending 2 Objects (Wrapping) // Added "BodyStyle = WebMessageBodyStyle.WrappedRequest". [WebInvoke(UriTemplate = "Products/API.Service?Product={productName}", Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest )] public string APIGet(string productName, Product product1, Product product2)jQuery Ajax Call (Sending 1 object vs 2 objects)
// Common Objects to use in examples below var Product1 = {}; Product1.Name = 'Name1'; Product1.Description = 'Desc1'; Product1.Price = 1.0; Product1.Quantity = 1; Product1.IsDiscontinued = false; var Product2 = {}; Product2.Name = 'Name2'; Product2.Description = 'Desc2'; Product2.Price = 2.0; Product2.Quantity = 2; Product2.IsDiscontinued = false; // Sending 1 Object (No Wrapping). $.ajax({ type: 'POST', url: '/InventoryService/Products/API.Service?Product=ProductXYZ', contentType: 'application/json; charset=utf-8', dataType: 'json', data: JSON.stringify(Product1), // Here we are sending the 1 object, no wrapper. success: function (response) { // Do Something } }); // Sending 2 Objects (Wrapping) // Here we are creating a new jsonRequest object that wraps our 2 objects that we want to send to the server. jsonRequest = { 'product1': Product1, 'product2': Product2 }; $.ajax({ type: 'POST', url: '/InventoryService/Products/API.Service?Product=ProductXYZ', contentType: 'application/json; charset=utf-8', dataType: 'json', data: JSON.stringify(jsonRequest), // Here we are sending a object that wraps our 2 product objects. success: function (response) { // Do Something } });
GET / POST / PUT / DELETE WCF Services and their jQuery Ajax Calls
GET Method
Service
[WebGet(UriTemplate = "Products/{name}")]
[OperationContract]
public Product GetProduct(string name)
{
// Get a Product
}
jQuery Call
var name = 'ProductXYZ';
$.ajax({
type: 'GET',
url: '/InventoryService/Products/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: '',
success: function (response)
{
// Do Something
}
});
// Alternative to $.ajax for a GET request is using $.getJSON.
$.getJSON('/InventoryService/' + name, '', function (result) { // Do Something });
This is probably the simplest service call to issue, but the amazing jQuery team made the process even easier with the getJSON() call that wraps up a ajax() GET request. Notice the svc-less call above, there’s no ugly “.svc” telling your consumers… Hay, I’m using WCF!!!
POST Method
Service
[WebGet(UriTemplate = "Products/{name}", Method = "POST")]
[OperationContract]
public Product GetProduct(string name, Product product)
{
// Insert New Product
}
jQuery Call
var name = 'ProductXYZ';
var Product = {};
Product.Name = 'ProductXYZ';
Product.Description = 'Product XYZ Description';
$.ajax({
type: 'POST',
url: '/InventoryService/Products/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(Product),
success: function (response)
{
// Do Something
}
});
This has always been my go to method for sending data to a service, but according to a few RESTful people this method is only supposed to be used for inserts. I’m not really sure how “firm” this rule is, so I decided to do all Inserts and Updates with the POST method, since I almost always handle this in the same function call in my DAL. In addition to posting my Object to the service, I also include the primary key (“PK”) in the service path so I can use the IIS logs to show who touched a specific record.
PUT Method
Service
[WebInvoke(UriTemplate = "Products/{name}", Method = "PUT")]
[OperationContract]
public Product GetProduct(string name)
{
// Update Product
}
jQuery Call
var name = 'ProductXYZ';
var Product = {};
Product.Name = 'ProductXYZ';
Product.Description = 'Product XYZ Description';
$.ajax({
type: 'PUT',
url: '/InventoryService/Products/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(Product),
success: function (response)
{
// Do Something
}
});
I don’t use this much, but when I do the calls look exactly the same as a POST except for the change in request type.
DELETE Method
Service
[WebGet(UriTemplate = "Products/{name}", Method = "DELETE")]
[OperationContract]
public bool GetProduct(string name)
{
// Delete Product
}
jQuery Call
var name = 'ProductXYZ';
$.ajax({
type: 'DELETE',
url: '/InventoryService/Products/' + name,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: '',
success: function (response)
{
// Do Something
}
});
Since I always like “confirmation” when something has been done, I always return a boolean from my delete services. This allows me to confirm something was able to be deleted, if you expect to have various failure states you might want to consider using a string return type to provide a detailed “error” message whey the request failed (e.g. “Successfully Deleted”, “You don’t have permission.”, “Product is associated with other orders.”).
Nathan and I ran out for a few hours on Monday night to catch a few perch, and he ended up finding a few HUGE sandcrabs that would make perfect bait for Corbina and Spot Fin Croaker!!!