In the first part of this series, we spent some time discussing how WebMAP converts the classic two tier Windows "forms over data" architecture to a MVC-server/MVVM-client structure. A complete discussion of MVC or MVVM (two slightly different takes on the same concept) is beyond the scope of this blog, so if you are puzzled by it this is a good time to go review some of the excellent tutorials available.
We also discussed some differences between a Windows app--which runs on the desktop and is dedicated to a single user--and a web application, which runs both on a client (browser) and web server and which has to be able to handle multiple users simultaneously. We're currently finishing up a little video which will explain this in more detail; I'll post a link so you can watch it when it's ready.
So a quick rehash:
- It refactors the back-end code in to ASP.NET/MVC
- We create a single page application (more about that below)
- The MVC pattern abstracts the presentation from the core business logic
- We use whichever of Kendo UI or AngularJS with Bootstrap for the client presentation
- We send state changes back and forth as JSON.
If we were to look at this visually, it might look like this:
- Binds the ViewModel to the View
- Renders controls and handles events
- Tracks changes to the ViewModel
- Serializes changes and sends to server
- Updates ViewModel from response
- Refreshes View from revised ViewModel.
- Handles session ID and authentication
- Abstracts UI objects to Models
- Acts on state changes from client
- Caches state for session persistence
- Serializes state delta and sends to client.
In the world of Windows code you are used to the idea of a event handler for every event you want to respond to. A very typical example of this is in a form-based application where the user sees controls (some of which are data-bound) and makes changes, then clicks some sort of button or creates a change event. The event-handling code uses some business rules to change the state of the application and the data in the form is refreshed. More or less.
But with a single page web application things are a little different. Remember the client and server are remote from each other, connected via the internet (usually but not required--could be on an intranet). That connection could be solid and reliable or slow and flaky. Generally you have to hope for the former but design for the latter. Because of that, we want to keep the chattiness to a minimum. Remember that we're holding a model of the UI (the ViewModel) on the server; it wouldn't make sense to send that entire model to the client with every interaction.
What we do instead is the following: When the user makes changes on the client (selects an item from a dropdown, types into a text field, etc) the client code flags that bit of state as "dirty." Then at the point the user clicks some submission button (ie a command to process the changes), the "dirty" data is serialized as a JSON object and sent to the server, along with an identifier so the server knows which session this request is coming from.
The controller on the server side routes the modified state info for processing in the logic code, then updates the internal view model and sends a response--again serialized JSON--back to the client. The client, in turn, takes the server response, updates the ViewModel, and then uses that to refresh the View.
Let's take an example. If we use Fiddler to snoop our web traffic, we can see the acutal JSON being handed back and forth. Here's a field getting a value in our sample app Salmon King Seafood:
In this case the "Company name" field has a listener that generates a SQL statement when you type in it. In this case I typed "wa" and here's what Chrome sent to the server (from Fiddler):
It's pretty self-explanatory: we sent a POST command to the server notifying of a TextChanged event on the field txtCompanyName, which is in turn on the form frmOrderRequest. The JSON we sent along looks like this (also from Fiddler):
Again, pretty straightforward:
- "dirty" signals that a change in state has occured
- txtCompanyName#20 tells the server the field and the session (20)
- Text=wa passes the actual value input by the user (see the form above) for processing by the business logic; in this case it will invoke a SQL query built dynamically from that input string ("wa").
Ok, so we sent a change to the server. The server does a DB lookup and returns a response to the client ViewModel. Here's the JSON that gets returned:
The interesting part is under "ItemContent" --notice we sent back some results (Wappec, Ronald J. Ratzaff, etc) from the DB lookup. The ViewModel then updates the View and the form (page) is refreshed to reflect the completed action:
The Circle of Life
Well, not exactly but you get the idea. We change the View, triggering a change to the ViewModel which in turn sends the delta in state to the server, which in turn executes the appropriate event handling code--in this case a SQL query--then takes the change to the model and sends it back as a JSON response, which then causes the ViewModel and View to be updated. The user sees the information they were looking for and continues. Rinse and repeat.