330 likes | 470 Views
Stateful Web Clients (SPA). Marc Müller Principal Consultant, 4tecture GmbH mmueller@4tecture.ch / www.4tecture.ch @ muellermarc / @4tecture. Agenda. Introduction 10’ Backend Architecture 10’ UI Architecture 15’ Views and View Models 10’ Recap & Questions 5 ’. Introduction.
E N D
Stateful Web Clients (SPA) Marc Müller Principal Consultant, 4tecture GmbH mmueller@4tecture.ch / www.4tecture.ch @muellermarc / @4tecture
Agenda Introduction10’ Backend Architecture10’ UI Architecture15’ Views and View Models 10’ Recap & Questions 5’
Introduction Chapter 1/5
My Web Applicationa My Web Applicationa Web and Rich Applications http://www.url.com http://www.url.com Page request DB AJAX Page Page response Layout & data request response DB Plug-In Silverlight Flash Etc. Plug-inapp request response data
Single Page Application Whole application resides in 1 web page • In-Page Navigation (# tags) • Content (pages) will be shown or hidden on demand Heavy use of JavaScript • MVVM Framework, Navigation Framework • Communication (AJAX Calls) Client-Side stateful representation • In-Memory • Browser Storage Connected to RESTful / HTTP-Service backend (JSON) • Dataservice for CRUD operations, Metadata
Benefitsof Single Page Applications Great userexperience Runs on anydevice Interoperability • Web Standards (HTML / JavaScript) • Cross-Device support • May beintegrated in Hybrid-Application (App Stores) Fluent-UI • Applicationfeelslikerichapplication • UI does not loadforeachrequest (visually) MVVM • Declarativedatabinding • Statefulclientrepresentation • Rich-UI programmingmodel Offline-Support (Browser Storage) App Store deployable
ArchitecturalOverview View Layer (HTML, CSS) Partial View (Application View) Main View (Shell) Partial View (Application View) UI Endpoint Data Endpoint • Application / BL Layer (JavaScript) • Shell: Navigation, Modules, etc • UI Business Logic: View Models, Models • Data Access Layer (JavaScript) • Agents: REST / HTTP calls • Statefuldatarepresentation
My Web Applicationa Navigation / Views http://www.url.com VM1 • Register Views • Viewname • Hashvalue • ViewModel • Bind ViewModel • selector on view • KnockoutJSdatabind • Navigate • check ifcanleave • activateview • hide & show Page VM2 View id=«v1» #view1 VM3 hide View id=«v2» #view2 hide View id=«v1» #view1 hide
Frameworks (used in sample) Durandal • Applicationstructure: AMD Modules and HTML Views • UI Plumbing • Page Navigation / Routing • Life-Cycle events Breeze • Data Access to Data Services • LINQ-likequerylanguage • NavigateObject Graphs / avoiddatamashing, Metadata • Client Caching • Change Tracking / Unit ofWork
Backend Architecture Chapter 2/5
Server Architecture Standard ASP.NET MVC 4 • Standard Controller toprovide • Main View • Sub Views (orloadeddirectlyfromclient) • Provide JavaScript files (orloadeddirectlyfromclient) • WebAPI Controllers toprovidedata • CRUD accessforentities • Security and Validation • Metadata (BreezeJS)
Building a WebAPI Controller (1/2) Standard Layeringand Patterns EF as Data Access Repository Pattern / Unit of Work Pattern SharedEntities / DTO Access Controlthrough ASP.NET Stack
Building a WebAPI Controller (2/2) Entities WebAPI Controller Security BL Service UoW Repository EF Context DB
Web API - Breeze Custom extensionforWebAPI Don’tpanic! Can beextendedtousecustomservices / complexarchitecture Support forOData (future) [BreezeController] publicclassTodosController : ApiController { readonlyEFContextProvider<TodosContext> _contextProvider = newEFContextProvider<TodosContext>(); // ~/api/todos/Metadata [HttpGet] publicstringMetadata() { return _contextProvider.Metadata(); } // ~/api/todos/Todos // ~/api/todos/Todos?$filter=IsArchivedeqfalse&$orderby=CreatedAt [HttpGet] publicIQueryable<TodoItem> Todos() { return _contextProvider.Context.Todos; } // ~/api/todos/SaveChanges [HttpPost] publicSaveResultSaveChanges(JObjectsaveBundle) { return _contextProvider.SaveChanges(saveBundle); } }
Web API - Breeze Sample endpointforour UI -> getshoppinglists [HttpGet] publicIQueryable<Common.Entities.ShoppingList> ShoppingLists() { try { returnthis.ShoppingListService.GetUserShoppingLists(); } catch (SecurityException) { thrownewHttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized)); } catch (Exception) { thrownewHttpResponseException(Request.CreateResponse(HttpStatusCode.InternalServerError)); } }
Backend Services Demo 2
Web ApplicationStructure OrganizeJavaScript files • Separate App-Code and Library Code • Don’tpollutethenamespace use JavaScript AMD patterns Onebig HTML is not maintainable • Separate the different views in singlefiles • Composeviewswith sub-views Maintainable JavaScript • Usegenerators • UseTypeScript (demoapplication)
JavaScript Modularization AMD – Asynchonous Module Definition • Encapsulatecode in object • Loadmodule on demand / dependencyanalysis RequireJS • Doesdependencyresolving • Loadstherequired JavaScript files Anonymous moduledefinition Dependencies define(["require", "exports"], function(require, exports) { varGroup = (function () { function Group() { this.id = ko.observable(0); this.name = ko.observable(""); } return Group; })(); exports.Group = Group; })
Web Project Structure Demo 3
UI Architecture Chapter 3/5
ApplicationBuild-up Startup LogicandConfiguration -> main.js Main UI & Navigation -> Shell • Router extensionsfor in-page navigation • Map View toViewModel In-Memory entityrepresentation -> DataContext CRUD on WebAPI -> DataManager
Lifecycle Events preventnavigation on unsavedchanges Durandalsupportsmanyhook-points Lifecycle Events • getViewEnables the new object to return a custom view. • canDeactivateAllows the previous object to cancel deactivation. • canActivateAllows the new object to cancel activation. • deactivateAllows the previous object to execute custom deactivation logic. • activateAllows the new object to execute custom activation logic. • beforeBindNotifies the new object immediately before databinding occurs. • afterBindNotifies the new object immediately after databinding occurs. • viewAttachedNotifies the new object when its view is attached to its parent DOM node. loaddatafromcontext setup UI events
UI Architecture Demo 4
MVVM Chapter 4/5
MVVM - Definition PersonVM persons: Person[] getPersons() savePerson() Model • The actualdatarepresentation • Provideschange-tracking View Model • Containstheview-logic • Loadsthedata • Getseventnotifications View • The visualrepresentation • Usesdeclarativedatabinding • notifiedbyevents (change, click, etc.) Person firstname : string lastname : string databinding Events, Commands PersonView <div data-bind="text: fullname" />
KnockoutJS Key Concepts DeclarativeBindings Automatic UI Refresh Dependency Tracking Templating imagesource: knockoutjs.com
KnockoutJSextensions KoLite - Lightweight Toolkit for KnockoutJS • asyncCommand • activity • dirtyFlag self.saveCommand = ko.asyncCommand({ execute: function(callback) { $.ajax({ complete: callback, data: { name: self.name() }, type: 'POST', url: '/save/', success: function(result) { alert('Name saved:' + result) } }) }, canExecute: function(isExecuting) { return !isExecuting && self.name() } })
Databinding with KnockoutJS Demo 5
Recap & Questions Chapter 5/5
Summary Complete application in Single Page Heavy use of JavaScript Declarative Binding Backend Communication with RESTful / HTTP-Services (JSON) Fluid, Interoperable Client Application
Wheretostart http://learn.knockoutjs.com/ http://learn.breezejs.com/ http://durandaljs.com http://www.asp.net/single-page-application/overview/templates/hottowel-template http://www.4tecture.ch/blog