3 Main Principles

  1. Inheritance

    Re-Using code from a parent class by extending it in a child class.

  2. Encapsulation

    Hiding implementation details of a class from the consuming code.

  3. Polymorphism

    At runtime, derived types can be treated as base types. The caller does not have to care about the implementation between different derived types.

Abstract Class (AC) vs Interface

  • AC can provide both astract and concrete members
  • AC can have non-public members
  • AC is good for code re-use. With AC, you can enforce implementation on abstract methods (template pattern).

Prefer Inheritance Over Composition

  • Composition - allows for more flexiblity. It's easy to change behavior on the fly with Dependency Injection / Setters
  • The rule of thumb: does TypeA want to expose the entire interface of TypeB (or more)? If yes - inheritance. If no - composition.

Override vs New

  • Override extends base class member, New hides it
  • Polymorphism does not happen with New. You only get derived implementation if casted directly.
  • Good for code re-use. Can enforce implementation on abstract methods (template pattern).
  • To allow override, base class must declare member as virtual. Not the case with New.

SOLID

  • Single Responsibility Principle

    Every object should have only one responsibility, or reason to change

    Reduces impact of making changes to the system, if that class is the only thing to be changed.

  • Open/Closed Principle

    Code is open to extension, closed for modification.

    If you need to extend a system, you shouldn't have to make changes to the source code.

  • Liskov Substitution Principle

    Subtypes must be substitutable for their base types.

    Calling code shouldn't care about if the a base type has implemented differently. It only cares that the expected outcome is the same for any subtype.

    vs polymorphism: in LSP, behavior must be substitutable, in polymorphism only "appearance" (interface) must be substitutable

  • Interface Segregation Principle

    Interfaces should be "lean" --contain only the methods that will be consumed.

    Clients shouldn't have access to a bunch of methods they are not going to use.

  • Dependency Inversion Principle

    Dependencies should point inward, not outward.

    A class using a dependent class (i.e. email service) should not be responsible for instantiating that class directly. Rather, it should have the dependency passed into it.

Coupling

  • Measure of how interconnected classes or subsystems are
  • Tight coupling - related classes have to know internal details of each other, changes ripple through the system, and the system is potentially harder to understand, change or maintain.

Cohesion

  • The methods and of a class are all relevant to its single responsibility. Example, a "car repository" has methods that are responsible for and only for the data access of a car.

Cohesion & Coupling together

  • As you decrease coupling, you increase cohesion and vice versa. Example, if all data access code in a "car service" class is moved to a repository class, that class will become:
    • More cohesive - the methods will be MORE concerned with application logic and LESS concerned with data access
    • Less coupled - the service no longer has to know about the internal details of data access

Repository

  • mediates between storage & model
  • handles all persistence level code, abstracting data access completely
  • you would typically expose repositories as interfaces
  • typically works in conjuction with Unit of Work Pattern

Unit of Work

  • abstraction around grouping operations and executing them in batch
  • helps to manage concurrency
  • very common for data access; typically your unit of work will be responsible for newing up repos and managing the db context

Template

  • Derived classes "inject" custom functionality into parts of that algorythm by overriding virtual methods or implementing abstract methods provided in base class.
  • A little harder for developers to understand and implement vs composition.

Strategy

  • Encapsulating algorythms/business logic into a class.
  • Useful when calling classes need to execute business logic, but don't want to be responisble for the implementation of that logic.
  • Supports Open/Closed Principle

Factory

  • Class that is reponsible for creating objects at runtime.
  • Useful when there is some logic that needs to be abstrated for the creation of certain types.
  • Used less these days since IOC containers became the norm.

Null Object

  • Providing a custom implementation of null
  • Allows greater control of how null is handled, avoids fatal side effects of null (null ref exception, for instance)

TDD

  • Test-Driven Development
  • Building your unit tests before coding your feature
  • Red-Green-Refactor: build a test that fails, add just enough code to make it pass, refactor and repeat
  • Best Practices: one assertion per test, isolation with mocks (Moq, Rhino)
  • Benefits:
    • fewer defects
    • living documentation
    • well crafted code -more de-coupling, better api's
    • automated regression testing
  • My Best Practices:
    • My Structure: (folder)[ClassName]Tests/(class file)[MethodName]Should.cs/(methods)[ExpectedResult]_[IfOptionalCondition]
    • Separate sad path from happy path tests (NUnit category)
    • Mother: static class for re-usable test code
    • Data Access code - should be integration testing (quirkiness with LINQ deceptive)
    • Mocks are key to isolate and make tests easier

DDD

  • Domain-Driven Design
  • Primary focus is on the domain and modelling your entities based on "ubiquitous language".
  • Onion Architecture (DDD n-tier):

    Solution Structure:

    • UI (i.e. Website)
    • Core (Models, Domain Services, Services, Infrastructure Interfaces, Repo Interfaces)
    • Infrastructure (Infrastructure Implementations, Repository Implementations)
    • Test (unit tests for all tiers)
    • UI->Core<-Infrastructure, Test References all

SOA

  • Service-Oriented Architecture
  • Making use of a collection of services
  • Services expose a set of business functionality that is autonomous and can be re-used in many applications
  • Clients of these services are unaware of implementation details

CLR

Common Language Runtime

The .Net runtime framework. It handles security, memory (garbage collection), abstracts low-level things like OS, hardware, source code language.

Types

  1. Primitive

    • Supported by the compiler.
    • Can be created by assigning literal values (i.e. var i = 0).
    • Can be used for constants.
    • Most are value types.
    • int, long, single, double, decimal, bool, date
  2. Reference

    • Stored on heap.
    • A pointer to an object in memory.
  3. Value

    • Stored on stack.
    • No memory pointer.
    • Most primitives

Object

All types derive from object, except open generic types & interfaces.

String

A reference type that behaves like a value type:

  • immutable
  • "==" equality check --string value vs. memory pointer

Unboxing

Converting a reference type to a value type.

Boxing

Converting a value type to a reference type.

Interface

  • Group of related public members
  • No implementation
  • Classes can implement multiple

Access Modifiers

  • public

    not restricted

  • protected

    limited to derived classes

  • internal

    limited to containing assembly

  • protected internal

    limited to derived classes OR limited to derived classes

  • private

    limited to containing class

Class Modifiers

  • public

    not restricted

  • internal

    limited to containing assembly

  • sealed

    cannot inherit from

  • abstract

    cannot be instantiated on its own

  • private, new, protected

    inner classes only

const vs readonly

Const can be assigned only at declaration. Readonly can be assigned only once at runtime.

