Developing RESTful Services in .NET


Published on

This presentation takes a very practical view of the various ways you can build RESTful services in the .NET Framework.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Developing RESTful Services in .NET

  1. 1. RESTful Services
  2. 2. Look at creating RESTful Services using .NET NOT covering Design Patterns Best Practises* Overture
  3. 3. REST Acronym? Representational State Transfer Source? Came about in 2000 doctoral dissertation of Roy Fielding
  4. 4. What is it? ROA – Resource Orientated Architecture WOA – Web Orientated Architecture Thanks Gartner for another TLA  It is a style NOT API Interface Official Standard A drop in replacement for SOAP
  5. 5. Setup Visual Studio - load restful service base Make sure WCF REST template is installed Fiddler – make sure capture traffic is off Make sure JSON addon is installed Tools -> Fiddler Options -> Enable IPv6 must be disabled Rule 18 Demo 1 – ASP.NET Web Forms Add new ASP.NET Empty Web Application project - Name WebForms Right click web project -> properties -> web -> specific port: 4000 Add Reference to BlackBox Add new item web form – named games.aspx Switch to code view and remove page_load method Add render override (Ctrl+0) protected override void Render(HtmlTextWriter writer) { } Add Database Connection string (Ctrl+1) Database.ConnectionString = @"data source=C:UsersRobert MacLeanDesktopRESTfulWebFormsbinsuperstore.sqlite"; Add Response.Clear(); (Ctrl+2) Add Request.HttpMethod switch (Ctrl+3) switch (Request.HttpMethod.ToUpperInvariant()){ case "POST": { break; } case "GET": {  break; } case "PUT": { break; } case "DELETE":  { break; }} Add DisplayGames method signature (Ctrl+4) private void DisplayGames(HttpRequest request) {        }
  6. 6. Demo 1 continued. Add code to get and return all games (Ctrl+5) dynamic response;response = Database.Instance.Games.ToList();Response.ContentType = "application/json";Response.Write(JsonMagic.ConvertToJson(response));Response.StatusCode = 200; Add DisplayGames(Request); to GET case – (Ctrl+6) RUN -> Show error in browser Fiddler -> Request Builder -> GET: http://localhost:4000/Games.aspx -> Execute Tour inspector Change DisplayGames to cater for single game option (Ctrl+7) if (request.QueryString["id"] != null){Guid pk = Guid.Parse(request.QueryString["id"]);   response = (from g in Database.Instance.Games                           where g.PK == pk                           select g).ToList();}else{ response = Database.Instance.Games.ToList(); } Build -> Fiddler -> Request Builder -> GET: http://localhost:4000/Games.aspx -> Execute Fiddler -> Request Builder -> GET: http://localhost:4000/Games.aspx?id=11a78864-1f71-4010-b2f1-1735dfbf6bef -> Execute Change from return .ToList() for one item to .Single(); Fiddler -> Request Builder -> GET: http://localhost:4000/Games.aspx?id=11a78864-1f71-4010-b2f1-1735dfbf6bef -> Execute -> Note difference in array Repeat with http://localhost:4000/Games.aspx?id=oops
  7. 7. Demo 1 continued Wrap single response in try/catch (Ctrl+8) try { Guid pk = Guid.Parse(request.QueryString["id"]); response = (from g in Database.Instance.Games                         where g.PK == pk                         select g).Single();}catch{Response.StatusCode = 404; return;} Fiddler -> Request Builder -> GET: http://localhost:4000/Games.aspx?id=opps -> Execute -> Note 404 response Add Create, update and delete methods – (Ctrl+9) private void CreateNewGame(HttpRequest request){ Game game = JsonMagic.ConvertFromJson<Game>(request.Headers["game"]);Database.Instance.InsertGame(game);Response.StatusCode = 201;}private void UpdateGame(HttpRequest request){ Game game = JsonMagic.ConvertFromJson<Game>(request.Headers["game"]);Database.Update(game);Response.StatusCode = 204;}private void DeleteGame(HttpRequest request){ Game game = JsonMagic.ConvertFromJson<Game>(request.Headers["game"]);Database.Delete(game);Response.StatusCode = 204;}
  8. 8. Demo 1 Continued Update switch to call relevant methods (Alt+0) case "POST":{CreateNewGame(Request); break;}case "GET":{DisplayGames(Request); break;}case "PUT":{UpdateGame(Request); break;}case "DELETE":{DeleteGame(Request); break;} Build -> Fiddler -> POST: http://localhost:4000/Games.aspx Add new game header (Alt+1): game: {"Arcade":true,"Genre":"RTS","Image":"smile.jpg","MSPointsCost":1200,"PK":"2B0E0DB8-0DCF-4654-B225-61B57114A2EF","Rating":"E10","ReleaseDate":"/Date(1261519200000+0200)/","RetailCost":0,"Title":"Starcraft 2"} Execute -> Note 201 response Fiddler -> GET: http://localhost:4000/Games.aspx -> Execute -> Note the new one in the list Fiddler -> PUT: http://localhost:4000/Games.aspx -> Change the game header, for example the title -> Execute -> Note the 204 response Fiddler -> GET: http://localhost:4000/Games.aspx -> Execute -> Note the update Fiddler -> DELETE: http://localhost:4000/Games.aspx-> Execute -> Note the 204 response Fiddler -> GET: http://localhost:4000/Games.aspx -> Execute -> Note the item is gone!
  9. 9. Demo 2 – MVC Add -> New ASP.NET MVC 2 Empty project -> Name: MVC Project Properties -> Web -> Specific Port: 4010 Add Reference to BlackBox Open Global.asax and in the start method and add (Alt+2): Database.ConnectionString = @"data source=C:UsersRobert MacLeanDesktopRESTfulMVCbinsuperstore.sqlite"; Add new controller. Name -> GamesController. -> Click Add Add code to return games in Index method (Alt+3) dynamic response;response = Database.Instance.Games.ToList();return Json(response); F5 -> Go to http://localhost:4010/Games -> Error Change the return to (Alt+4) return Json(response, JsonRequestBehavior.AllowGet); F5 -> Go to http://localhost:4010/Games -> It tries to download Fiddler -> Request Builder -> GET: F5 -> Go to http://localhost:4010/Games Change the Index method to support a single item (Alt+5) public ActionResult Index(Guid? id){ dynamic response; if (!id.HasValue)  { response = Database.Instance.Games.ToList(); } else  {   try   { response = (from g in Database.Instance.Games                 where g.PK == id.Value                 select g).Single();    }    catch    {    Response.StatusCode = 404;      return new EmptyResult(); } } return Json(response, JsonRequestBehavior.AllowGet);}
  10. 10. Demo 2 continued Add the create, update and delete methods (Alt+6) public ActionResult Create(){ Game game = JsonMagic.ConvertFromJson<Game>(Request.Headers["game"]);Database.Instance.InsertGame(game);Response.StatusCode = 201; return new EmptyResult();}public ActionResult Edit(){ Game game = JsonMagic.ConvertFromJson<Game>(Request.Headers["game"]);Database.Update(game);Response.StatusCode = 204; return new EmptyResult();}public ActionResult Delete(){ Game game = JsonMagic.ConvertFromJson<Game>(Request.Headers["game"]);Database.Update(game);Response.StatusCode = 204; return new EmptyResult();} Build -> Fiddler -> GET: http://localhost:4010/Games/Create add header from (Alt+1) Fiddler -> GET: http://localhost:4010/Games/Delete add header from (Alt+1) Add the HttpPost/HttpPut/HttpDelete & ActionName attributes to methods [HttpPost, ActionName("Index")] [HttpPut, ActionName("Index")] [HttpDelete, ActionName("Index")] Build -> Fiddler -> POST: http://localhost:4010/Games add header from (Alt+1) Fiddler -> GET: http://localhost:4010/Games Fiddler -> DELETE: http://localhost:4010/Games add header from (Alt+1)
  11. 11. Demo 3 – WCF Data Service Add new empty webform project -> Name WCFDataService Project properties -> Web -> Specific Port -> 4020 Add blackbox reference Add new item -> WCF Data Service -> Name: Games.svc Set Dataservice<T> to be DataService<EDMDatabase> Add CreateDataSourceMethod (Alt+7): protected override EDMDatabase CreateDataSource(){EDMDatabase.ConnectionString = @"data source=C:UsersRobert MacLeanDesktopRESTfulMVCbinsuperstore.sqlite";  return EDMDatabase.Instance;} Set EntityAccessRule to config.SetEntitySetAccessRule("*", EntitySetRights.All); Run -> Browse to http://localhost:4020/Games.svc/XboxGames Fiddler -> GET: http://localhost:4020/Games.svc/XboxGames -> XML view Add header: Accept: application/json-> Repeat last step Change to POST. Change Accept header to Content-Type. Add following (Alt+8) to body {"Arcade":true,"Genre":"RTS","Image":"smile.jpg","MSPointsCost":1200,"PK":"2B0E0DB8-0DCF-4654-B225-61B57114A2EF","Rating":"E10","ReleaseDate":"/Date(1261519200000)/","RetailCost":"0","Title":"Starcraft 2"} This will fail due to a bug in .NET which requires A METRIC TON of code to work around or just use Entity Framework without POCO support
  12. 12. Demo 4 – WCF REST Add new project -> WCF REST Service App -> Name: WCFRest Project Properties -> Web -> Specific Port: 4040 Add Blackbox Reference Global.Asax -> AppStart -> Add (Alt+9): Database.ConnectionString = @"data source=C:UsersRobert MacLeanDesktopRESTfulWCFRestbinsuperstore.sqlite"; Global.asax -> Remove the route prefix (Service1) -> Should look like: RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHostFactory(), typeof(Games))); Rename Service1.cs to Games.cs Delete SampleItem.cs Game.cs: Replace SampleItem with Game (Current Doc only, Match Whole Word, ReplaceAll) Game.cs: Change content of GetCollection to (Ctrl+Alt+0): return Database.Instance.Games.ToList(); Change Get method content to (Ctrl+Alt+1): Guid pk = Guid.Parse(id);return Database.Instance.Games.Where(g => g.PK == pk).Single(); Run without debugging Fiddler: GET: http://localhost:4040/ Add accept header: Accept: application/jsonand execute. GET: http://localhost:4040/1e6e1590-7201-4a9f-aee1-48c7c6575a5c Update create method content to be (Ctrl+Alt+2): Database.Instance.InsertGame(instance);return instance; Update update method to be (Ctrl+Alt+3) [WebInvoke(UriTemplate = "", Method = "PUT")]public Game Update(Game instance){Database.Update(instance); return instance;} Update delete method content (Ctrl+Alt+4) to be: Guid pk = Guid.Parse(id);Database.Delete(Database.Instance.Games.Where(g => g.PK == pk).Single());
  13. 13. Demo 4 continued Build -> Fiddler -> Add Content Type header: Content-Type: application/json Add request body (Alt+8) -> POST -> http://localhost:4040 GET: http://localhost:4040 GET: http://localhost:4040/2B0E0DB8-0DCF-4654-B225-61B57114A2EF DELETE: http://localhost:4040/2B0E0DB8-0DCF-4654-B225-61B57114A2EF GET: http://localhost:4040/2B0E0DB8-0DCF-4654-B225-61B57114A2EF Browse to: http://localhost:4040/help
  14. 14. ASP.NET WebForms ASP.NET MVC WCF Data Services WCF REST 3rd Parties Options for .NET
  15. 15. Demo in all 4 .NET technologies Full CRUD on Games Focus on the REST – Ignore the rest (i.e black box) Work in JSON Demo Goals
  16. 16. A RESTful Service
  17. 17. WebForms Not really built for this Need to EVERYTHING Not recommended unless you have no other option Recap
  18. 18. MVC A lot better than WebForms Helper methods for handling method type, json etc… Multiple return types means more work Recap
  19. 19. WCF Data Services All done for you Good security model Designed with data solutions in mind Issues if not using EF (non-POCO) Powerful client side options OData Format Recap
  20. 20. WCF REST Loads of helpers Designed with REST in mind Not tied to data solutions Powerful clients Recap
  21. 21. WebForms + MVC WCF REST + WCF Data Services MVC + WCF Data Services Embrace Hybrids