In the previous blog post I demonstrated how to get started with the ASP.NET Web API and retrieve some products data from the Northwind database. Something that was really easy to do But quite often we want to update data just as much as we want to retrieve it.
A quick recap of REST and HTTP methods used.
The convention for REST service as defined by Roy Fielding is to use different HTTP methods to signify our intent with the HTTP request. The HTTP GET method, by far the most commonly used one on the internet, is used to retrieve data. This should be a completely save action and have no side effects whatsoever for the client to worry about. When we start changing data we start using other HTTP methods. The following table are the most commonly used HTTP methods and the database CRUD actions they to.
HTTP Method | CRUD Action |
Get | Select |
Post | Insert |
Put | Update a complete entity |
Patch | Update a partial entity |
Delete | Delete an entity |
Quite simple right? And even the Patch method isn’t used that often, in most cases just 4 methods are used.
Implementing update methods in the ASP.NET Web API
As I explained in my last post the ASP.NET Web API uses convention over configuration and by convention is to create an ApiController with functions where the name starts with the HTTP method to support. We can do things differently with attributes if we want to but for now lets just stick to the convention.
Adding new products to the database.
As we have just seen creating new data is done with a POST method so we need to implement a Post() function in our ProductsController. Doing so is quite easy:
1: public class ProductsController : ApiController
2: {
3: private NorthwindEntities _db = new NorthwindEntities();
4:
5: // GET /api/<controller>
6: public IEnumerable<Product> Get()
7: {
8: return _db.Products.ToList();
9: }
10:
11: // GET /api/<controller>/5
12: public Product Get(int id)
13: {
14: return _db.Products.Single(p => p.ProductID == id);
15: }
16:
17: // POST /api/<controller>
18: public void Post(Product product)
19: {
20: _db.AddToProducts(product);
21: _db.SaveChanges();
22: }
23:
24: protected override void Dispose(bool disposing)
25: {
26: if (disposing && _db != null)
27: {
28: _db.Dispose();
29: _db = null;
30: }
31: base.Dispose(disposing);
32: }
33: }
Of course in reality a Post action would be somewhat more complicated. For starters we would need some error handling in case the data was invalid. Another issue is that, if everything goes well, we are just returning a 200 Ok status where we should be returning a 201 Created status with the location of the newly created resource. But for now this is good enough.
We still need a way to test this and the perfect tool to monitor and test HTTP related traffic if Fiddler. Using Fiddler we can POST a new product, in this case the ASP.NET Web API itself, to the server.
And as we can see when we check the database or use the GET method in the correct URL the new record is inserted.
There are two interesting things to note here.
- All I had to do is have a function were the name starts with Post and it is automatically called when an HTTP POST is received.
- The function parameter is of type Product and the ASP.NET Web API does the proper deserialization for us.
How easy can they make things?
And implementing PUT and DELETE would work in the same way.
The “complete” ApiController looks like this:
1: public class ProductsController : ApiController
2: {
3: private NorthwindEntities _db = new NorthwindEntities();
4:
5: // GET /api/<controller>
6: public IEnumerable<Product> Get()
7: {
8: return _db.Products.ToList();
9: }
10:
11: // GET /api/<controller>/5
12: public Product Get(int id)
13: {
14: return _db.Products.Single(p => p.ProductID == id);
15: }
16:
17: // POST /api/<controller>
18: public void Post(Product product)
19: {
20: if (ModelState.IsValid)
21: {
22: _db.AddToProducts(product);
23: _db.SaveChanges();
24: }
25: }
26:
27: // PUT /api/<controller>/5
28: public void Put(int id, Product product)
29: {
30: var orgProduct = _db.Products.Single(p => p.ProductID == id);
31: // Copy properties from product to orgProduct
32: _db.SaveChanges();
33: }
34:
35: // DELETE /api/<controller>/5
36: public void Delete(int id)
37: {
38: var product = _db.Products.Single(p => p.ProductID == id);
39: _db.Products.DeleteObject(product);
40: _db.SaveChanges();
41: }
42:
43: protected override void Dispose(bool disposing)
44: {
45: if (disposing && _db != null)
46: {
47: _db.Dispose();
48: _db = null;
49: }
50: base.Dispose(disposing);
51: }
52: }
Enjoy!
[f1]
[f2]