Building Single Page Apps with HTML5, Knockout, jQuery, and Web API – Part 4 – Serving JSON with ASP.NET Web API | John Papa

John Papa

Evangelist on the loose

Building Single Page Apps with HTML5, Knockout, jQuery, and Web API – Part 4 – Serving JSON with ASP.NET Web API

...

 

It’s about T-4 weeks til my Pluralsight course is available. As I get closer to reaching completion I’ll continue sharing some thoughts on how the SPA is architected.

Web Service Layer and JSON

The X AJAX stands for XML … but most of us use AJAX for requesting/pushing JSON. Most HTML5/JavaScript apps these days deal with JSON which makes having solid and simple server side JSON serving tools (lots of S’s in there) really important. Enter the ASP.NET Web API, which I used an an integral part of the Code Camper SPA for my Pluralsight course, titled “Building Single Page Apps (SPA) with HTML5, ASP.NET Web API, Knockout and jQuery”.

Recently I wrote about how my new end to end course on how to build a SPA is progressing.  In this post I share some of my thoughts on how the web service layer is designed in the course. I chose the the ASP.NET Web API because it simplifies web services, is ideal for serving JSON and follows a familiar pattern for me (ASP.NET MVC). I had other options, of course, even in the .NET realm. WCF, ASMX, or even MVC controllers exposing actions. But truth be told, the simplicity of the Web API made it a slam dunk.

More on the Code Camper SPA

Part 1 – The Story Begins (What is the Code Camper SPA?)

Part 2 – Client Technologies

Part 3 – Server Technologies (the Data Layer)

Part 4 – Serving JSON with ASP.NET Web API

Part 5 – HTML 5 and ASP.NET Web Optimization

Part 6 – JavaScript Modules

Part 7 – MVVM and KnockoutJS

Part 8 – Data Services on the Client

Part 9 – Navigation, Transitions, Storage and Messaging

Part 10 – Saving, Change Tracking, and Commanding

Part 11 – Responsive Design and Mobility

Controllers

Controllers are at the heart of the Web API. If you know MVC then this will flow pretty easily for you. Even if you don’t know MVC< the concept is pretty simple. A client makes a HTTP request, it is sent to the server, the Web API routes it to a Controller (a class), and the Controller handles the request. A ASP.NET Web API Controller is simply a class that inherits from ApiController.

The Code Camper SPA has a view which needs a summary list of sessions. So I exposed a method on a Web API Controller to return a list of SessionBrief models. All I have to do from the client was make an ajax request to /api/sessionbriefs

//C#

public class SessionBriefsController : ApiControllerBase
{
public SessionBriefsController(ICodeCamperUow uow)
{
Uow = uow;
}
public IEnumerable<SessionBrief> Get()
{
return Uow.Sessions.GetSessionBriefs()
.OrderBy(sb => sb.TimeSlotId);
}
}

The ApiControllerBase class is a very simple class that defines the Uow property and inherits from the ApiController class. This adds the Unit of Work class instance to all controllers that inherit from it , which in turn allows them to talk to the database (indirectly).

Routes

Web API works off convention over configuration, so ajax calls to /api/sessionbriefs will be routed to it. This route (below) helps route the call to the intended Controller.

routes.MapHttpRoute(
name: ControllerOnly,
routeTemplate: "api/{controller}"
);

Because the ajax request uses an HTTP GET verb, the Get method in the controller is invoked. Then the unit of work (UoW) does its job to get the list of SessionBrief models. Finally, the Web API returns the models as JSON to the client. And when the Code Camper SPA makes PUT, POST, and DELETE requests, they are routed to the Controller’s matching methods for those.

And More

The keys to using the ASP.NET Web API are to set up the routes to the controllers and deciding how to define your controllers and their methods. Once you do that, using the Web API is a breeze. In my course I explain how the different routes in the Code Camper SPA work, how the controllers were designed, and how Ward Bell and I decided to customize them. We ended up using a combination of what I refer to as controller-per-type (a controller services an entity by convention) or custom controllers (mixture of RPC and REST styled calls).

Perhaps my favorite “closet feature” of the Web API is how you can tell it to return models using camelCase. So instead of getting back a SpeakerId property I get speakerId in the JSON. Very simple to implement, but its great and sticks with conventional JavaScript practices.

//C#

public class SessionBrief
{
public int Id { get; set; }
public string Title { get; set; }
public int speakerId { get; set; }
}

//JavaScript

var sessionBrief = {
id: 1,
title: 'A Trip to a SPA',
speakerId: 7
};

Next Up

Next time, I’ll share some insight on how the “single page” in the Single Page App is designed and optimized.

