Making a REAL web application with ASP.NET Web API Part 2, the Controller
7/31/2012Slow tuesday, so I thought I would throw up what my controller looks like real quick and briefly explain what is going on. This is part 2 of and 3-4 part post on how to create a real web application using asp.net web api, handlebar.js, ajax, and asp.net MVC4! You can get to part 1 here.
So without further ado: setting up the web api controller. In my project I created a new folder called API in the root directory. From there I right-clicked and selected add > controller. For the controller template, select the Empty Web Api Controller.
A note on where you place your controllers in ASP.NET MVC: It does not matter. You can have all your controllers (API or otherwise) sitting in the controllers folder, but for the sake of organization, I placed mine in a seperate folder.
So with the Web Api we need to implement four HTTP Verbs: GET POST PUT & DELETE. Technically we will be doing five, a GET to retrieve all of them and a GET to retrieve just one. First lets took at how we set up the empty controller to be able to talk to our database.
public class OnusesController : ApiController { private OnusDb db; public OnusesController() { db = new OnusDb(); db.Configuration.ProxyCreationEnabled = false; } }
So here I created a constuctor that will take the private field, db, that I created and create a new instance of OnusDb. OnusDb is my Database Context class. I set ProxyCreationEnabled to false to disable change tracking and lazy-loading. For this web api, I really dont have any need to Entity Framework to track the changes of my POCOs. For more info on this check this article.
Implementing the get requests is very easy in a web api controller:
public IEnumerableGetAllOnuses() { return db.Onuses; } public Onus getOnus(int id) { var onus = db.Onuses.Find(id); if (onus == null) { throw new HttpResponseException( Request.CreateResponse(HttpStatusCode.NotFound)); } return onus; }
The first one returns a list of all of the objects, and the second one grabs a single one based off of the object Id property.
POST is fairly simple:
public HttpResponseMessage PostOnus(Onus onus) { if (ModelState.IsValid) { db.Onuses.Add(onus); db.SaveChanges(); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, onus); response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = onus.Id })); return response; } else { return Request.CreateResponse(HttpStatusCode.BadRequest); } }
One thing I am doing here is adding the url of the newly created object in the return header. This is in there in case an end user of the API wanted to use this location to spin off some more logic.
Now for PUT and DELETE:
public HttpResponseMessage PutOnus(int id, Onus onus) { if (ModelState.IsValid && id == onus.Id) { db.Entry(onus).State = EntityState.Modified; try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { return Request.CreateResponse(HttpStatusCode.NotFound); } return Request.CreateResponse(HttpStatusCode.OK, onus); } else { return Request.CreateResponse(HttpStatusCode.BadRequest); } } public HttpResponseMessage DeleteOnus(int id) { Onus onus = db.Onuses.Find(id); if (onus == null) { return Request.CreateResponse(HttpStatusCode.NotFound); } db.Onuses.Remove(onus); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { return Request.CreateResponse(HttpStatusCode.NotFound); } return Request.CreateResponse(HttpStatusCode.OK, onus); }
One thing to note here it the type of exception I am catching here. It is unique to the DbContext and is thrown when the result of SaveChanges effects no rows, but it should have. Can read more about it here.
Regarding the naming convention here:
ASP.NET Web Api looks to a naming conventions by default. If you set up a new api controller with it scaffolded to have you verbs in place, they will all be named after those verbs (GET, PUT, POST, DELETE). As long as your method starts with that name, you are good to go. So PostHolyCrap() would be recognized as a POST. If for some reason you need to name them without being tied to these conventions, all you need to do is decorate the method with [HttpPost] (or [HttpPut], etc ...)
So that is all there is to it the have a functional web api that passes back what an api should: response messsages! In the next post (maybe tonight, maybe in a couple days) I will show you how to talk to this api using javascript/jQuery and how to bind the results to templates using handlebars.js
Cheers
{David Stanley}