Array

  • A collection of variables
  • 0 based

Assembly

A grouping of types

Compilation

Source Code (C#/Vb.Net) -> MSIL -> (jit compile) -> Machine Code

Delegate

  • A reference to a method
  • For Events:
    • declaring:

      public event [delegate type] EventName

      if(EventName !=null) EventName(this,[args])

    • consuming:

      [object].EventName+=new [delegate type]([callback method])

Struct vs Class

  • Struct is value type, class is reference type
  • Allocated to memory differently. Struct->stack. Class-> heap
  • Struct typically used for simple data types to pass around, where caller does not need a reference

Func<in T, out TResult>

  • shortcut syntax for a delegate
  • first params (0..*) are input params
  • last params always return type

Action<T>

Like func, but void return type

Expressions<Func<in T, out TResult>>

Wraps func to provide more metadata. Useful for LINQ providers

Nuget

  • packages go to Packages dir in solution
  • in Packages, one folder per package
  • can add sources other than MS
  • VS console - get-package, uninstall-package
  • packages go to Packages dir in solution
  • packages go to Packages dir in solution

Http Modules

  • Plug into http pipeline
  • Called on every request

Http Handlers

  • Target certain request based on URL
  • By default, .ashx file/extension

Membership

  • Functionality for site members, user tracking, authentication

Roles

  • Functionality for site member authorization

SEO-Aware Development

  • Generate quality markup - server side rendering (not ajax), h1 tags, code->text ratio low, ViewState at bottom
  • Keyword-rich URL's
  • Google sitemap.xml
  • Quick page response times
  • Control over indexing - robots.txt, no-follow on links

Mantaining State

  • On server: application, cache, session, url (routes/querystrings)
  • On client: viewstate/controlstate(webforms only), cookies, url, form post

Session

  • Types: InProc, StateServer, SqlServer, Custom, None
  • InProc - the default, web server memory, fastest, not good for load balancing

IIS Authentication

  • Types: anonymous, basic, windows

Asp.Net Authentication

  • Types: anonymous, basic (pass credentials), digest (pass credentials), windows, forms
  • Web.Config -> <Authorization mode="None|Windows|Forms" >

Caching

  • Cache Profiles
    • Set in web.config, allows caching to be changed without recompilation
      <system.web>
          <caching>
              <outputCacheSettings>
                  <outputCacheProfiles>
                      <add name="MyProfile" duration="60" varyByParam="*" />
                  </outputCacheProfiles>
              </outputCacheSettings>
          </caching>
      </system.web>

Localization

  • Thead.CurrentCulture - formatting of data types (i.e. DateTime.ToString(), decimal.ToString("c")
  • Thead.CurrentUICulture - loading of resources
  • Both are set based on accept-language request header, if culture="auto" set in web.config
  • OutputCache - need VaryByHeader="accept-language"
  • Resource loading:
    • .resx files with format: [Name].resx (default), [Name].[culture]-[subculture].resx
    • if .resx file Build Action = "embedded", .resx file will compile to class "Resources.[Name]", and can access resource entries in code

Diagnostics

  • Default - In machine.config -> healthMonitoring -> windows event log logging
  • Use ELMAH for better error handling or splunk or similar for perf testing

Deployment

  • config hierarchy:
    1. machine.config
    2. machine.web.config
    3. parent -> web.config
    4. web.config

WebForms (lame)

ViewState

  • Stores information in browser (hidden field) to maintain state between postbacks
  • Disabling: EnableViewState = false (in page) or EnableViewState = true AND ViewStateMode=enabled/disabled

Control State

  • Used by controls instead of ViewState if state is always needed
  • Overriding: LoadControlState, SaveControlState

Advantages over Web Forms

  • cleaner separation of concerns (better separated between the Model, View and Controller)
  • less complex life cycle
  • more in line with web development in other technologies (less abstraction around core web apis)

Pipeline Diagram

Routing

  • Process of directing http traffic to Controller
  • Setup in Global.asax-> Application_Start
  • RouteCollectionExtensions.MapRoute:

    routes.MapRoute(name, url template, defaults (object),contraints (object), namespaces (string[]))

  • Default route in mvc project: {controller}/{action}/{id}, id is optional
  • First match wins, so more specific routes should go before more generic ones
  • Useful for debugging: Install-Package RouteDebugger
  • Custom Route Constraint:
    • Inherit IRouteConstraint, Match method
    • Good for additional custom route filtering, i.e. by IP Address
  • Custom Route Constraint:
    • Inherit IRouteConstraint, Match method
    • Good for additional custom route filtering, i.e. by IP Address
  • Custom Route Handling:
    • Inherit IRouteHandler
    • Good for if you want to do some processing before route is passed to MVCHandler. For example, you wanted to handle routing for subdomains in a fancy way.
    • Registering:

      Route customRoute = new Route("url", new CustomRouteHandler());
      routes.Add("name", customRoute);

Controllers

  • responsible for responding to requests made against an ASP.NET MVC website
  • responsible for responding for rendering views (chosing the view, passing model data, etc)
  • testing: ControllerContext and associated contexts are mockable
  • Default Controller:
    • System.Web.Mvc.Controller
    • Implements IController, inherits from ControllerBase
    • Almost always will inherit the default controller.
    • ControllerBase: adds actions and has helper methods (Url,etc.)
  • ModelState/Validation
    • ModelState is a property that represents the "state" of the current model in the current action methods. Mostly used for checking and manipulating validation state of the model.
    • ModelState.AddModelError(key, error) - add an error to the model, key is the prop name, if blank it will be for the entire model
    • ModelState.IsValid - determines if model has passed all validations
    • ModelState["Prop"].Errors - get errors for property
    • Typical pattern:

      [HttpPost]
      public ActionResult Update(Model model)
      {
      //validate
      if (!ModelState.IsValid) return View(model);
      //update //..server code to update //redirect\ return RedirectToAction("UpdatedAction");
      }
  • Model Binding
    • mapping request info to .Net types
    • DefaultModelBinder
      • maps form/url values to object and/or primitive parameters of action method
    • Manual Binding
      • Controller -> UpdateModel, TryUpdateModel
    • Bind Attribute
      • Use on actionmethod object parameters to control which props get bound (Exclude or Include)
    • Custom Model Binder
      • Inherit IModelBinder/DefaultModelBinder
      • Call ValueProvider.TryGetValue
      • Register: (global->app_start) ModelBinders.Binders.Add([binder instance])
      • Useful examples: bind to a cookie value, bind user object to UserIdentity
      • Helps decouple controller from http details
    • Data Annotations & Validation
      • for validation: Required, Regex, StringLength, Range
      • can pass validation message or resource for localization
      • in view, Html.ValidationMessageFor...
      • Custom Data Annotation:
        1. inherit ValidationAttribute, implement IsValid
        2. can pass values in attribute if part of constructor
        3. can override FormatErrorMessage
        4. w/ Client Validation
          1. implement IClientValidatable
          2. in js, add Jquery validation method: $.Validator.addMethod(name, function(){...})
          3. in js, add unobstrusive adapter
      • Self Validating Model: inherit IValidatable->Validate
      • Client Validation
        • Turning On:
          1. in view reference jquery, jquery.validation, jquery.validation.unobstrusive
          2. web.config->appsettings: ClientValidationEnabled=true, UnobstrusiveValidationEnabled=true
        • Remote Validation: attribute, will call action method client side
  • Actions
    • Final request destination
    • must be non-static, public methods
    • can return anything
    • selected by IActionInvoker
    • selector filter attributes: [ActionName("name")], verbs ([HttpPost], [AcceptVerbs], etc.)
    • typical pattern in controller:
      [HttpGet] ActionResult Book() {...}
      [HttpPost] ActionResult Book(BookModel model) {...}
    • Optional Parameter - make param with default in action method, or set default for param in routing table, or set param as optional in routing table and make param nullable in action methods
    • Action Filters
      • Responsible for doing some processing of action before action method is executed
      • Built in:
        • OutputCache – This action filter caches the output of a controller action for a specified amount of time.
        • HandleError – This action filter handles errors raised when a controller action executes.
        • Authorize – This action filter enables you to restrict access to a particular user or role.
        • ValidateInput, ValidateAntiForgery
      • Custom Action Filtering:
        1. Inherit ActionFilterAttribute (Implements IActionFilter, IResultFilter)
          Override OnActionExecuting, OnActionExecuted, OnResultExecuting, OnResultExecuted. (If result methods, it is called a "Result Filter")
        2. Override one or more of the controller's On[Filter[ methods. Useful if only applies to one controller.
        3. implement IActionFilter, IResultFilter, IAuthorizationFilter or IExceptionFilter and create FilterProvider
        4. Can register filters globally, create filter provider(good for Injection too) or as attributes on controller/action
    • Action Results:
      • Built In:
      • Security
        • XSS: ValidateInput attribute (on by default), encode html in views, AllowHtml attribute model - to allow html for a target model's property
        • CSRF: ValidateAntiForgeryToken attribute, AntiForgeryToken in views.
          Use where authed only form posts occur.
        • Authorization types
          • Forms - use MVC4 Internet Project, uses SimpleMembershipProvider
          • OpenID - use MVC4 Internet Project, AuthConfig.RegisterAuth(), registers OAUTH clients
          • Window - use MVC4 Intranet Project, web.config->authentication mode="Windows"
        • Forms Auth
  • Controller Factories
    • responsible for selecting and creating the appropriate controller
    • DefaultControllerFactory - the default factory, instantiates controller based on URI/defaults in the routing.
    • Custom Controller Factory:
      • Inherit IControllerFactory or DefaultControllerFactory
      • Override GetControllerBase
      • Register: (global->app_start) ControllerBuilder.Current.SetControllerFactory([custom factory instance])
  • async/await
    • syntax for aysnc method
    • public async Task<ActionResult> Get()
        {
         var result=await SomeExternalAsync()
        ...
    • await frees calling thread up to do other work and will be picked up when async method is done
    • AsyncTimeout attribute
    • Task.WhenAll(task1, task2,...) - to execute multiple tasks at once, wating for all to return
    • Exceptions -> the first exception thrown only

Views

  • responsible for presentation, such as rendering some html
    • selection:
      1. first looks in Views/[controller name]/[viewname](cshtml|aspx|ascx)
      2. first looks in Views/Shared/[viewname](cshtml|aspx|ascx)
    • html helper:
      • Utl. class for view responsible for generating common markup
      • Can extend by using extendion methods
      • Method should return HtmlString or TagBuilder --both handle encoding
    • Partial Actions
      • Html.RenderAction(action,controller,params) - renders an action and outputs the html in the calling view
      • The action method must return PartialViewResult to just send the html snippet
      • ChildActionOnly attribute on action method - prevents users from reaching method directly in URL
    • Templated models (model metadata)
      • Html Helper methods: DisplayFor(model/prop), DisplayForModel() - the current model, EditorFor(model/prop), EditorForModel()
      • If no custom template exists, will output default markup
      • Model attributes: DisplayName, DisplayFormat (dates and such), DataType (password, email, date, etc)
      • Custom Templates:
        • Views/(EditorTemplates|DisplayTemplates)/[typename] --finds view by type name by default
        • UIHint - maps type to a different view
        • DisplayFor - can also pass view name
        • In view- ViewData.MetaData.TemplateInfo - can get the formatted value among a bunch of binding info
      • If no custom template exists, will output default markup
      • If no custom template exists, will output default markup
    • Razor
      • easy to use, clean syntax
      • no coupling to asp.net
      • "@" for outputting
      • ""@@"" to escape "@"
      • "@(code)" - explicit
      • <text> tags for literal text
      • Has ViewBag and ViewData
      • "@model" to declare model
      • "@using" to import namespace, or add to web.config in views directory
      • html encoded by default, must call "@Html.Raw" for raw html
      • "@Html.Partial" to ouput partial view as string
      • layouts & sections
        • layouts are like master pages
        • added to Views/Shared
        • assign layout to view in Razor
        • call RenderBody in layout to render child view's content
        • use viewbag to pass data between layout and child
        • sections
          • in layout-> RenderSection(name, required)
          • in layout-> IsSectionDefined to see if populated in child
          • in child-> @section name {...}
        • _ViewStart.cshtml -> assigns layout to all views by default, can have one per folder and will overwrite

Areas

  • breaks large apps into sections with their own views and controllers, like a namespace
  • Adding an Area
    • VS->add area
      • creates folder w/ area registration
      • global.asax, call AreaRegistration.RegisterAllAreas()
      • routing happens in each area RegisterArea
      • can have duplicate controller names between areas
      • for default controller in app, if area controllers named same, need to add a namespace to the default
      • UrlHelper.ActionLink - need to pass area as param or "" to break out of area

Dependency Resolution

  • IDependencyResolver->GetService, GetServices
  • Register: global-> DependencyResolver.SetDependencyResolver([resolver instance])
  • Would create custom for example to add IOC Container support
  • Unifies that various API's for dependency resolution before (controller factorites, etc)

Bundling & Minification

  • System.Web.Optimization
  • BundleConfig->RegisterBundles-> bundles.add(new StyleBundle(outputfile).Inlude(files)) or bundles.add(new ScriptBundle(outputfile).Inlude(files))
  • In view: @Styles.Render(path) or @Scripts.Render(path)
  • web.config, debug must be off to activate the bundling

Mobile

  • Display Modes
    • controller->broswer useragent string->DisplayModeProvider->view (i.e. Home.cshtml, Home.iphone.cshtml
    • like routing, first match is applied
    • registering a new DisplayMode: global-> DisplayModeProvider.Instance.Modes.Insert("suffix (i.e. iphone)", condition (delegate))
    • overriding useragent string: HttpContext.SetOverriddenBrowser, GetOverriddenBrowser, ClearOverridenBrowser

Caching

  • OutputCache attribute
    • Duration-> in seconds
    • VaryByParam -> vary by url/querystring, *=all
    • VaryByHeader -> vary by request header, ajax="x-requested-with"

High-Level Details

  • Resprestational State Transfer
  • System architecture that embraces http, in similar fashion as a end-user of the Web:
    • URI's as resource ID's
    • Uniform Interface (verbs + URI)
    • Stateless
    • Cacheable
    • Hypermedia Driven (HATEOAS) (links)
    • Separation of client & server

Key Advantages

  • Typically easier to consume than RPC technologies like SOAP. (This is because interacting with Http is relatively simple.)
  • Discoverablity is easier with the Uniform Interface and Hypermedia
  • Api can take advantage of all that Http and Infrastructure that Http has to offer. (Caching servers, security, etc).

vs RPC

  • REST - focus is on resources, not operations
  • REST - http provides the interface ("uniform interface"), RPC - interface is specific to app
  • REST - content negotiation, RPC - usually only one format - SOAP/xml

Dogma

Don't get too sucked into the differing opions on REST. Stick with the basics and tailor to your solution.

Hypermedia

  • Not necessary for a RESTful api

URI's

  • Design with nouns, not verbs in mind
  • Plural - "customers, cars"
  • Single resources have identifiers in URI, "customers/123", identifiers should not change
  • Associations - sub segments of URI - "/customers/123/invoices",
    for more complex scenarios use querystrings - "/customers?state=GA"

Common Status Codes

200 ok
201 create
304 not modified
404 not found
401 unauthorized
403 forbidden
400 bad request - user
500 server error

Content Negotiation

  • Determining media type based on client request
  • Best practice - user Accept header for GET, Content-Type header for others, alernatively can use querystring but not a BP
  • Common Content Types:
    json application/json
    jsonp application/javascript
    xml text/xml
    html text/html
    form post application/x-www-form-urlencoded

Results

  • Should be simple objects
  • For json should use camel casing

Caching

  • Only GET requests are cacheable
  • With REST you should avoid programmatic caching like in MVC, other infracture should handle caching (i.e. browser or proxy server)
  • Etag
    • only serve content if not changed, reduces bandwidth
    • request->response w/Etag:[etag value] in header->2nd request w/If-None-Match:[etag value] in header-> request Etag==server Etag ? send 304 with not response body : send 200 w/ response body and new Etag header
  • Modified Since
    • only serve content if not changed after specified time
    • request->response w/Last-Modified:[date] in header->2nd request w/If-Modified-Since:[date] in header-> request server last modified &lt; last modified ? send 304 with not response body : send 200 w/ response body and new Etag header
  • Cache Control
    • instruct client not to request again until after specified period
    • request->response w/Cache-Control:max-age=[seconds] in header->client waits until max-age expires

Paging

Use querystring, page no and page size (optional)

Security

  • Https for sensitive data
  • Cross domain
    • jsonp
      • for browser, client inserts script tag w/ URI of call, results executed as a js callback,
      • for GET requests only
      • no true error handling, only timeouts
    • CORS
      • for newer browsers
      • 3 step process involving headers
  • authentication
    • OAauth - authenticating w/ third party and trusting those creds, don't implement yourself (complex - long dance), best for public api
    • Cookies/Netwok - physical login, ok for api that is private or under the same application

High-Level Details

  • A framework for building http-based services
  • Part of MVC4, but not tied to MVC
  • Embraces some of REST, but not all by default (i.e. hypermedia); however, not tied to REST
  • VS - MVC 4 Web Api Project stubs out some controllers.
  • Convention - "/foos" (GET|POST|PUT|DELETE) -> FoosController -> (Get()|Post(model)|Put(id, model)|Delete(id))
  • HttpRespsonseMessage - allows for better control of http (status codes, etc); Request.CreateResponse, Request.CreateErrorResponse
  • Accept header - type of data wish to get back; Content-Type header - type of data we are sending
  • Can host in MS WebServer (IIS/Cassini/IIS Express) or self host
  • Configuration - HttpConfiguration.Configuration for IIS, GlobalConfiguration for self hosted

Web Api vs WCF REST

  • WCF is more geared towards SOAP, and thus more bloated and harder to use for http
  • Only use WCF if you are limited to .Net 3.5 or need to use SOAP

Pipeline Diagram

Main Namespaces

Namespace Contains
System.Net.Http HttpClient and raw messages
System.Net.Http.Formatting Model Binding, Media Type Formatters
System.Web.Http ApiController
System.Web.Http.Common common API's
System.Net.Http HttpClient and raw messages

Web Api & The Uniform Interface

  • A consistent interface using URI's & http verbs
  • "unsafe" - action has side effects, all verbs are unsafe except GET
  • "idempotent" - many request will have the same result, all verbs are idempotent except POST
  • Convention
    • URI's set up in route table
    • Custom controllers inherit ApiController
    • Action Methods selected based on verb and method name beginning (Post* for example), unless overwritten in routes.
    • PUT/POST methods - content comes from request body, can only have one body type, since body can be read only one
    • [FromBody] can explicity specify which type is coming from request body
  • HttpResponseMessage - provide better control (headers, status codes, etc)
  • Post - should provide URI of newly created entity in Location header response
  • Get - if item not found in operation lookup, should return 404

Web Api & Content Negotiation

  • by default the Accept header w/ one or more media types or Content-Type header if sending data
  • like model binding for MVC
  • request body read only once
  • Parameter Binding (Model Binding)
    • If the parameter is a “simple” type, Web API tries to get the value from the URI using IModelBinder's
    • For complex types, Web API tries to read the value from the message body, using a media-type formatter.
    • Can override default behavior by using [FromBody], [FromUri]

HTTPClient

  • A better client for interacting with RESTfull endpoints
  • Basic usage:

    var client = new HttpClient();
    var response = await client.GetAsync(url)
    response.EnsureSuccessStatus();
    var result = await response.Content.ReadAsAsync<T>()
  • Media Types Built In:
    • Response - application/json, application/xml; client.PostJson, client.PostXml
    • Request - application/json, application/xml, form, mulipart form, byte[]; for content other than Json and Xml need to pass content w/ MediaTypeFormatter
  • For non asp.net project, use Nuget Web Api Client Libraries project
  • Set headers using client.DefaultRequestHeaders.Accept.Add (for all subsequent requests)
  • Use HttpClientHandler for more control over message sent
  • Useragent - not set by default, you need to set

Security

  • All the same security as Asp.Net
  • Forms auth for non-asp.net clients:
    • /account/jsonlogin - POST w/ username/pwd to get cookie
    • or activate /authenticaton_JSON_AppService.axd
  • Authorization
    • User [Authorize] attribute
    • Or web.config for URL paths (not recommended)
    • Unauthorized calls will return a 401 w/ error message

Extensibility

  • HttpConfiguration
    • All custom extensibily applied to appropriate section of HttpConfiguration (.Formatters, etc.)
    • IncludeErrorDetailPolicy - error details that get sent to client, LocalOnly(default)|Always|None
    • Properties - collection used to add custom info
  • Media Type Formatters
    • Based on media type of request by default (Accept or Content-Type headers)
    • Custom Media Type Formatter
      1. inherit MediaTypeFormatter
      2. in ctor add SupportedMediaTypes.Add(new MediaTypeHeaderValue(type))
      3. (response parsing) Override the CanWriteType method to indicate which types the formatter can serialize
      4. (request parsing) Override the CanReadType method to indicate which types the formatter can deserialize. In this example, the formatter does not support deserialization, so the method simply returns false.
      5. override the WriteToStream method. This method serializes a type by writing it to a stream;
        if your formatter supports deserialization, also override the ReadFromStream method
  • Model Binding
    • Typically used if type not part of body
    • Custom: Inherit from IModelBinder , HttpParameterBinding and config.ParameterBindingRules.Add (easiest)
  • Filters
    • Hook into model binding and controller execution
    • Custom: Inherit from IFilter
  • Message Handlers
    • First step in message pipeline, before action and model binding
    • Custom Message Handler
      1. derive from System.Net.Http.DelegatingHandler and override the SendAsync method
      2. config.MessageHandlers.Add(new MessageHandler1())
  • Message Handler vs Filter?
    • Can create custom resolver
    • Impelement IDependencyResolver
    • config.DependencyResolver = new CustomResolver();

Best Practices

  • Enforce camel casing of JSON: (in WebApiConfig):
    var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  • Remove XML (if not provided) (in WebAPiConfig):
    var formatters = config.Formatters;
    formatters.Remove(formatters.XmlFormatter);

WebAPI 2.x --what's new

  • IHttpActionResult
    • Easier for unit testing (no mocking of HttpRequest)
    • Includes helper methods Ok(), etc
  • Attribute routing: (controller level): [RoutePrefix("api/books")], (method level): [Route("{id:int}")]
  • CORS support: (in WebApiConfig): config.EnableCors();, then add EnableCorsAttribute globally, at controller or at method.
  • Global error handling - add custom IExceptionLogger as a service in WebApiConfig
  • Oauth2 support
  • BSON mediatype formatter
  • Ignoring routes

ORM Query Performance Optimization

  1. turn off change tracking
  2. eager loading where possible
  3. compiling queries and views

Code First

Setting up ORM

  1. create POCO model class
  2. create class that inherits DBContext with DbSet<Model> properties for models
  3. set connection string in contructor of DBContext
  4. for navigation properties one->many, many->many relationships, props need ICollection virtual (for lazy loading)

Operations

  • Update/Create:

    DbContext.Entry(model).State=EntryState.Modified or DbContext.Entry(model).State=EntryState.Added or DbContext.Entry(model).State=EntryState.Deleted;
    DbContext.SaveChanges();

DB Migrations

  • Use to initialize/schema data without having to worry about losing any data
  • Setting up
    1. vs powershell: enable-migrations, creates config class w/ Seed method, AutomaticMigrationsEnabled prop
    2. if AutomaticMigrationsEnabled==false, need to deal w/ InitialCreate "script"
    3. vs powershell-> update-database -verbose

Data Initialization

  • Use if you just need to create test data, best for development
  • Dev process
    1. Create configuration classes of type EntityTypeConfiguration<T>
    2. Override DBContext OnModelCreating method, add configuration classes modelBuilder.Configurations.Add(configClass), for multiplicity, HasMany/WithMany
    3. Create data initializer class - inherit from DropCreateDatabaseIfModelChanges or CreateDatabaseIfNotExists, override Seed method
    4. In environment call Database.SetInitializer([your initializer])

EF6 - what's new

  • Minor performance gains --compiling linq queries
  • Customize mappings
  • Intercepting requests
  • DbConfiguration class

Typing

  • No strong typing - no compile time checking, could assing a string to var that was originally an int
  • Runtime checking vs compile time checking
  • Duck Typing - don't need to have identity of a type, just the signature/shape
  • Can add new properties/functions at any time
  • javascript coalesces values by default, var t="v" + 1, 1 is coverted to string
  • "==" - equality with coalesce, "===" no coalesce
  • primitives:
    • "value" = boolean, string, number
    • "reference" = object, array
    • "delegate" = function
    • "special" = undefined
  • typeof operator, returns type as string
  • null=declared but no value, undefined = not declared
  • number
    • only number, no int, double, etc
    • special values: Number.MIN_VALUE,MAX_VALUE, etc
    • NaN - non a number, for invalid equation, need to call IsNaN() to test for NaN, NOT NaN==NaN
    • boolean - truthy, vars with values return true, vars with undefined or null, return false, 0 returns false
    • String - immutable, can access as array of chars, length-length of bytes, not chars (consider in unicode)
  • object
    • literal syntax var d = {param:1,bob:2}, can nest objects
  • array
    • untyped collection
    • push - add to end
    • pop - rm from end and return
    • shift - rm from beginning and return
    • unshift - add to beginning
  • function
    • a data type
    • like Func<>

Scoping

  • vars declared outside of function implicitly in global scope, which is window by default in browser
  • variables defined always scope globally withing function, variable declared in if block accessible outside of if block
  • global scopes - need to be careful that other scripts don't overwrite global member
  • Anon Self Executing Function - protects against global pollution, (function(){..code here..})(), can import types as params
  • "namespaces" - use an object, var NS = NS || {}, NS.func=..., can combine with Self exec function to "import" NS, can be used across separate scripts

Functions

  • params optional by default, undefined if not passed, untyped variables
  • arguments - reprents arguments passed to function, an array-like object, can access values as array; to return an actual array from arguments call Array.prototype.slice.call(arguments)
  • functions always return values, default is undefined if no return statement
  • just an object, can add more functions props, toString returns entire funtion as string, length returns number of params
  • this keyword
    • represents the owner of the function, can differ based on calling context
    • [function].bind - returns copy of func with different owner, use when calling the function later
    • [function].call(this,arg1,arg2) - explicitly assigns "this" and optionally pass arguments
    • [function].apply(this,arg[]) - explicitly assigns "this" and optionally pass arguments as array, use when args in array need to be pass to func that does not take an array
  • closures
    • the concept that variables defined outside of a function will always be accessible within that function; if referenced in code,
      never garbage collected if "closed" around the function

OO

  • object prop - if prop name has space need quotes
  • props - can access like array obj["name"] or obj.name
  • props/funcs can be added on the fly
  • "Classes"
    • no offical class
    • can use functions, var Customer= function(name){this.name=name;}; var cust= new Customer("name:);
    • private - use var instead of this within class function, public - assign to this
    • property setter/getter - Object.defineProperty(this, "name", get:func(){}, set:func(){}); only use if really necessary
    • static members, assign to func, not instance - Customer.staticFunc=func....
    • Duck Typing instead of interface
    • prototype
      • the "blueprint" for all instances, like an abstract base class
      • only one copy of defined props/funcs per instance
      • Customer.prototype.send=func...
      • properties off prototype are for all instances
      • can use instanceOf operator
      • interitance
        • assign other func/object to prototype of function, Customer.prototype = new User(); instanceOf will work for type and base type
        • "abstract" class, use object literal instead of function, obj literal can't be newed up, but instanceOf won't work, no recommended
        • protected not supported
        • can't overload constructors
    • singleton
      • revealing module pattern
    • reflection
      • for(var prop in cust){alert(prop);alert(cust[prop])}
      • cust.hasOwnProperty("name")
    • extension methods
      • use prototype

Best Practices

  • "use strict"; --errors thrown more strictly (i.e. not putting var in front of variable declaration)
  • for in loop is not for each loop
  • use namespaces and IFFE's between scripts, or require.js
  • "compile" js by using bundling/minification

CDN

  • CDN with fallback

    <script src="//ajax.googleapis.com/ajax/libs/jquery/[ver]/jquery.min.js"</script>
    <script> window.jQuery || document.write('<script src="/Scripts/libs/jquery-[ver].min.js"><\/script>')</script>

DOM

  • prefer caching of selectors, instead of $(item).addClass.., $(item).find..., use var $item = $(item), then reuse
  • prefer chaining over mutliple calls, $item.addClass('class').find()
  • find() method has the best performance
  • prefer data() function rather than setting custom attribute if manipulated in browser, data() will coalesce the type
  • custom selector
    $.extend($.expr[':']), { 
      customSelector:function(){
      //return bool..
      }});
    $('div:customSelector').find...
    
  • custom plugin:
    $.fn.setEnabledState = function (enabled) {
    
        return this.each(function () {
    
            var $this = $(this);
            if (enabled) {
    
                $this.removeClass(disabled);
                $this.removeProp(disabled);
            } else {
                $this.addClass(disabled);
                $this.prop(disabled, true);
            }
    
        });
    };
    
  • dom performance
    • prefer .html method, vs appending dom elements, dom doesn't have to be continually requeried
    • test w/ jsperf.com
  • check if element exists - $(item).length>0
  • find() vs filter() - find is children only, filter is within collection
  • end() - moves up the chain
  • prefer object with when setting multiple attributes, such as with .attr
  • prefer css classes over inline css, add/removeClass vs .css

Events

  • prefer on() method over bind(), delegate(), live() - newer supported way, singe api, better performance, events attach automatically to dynamic items,
    $(item).on(event,childselector,callback) or $(item).on(event,callback)
  • event.stopPropigation() - prevents event from bubbling up
  • event.stopImmediatePropagation() - prevents ANY other event handers from firing
  • namespacing events - event.namespace (i.e. "click.myApp"), good for removing only your events, $(item).off('.namespace') --all events with namesapce or $(item).off('event.namespace') --only that event
  • using on(), you can set up your events before DOM ready
  • prefer to reuse functions as event callbacks rather than anon callbacks
    $.proxy - assigns the this keyword, so this is what is expected
  • triggering custom event - $(document).trigger('eventName',data), subsciber: $(document).on('eventName', callback)
  • event - has number of attributes for user input, e.which - the key, e.clientX - mouse position, etc
  • event - originalEvent will be undefined if NOT human-generated

Ajax

  • method call with most common options:
    $.ajax(url, {
        cache:true|false, //default true, if false adds random querystring
        contentType:"application/json", //when sending, used to set Content-Type header, i.e. "application/json",
        type: 'GET|POST|PUT|DELETE', //the type of request
        data: {}, //data to be sent to the server, if contentType is "application/x-www-form-urlencoded" 
                  //can use $('form').serialize() to create post string
        dataType: "xml|html|script|json|jsonp|text", //the data expecting back, sets the Accepts header, 
                                                     //default is intelligent guess based on contentType, 
                                                     //if "jsonP" will add script block and set callback
        headers: {key:val}, sets additional request headers if needed
        ifModified: true|false, //default false, sends If-Modified-Since header and Etag header, 
                                //for handling unchanged data
        timeout:1000 //timeout in millis
        }
    });
    
  • cross domain calls set by default (headers set if different domain)
  • prefer using promises instead of error/success callbacks, better more cosistent api, $.ajax(..).done(function(data){}).fail(function(xhr){})
  • use $.when to resolve multiple ajax calls, $.when(call1,call2).done(function(data1,data2){}).fail(function(xhr,statusText,err){})
  • to pass as array $.when.apply($, [call1, call2])
  • prefer global ajax callback for common processing of ajax: .ajaxStart(), .ajaxStop(), .ajaxComplete(), .ajaxError(), .ajaxSuccess(), .ajaxSend()

Utilities

  • $.map - project results of an array, also call of select $(div).map(func)
  • $.grep - filters array/collection
  • $.type - improved typeof, more specific types
  • prefer Modernizr for feature detection
  • $.Callbacks -
  • creating/returning deferreds in custom function:
    function retDef(){
            var $dfd = $.Deferred();
            $dfd.resolve(); //or $dfd.reject();
            return $dfd.promise();
    }
    
  • What is it?

    A complete javascript framework that extends HTML for use in applications.

    Ideal for data-heavy, single page applications

    Conceptual Definitions

    Concept Description
    Template HTML with additional markup
    Directives extend HTML with custom attributes and elements
    Model the data shown to the user in the view and with which the user interacts
    Scope context where the model is stored so that controllers, directives and expressions can access it
    Expressions access variables and functions from the scope
    Compiler parses the template and instantiates directives and expressions
    Filter formats the value of an expression for display to the user
    View what the user sees (the DOM)
    Data Binding sync data between the model and the view
    Controller the business logic behind views
    Dependency Injection Creates and wires objects and functions
    Injector dependency injection container
    Module a container for the different parts of an app including controllers, services, filters, directives which configures the Injector
    Service reusable business logic independent of views

    Controllers

    • Used for augmenting scope for views
    • example:
      angular.module('app').controller('EditCtrl', function ($scope, $state, $stateParams, item, matches) {
         $scope.item = {name: 'bob'};
         $scope.doSomething = function(){};
      });

    Services

    • Used to share "business logic" code across Directives and Controllers
    • Singletons
    • Lazily Instantiated
    • Ways to create:
      • .factory: most common way, returns result of function
      • .service: instantiates classes using "new" keyword
      • .provider: used to create services that can be configured in a modules .config() method

    Scope

    • The execution context for a model
    • Provides API's for listening and broadcasting model changes: $watch, $apply
    • Only one rootScope per application
    • Each controller creates child scope, prototype inheritance
    • $on, $broadcast: pub sub for events

    DI

    • Done through the constructor, via the injector service by default
    • Constructor injection not min safe: use min safe array, $inject or gulp/grunt step
    • Can enforce strict DI with ng-strict-di at app level

    Filters

    • for data formatting
    • in template {{expression | filter}}
    • in controller, inject [filterName]Filter, and call function

    Forms

    • 2 way binding, use ng-model
    • Validation:
      • Must use novalidate and give form a name
      • inputs: use ng-class with conditional form state:
        ng-class="{error: mediaForm.mediaImage.$invalid && mediaForm.mediaImage.$dirty}
      • messages: use ngMessages module

    Directives

    • The UI component in angular. Use for generating markup or manipulating DOM
    • Complete example:
      (function () {
      
          'use strict';
      
          angular.module('app').directive('editMedia', function (externalImageListModal) {
              return {
                  restrict: 'E', //E = element, A = attribute, C = class, M = comment 
                  templateUrl: 'app/directives/edit/editMedia.html', //the url for a template
                  //template: '..html..', or you can specify inline (not the best)
                  replace: true, //replace the angular html with generated?
                  transclude: false, //whether to allow transclusion
                  scope: {
                      media: '=' //isolate scope, @ reads the attribute value, = provides two-way binding, 
                                 //& works with functions
                      //,'.' //or inherited scope,
                      //or leave scope out to use shared scope
                  },
                  link: function (scope, element, attrs) { //link function where you do DOM manipulation
                      element.on('click', function(){});
                  },
                  controller: function ($scope) { //controller function to handle scope setup
                      $scope.loadExternalImages = function () {
                          return externalImageListModal.loadModal($scope.media);
                      };
                  }
              };
          });
      
      })();
      

    Routing

    • Best to use angular ui routing module 'ui.router'
    • Example:
      function configRoutes($stateProvider) {
              $stateProvider
                  .state('matches', {
                      url: '/?s',
                      templateUrl: 'app/controllers/home.html',
                      controller: 'HomeCtrl'
                  })
                  .state('matchesMine', {
                      url: '/mine?s&m',
                      params: {
                          s: '/api/my/matches'
                      },
                      templateUrl: 'app/controllers/home.html',
                      controller: 'HomeCtrl'
                  })
                  .state('login', {
                      url: '/login?r',
                      templateUrl: 'app/controllers/login.html',
                      controller: 'LoginCtrl'
                  })
                  .state('edit', {
                      url: '/edit/:id',
                      templateUrl: 'app/controllers/edit.html',
                      controller: 'EditCtrl',
                      resolve: {
                          item: function (matches, $stateParams) {
                              var id = $stateParams.id;
                              if (!id) {
                                  return {
                                      mediaPrimary: {},
                                      mediaSecondary: {}
                                  };
                              }
                              return matches.get(id);
                          }
                      }
                  });
      
              $urlRouterProvider.otherwise('/');
          }
                                  
           angular.module('app').config(function ($stateProvider) {
              configRoutes($stateProvider);
          });
      

    HTTP

    • $resource is higher level than $http --good for interacting with simple REST services
    • $http is more verbose, but provides finer grained control
    • global http processing - use an http interceptor. example:
      (function () {
      
          angular.module('app').factory('authHttpInterceptor', function ($q, channel, config, 
                                                                          authTokenStore, httpUrlFilter) {
      
              var getTargetedAjaxUrl = function (url) { //todo extra
                return httpUrlFilter.getTargetedAjaxUrl(url);
              };
      
              var appendAuthToken = function(url) {
                  url += (url.match(/\?/) ? '&' : '?') + 'auth_token=' + authTokenStore.token();
                  return url;
              };
      
              return {
                  request: function (config) {
                      var url = getTargetedAjaxUrl(config.url);
                      if (url) {
                          config.url = appendAuthToken(config.url);
                      }
                      return config;
                  },
                  responseError: function (rejection) {
                      var url = getTargetedAjaxUrl(rejection.config.url);
                      if (url) {
                          var status = rejection.status;
      
                          if(status === 401 || status === 403){
                              console.log('redirect to login');
                              channel.broadcast(channel.eventNames.authAppFail);
                          }
                      }
                      return $q.reject(rejection);
                  }
              };
          });
                                  
          angular.module('app').config(function ($httpProvider) {
               $httpProvider.interceptors.push('authHttpInterceptor');
          });
      })();
      
      

    Testing

    • Setting up Karma:
      • npm install karma karma-jasmine karma-sinon
      • sample karma.conf.js:
        // Karma configuration
        module.exports = function (config) {
            config.set({
        
                // base path that will be used to resolve all patterns (eg. files, exclude)
                basePath: '',
                // frameworks to use
                // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
                frameworks: ['jasmine', 'sinon'],
                // list of files / patterns to load in the browser
                files: [
                    './bower_components/underscore/underscore.js',
                    './bower_components/angular/angular.js',
                    './bower_components/angular-*/*.js',
                    './bower_components/angular-mocks/angular-mocks.js',
                    './src/client/app/**/*.js',
                    './src/tests/unit/**/*.js'
                ],
                plugins: [
                    'karma-chrome-launcher',
                    'karma-jasmine',
                    'karma-sinon'
                ],
                jUnitReporter: {
                    outputFile: 'test_out/unit.xml',
                    suite: 'unit'
                },
                // list of files to exclude
                exclude: [],
                // preprocess matching files before serving them to the browser
                // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
                preprocessors: {},
                // test results reporter to use
                // possible values: 'dots', 'progress'
                // available reporters: https://npmjs.org/browse/keyword/karma-reporter
                reporters: ['progress'],
                // web server port
                port: 9876,
                // enable / disable colors in the output (reporters and logs)
                colors: true,
                // level of logging
                // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN
                // || config.LOG_INFO || config.LOG_DEBUG
                logLevel: config.LOG_INFO,
                // enable / disable watching file and executing tests whenever any file changes
                autoWatch: true,
                // start these browsers
                // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
                browsers: ['Chrome'],
                // Continuous Integration mode
                // if true, Karma captures browsers, runs the tests and exits
                singleRun: false
            });
        };
        
    • Unit testing with Jasmine:
      'use strict';
      
      describe('MatchesCtrl', function(){
      
          var dfd, rootScope, scope, $controllerCtor, mockMatches, mockMatchesData = {};
      
          //init module before test run
          beforeEach(function(){
              module('app');
          });
      
          //inject angular rootscope, controller factory and promise service
          beforeEach(inject(function($rootScope, $controller, $q){
              rootScope = $rootScope;
              scope = $rootScope.$new(); //create a new scope for controller
              $controllerCtor = $controller;
              dfd = $q.defer(); //execute deferred so it can be evaluated in the test
              dfd.resolve(mockMatchesData);
          }));
      
          it('set the scope matchQuery from promise returned by matches service', function(){
              //arrange
              mockMatches = sinon.stub({query: function () {}});
              mockMatches.query.returns(dfd.promise);
              //act
              $controllerCtor('MatchesCtrl',
                  {$scope: scope, matches: mockMatches});
              rootScope.$apply();
              //assert
              expect(mockMatches.query.called).toBe(true);
              expect(scope.matchQuery).toBe(mockMatchesData);
          });
      });
      

    Doc Type

    <!DOCTYPE html>

    Semantic Markup

    Structural Elements

    • header - with multiple h tags, use hgroup around, can one multiple per section or one per page
    • footer - can have multiple per section
    • article - self-contained documents, i.e. blog post
    • section - can have in page or in in article
    • aside - sidebars, etc
    • nav - mark nav section, major links only
    • mark - highlighted document
    • time - for time output

    Text/Semantic Elements

    • address - contact details of author
    • cite
    • dl->dt/dd - name value pair list
    • ol - now has start attribute
    • s - inaccurate content
    • small - small print
    • strong - importance

    Forms

    • date/time/month/dayofweek input - input type="date", datepicker
    • range - slider, min/max
    • placeholder - input hint (watermark)
    • telephone
    • required property
    • email - multiple - comma separated list of emails
    • color - color picker, --hex value
    • data list - used for auto complete, input list="list"
    • progress - progress bar, value, max
    • meter - high low range
    • input form attribute - can assign form for input outside of form

    Video

    • no need for plugins
    • no standard across browsers - mp4 not free (IE and safari), webm - emerging standard
    • <video controls (show controls) autoplay (plays automatically) ><source src=url></video>
    • use source tag for multiple file formats

    Audio

    • no need for plugins
    • no standard across browsers - mp3 not free (all browsers), vorbis (FF and Opera)
    • use source tag for multiple file formats

    Data Storage

    • stores data on local machine
    • vs cookie - storage not sent to server
    • dependent on origin (site)
    • session storage - browsing session only
      • sessionStorge.getItem(key)
      • sessionStorge.setItem(key, value)
      • sessionStorge.removeItem(key)
      • sessionStorge.clear()
      • sessionStorge.key(i) - gets key at index
      • sessionStorge.length - number of items in collection
    • local storage - persisted to machine

      same api as sessionStorage

    • "storage" event - called when storage is changed, passes args containing key, newValue, oldValue, storageArea (session or local)

    Offline Apps

    • don't mix browser cache with application cache - make sure Cache-Control:no-cache for pages with manifest link
    • files are copied down and retrieved locally
    • combination of application cache and browser events
    • manifest applied after change applied, need to refresh twice
    • no ie9- support
    • Manifest file
      • file example
        CACHE MANIFEST
        # v10.1 
        
        # Explicitly cached 'master entries'.
        CACHE:
        /content/images/favicon.ico
        /Content/images/profile-image.png
        
        # Resources that require the user to be online.
        NETWORK:
        *
        
        # static.html will be served if main.py is inaccessible
        # offline.jpg will be served in place of all images in images/large/
        # offline.html will be served in place of all other .html files
        FALLBACK:
        / /content/offline.css
        
        # images/large/ images/offline.jpg
        # *.html /offline.html
        

        version at the top to force cache to refresh

      • linking to page: <html class="no-js" lang="en" manifest="url" >
      • mimetype: text/cache-manifest, encoding: utf-8
    • applicationCache
      • the class that represents the cache in js
      • has a number of events
      • onupdateready - fires when the manifest has been updated and loaded, call applicationCache.swapCache() and location.reload here to swap out the cache and avoid double refresh
      • offline/online events (window) - fires when offline/online (currently not reliable, use js solution)
      • errors - if there is an error in any file manifest not downloaded

    GeoLocation

    • all major browsers support
    • navigator.geolocation.getCurrentPosition(sucessCallback, errorCallback)
    • position passed to success callback - position.coords - lat/long, etc
    • errorCallback called if request denied, e.code
    • navigator.geolocation.watchPosition(sucessCallback, errorCallback) -- continual watching

    Backwards compatibility

    Use Modernizr

    Inner Join

    selects rows where match found in both tables

    Left Outer Join

    selects rows where match found in left table

    Clustered vs Non-Clustered Index

    • Clustered index is your primary key - only one per table