tags: asp.net entity framework json patterns pluralsight SPA webapi
  • GA

    Hi John,
    Good stuff (again).
    I can’t wait until this course comes out. A few things that I wonder… I wonder what will your client side code look like when interacting with the server? Will you be making raw ajax calls throughout the client using jquery? Or will the client code have its own repository that it deals with? I also wonder if and how you deal with persisting entities of different types but that are part of the same aggregate root? Will you be using a changeset based approach? Or will the whole aggregate be sent to the server for persistence? I have a lot of questions in this are…can’t wait until this course comes out…

  • john

    GA – Thanks (again). Wow, you have some pretty interesting questions :) I’ll try to address your questions 1 by 1, without giving too much away.
    Q) “Will you be making raw ajax calls throughout the client using jquery?”
    A) I separate the ajax calls out into a module I call dataservice. It encapsulates all ajax calls. So any presentation layer code/javascript calls the dataservice module, which then uses ajax to talk to the Web API.
    I also use amplify to handle my ajax calls. It helps cache the request results, toggle between mock and real data, and makes the ajax calls simpler.
    Q) I wonder what will your client side code look like when interacting with the server?
    A) Here is a sneak peek … dataservice.persons.getSpeakers(callback);
    Q) Or will the client code have its own repository that it deals with?
    A) My presentation layer has a repository module that I call datacontext. When requests are made to the dataservice, the results are stuffed into the datacontext, so i dont have to make future calls across the internet if I dont want to.
    Q) I also wonder if and how you deal with persisting entities of different types but that are part of the same aggregate root?
    A) I decided to save entities in logical groups. So I dont think I hit that exact scenario in my app. But there is no reason the code I have couldnt do that if you modified it to do so. That’s the fun in apps like this … refactor and go!
    Q) Will you be using a changeset based approach?
    A) I save only when the data has changed. If it has not changed, it wont save. When data changes and the user saves it, the entire object is passed down. This could be a changeset … but again … feel free to refactor it and run :)
    You might be sensing a general theme here … I HOPE people will refactor and tweak the code. Add features. Change how it works. Or swap out libraries for you own favorites. I intended his course to help folks see how it can be done in a real app, then take it from there.
    I hope this helps answer your questions. Thanks for the interest!

  • http://www.spirit.de/demos/metro/Zurbv3/MetroStyle.aspx Rainer Wittmann

    Here’s my take on having no manual ajax calls by using JayData as an data abstraction layer instead.
    Looking forward to the final course.

  • G

    Hello John.
    Thank you for the articles. I’m looking forward to more of them, as well as the Pluralsight course (I already have a membership). Unfortunately, I need it sooner rather than later. I need to have a working (almost production worthy) SPA by the middle of Sept and, obviously, can’t wait until Aug 31st for the videos.
    I’ve tried going through DeliveryTracker and BigShelf but have run into a lot of issues (since they’re using MVC 4 beta and we’re using RC, and they don’t seem to play nice together – maybe one could do it, but I don’t know how and I’m spending way too much time trying to get these example SPAs to work with MVC 4 RC).
    In lieu of having the training course now, can you provide some additional guidance now on how to build the SPA? I’m mostly referring to the client part (which is the key part, I suppose). I’ve already created a database, entities, etc. and am using ASP.NET Web API that has a controller that serves up JSON, but I’m unsure of where to go next. How do I start (and which of the client technologies do I start with) building the client part and start using the JSON data being served up? (The DeliveryTracker and BigShelf examples used DbDataController and upshot, which seemed to be fairly straight forward. But, that doesn’t seem to be a viable option at the moment.)
    Thanks! (And, thanks for your “Building HTML5 and JavaScript Apps with MVVM and Knockout” Pluralsight course. I just started it.)
    G

  • john

    G – I’ll be posting more about the client over the next few weeks and sharing some insights on what I used and how I suggest starting. Its material that is more of a “behind the scenes of the course in a more casual format. Perhaps this will help.
    Til then … sounds like you have a solid server structure. I would skip Upshot for your app if it has to go live in a few weeks. Instead, start with you views, mock them, create then, and flush out your view models. Then determine how you will be navigating (Sammy, History, etc) and how you will deal with data (Knockout, JsViews, Angular, Ember, etc). Also, make sure you stick with a modular approach … in other words, write JavaScript modules that each perform a specific role (SRP). If you do that, its easier to test, maintain, code re use and swap them out if you choose a different library later.
    Good luck!

  • Martin

    Looking forward to your course very much, as this seems to be exactly what I want and what I’m struggling with very much. :) Will be my reason to register with PluralSight. Just wish it would be release already.. :o

  • Kaffee

    Hi John,
    Thank you for the nice articles. Can’t wait to see the rest :).
    Can you explain more about your repository layer (datacontext)? When you call the function “dataservice.persons.getSpeakers(callback)”, are you make a ajax request to the server and store the returing objects?
    What is, if i have two arrays with equal (same properties) speakers:
    self.yourSpeakers = ko.observableArray([]);
    self.mySpeakers = ko.observableArray([]);
    are the objects in the array the same (there are only references to the original objects)? If its so, how you handle the “refresh” when one object gets modified (update, delete etc.) from the store?

  • john

    Kaffee – The dataservice.persons.getSpeakers method goes through my dataservice module, which uses ajax to make the WebAPI call. I’m a big fan of the client side service proxy approach (what I call a data service). And yes, in the app I store those in memory when they come back.
    For your second question, the answer is “it depends”. But likely you want to have 2 different lists of speakers, that point to speakers in memory (that have been returned already). In that case the speakers are the same ones, Meaning if “John Papa” is a speaker and is in both lists, you are pointing to the same one. However, you can make clones too (but I suspect thats not what you want) … see this fiddle. http://jsfiddle.net/johnpapa/xveEP/

  • Kaffee

    Ah, i see. What is if a entity will be deleted from the store? Are you go through all arrays, who has the entity and delete them?

  • john

    Kaffee – That all depends on how you want to delete. With deletes, You can delete the item on the server then refresh the data. Or you can delete it then tell the data context on the client that it is gone. Thre are other ways too … really up to you.

  • Art

    John,
    Will you show how to load/combine multiple applications into an single unit?
    A user may not have access to all available applications, and each applications should be loaded by user context. And how to customize application features per user context? If possible, make use of appmobi?
    For those that haven’t purchased plural sight, just get it. John Papa has many great courses.

  • john

    Art – Thanks for the comment. I will be showing an example of how to use user context/authorization. For example, speaker details can be edited by the speaker, but not by others. There are a few other scenarios too. It’s not something I go deep into, but its there as I felt it was common enough to include some samples. But I also had to try to keep the course to a core set of features or risk being a week long course :-) Hope this helps a little.

  • Hari

    Hi John,
    I am new to MVC. I am following your videos and posts on Single Page Application.
    It is very interesting, I tried a lot to implement the same but unable to pass the values to the controller.

    I created a sample solution which contains 2 textboxs and entered the values into it and tried to
    pass the values to controller method but unable to do so.

    Please let me know the sample basic application so that i can understand the flow.

    Please do the needful.

  • John Citizen

    John:

    I want to preface by saying I like your videos, but sometimes it seems you may not go far enough, or closer to the real world scenario.

    Case in point:

    I would have enjoyed this tutorial better if not only the database were dynamic but there was more than one. As example. a db for logging in, and once the user credentials were determined, a dynamic conn string for the respective database of the user.

    Scenario:

    What if I offered web svcs to many businesses in a particular sector, say companies that sell boats. Now I certainly would want them to have their own db. I wouldn’t want them to share the same db, now would I? And I wouldn’t want each of the respective companies’ db to have a table listing all the username and password for all my clients would I? Certainly not, I would want to keep that separate.

    This is the problem I am running into now. No where can I find a tutorial or github example where the app uses Ninject and the db’s are not determined until run-time (user log in). I am sure some type of placeholder can be put in the bindings that later has a conn string value passed in it after log in.

    You try to post this type of question on SO, and all you get a guys with ego’s larger than their points accumulated, providing terse, vague answers as if they think you are impressed.

    So how ’bout it? I signed up for your video. I watch Shawn Wildermuth’s video too. Always hard-coded conn strings. From my work-perspective, that almost never happens.

    Any chance you can comment here, or ask for my email address? Anything would be appreciated as long as it is understandable.

    I have spent several weeks on this and I am starting to get disgusted.

  • atplerry

    Goodday,

    Haven follow your tutorial, it straight forward and I really
    love the code pattern, when I run the code sample, it run with an error but
    when I add my own model, repository and other resources I get errors, I don’t know
    what am missing, this is the step I took:
    1. I create a sample model

    public class Rent
    {
    public int Id { get; set; }
    public string StreetAddress { get; set; }
    public string StreetAddress2 { get; set; }
    }

    2. Move to the DbContenxt to add to the DbSet

    public DbSet Tracks { get; set; }
    public DbSet Rents { get; set; }

    3. Then, The Uow

    public IRepository Tracks { get { return GetStandardRepo(); } }
    public IRepository Rents { get { return GetStandardRepo(); } }

    4. ICodeCamperUow

    IRepository Rooms { get; }
    IRepository Rents { get; }

    5. Then, To the lookups controllers

    [ActionName("rents")]
    public IEnumerable GetRents()
    {
    return Uow.Rents.GetAll();
    }

    The page do run but with he toastr error msg “Could not retrieve data, Please check
    the logs”
    But When I remove all that I added, the page will run without erros. Please help

%d bloggers like this: