Contents

  • C#
  • ASP.NET MVC
C Sharp 6.0 in a Nutshell
Book contents figure

Language Basics

Numeric Types

Types

Other Value Types

  • char (System.Char)
  • bool (System.Boolean)
  • struct
  • enum

Reference Types

  • object (System.Object)
  • string (System.String)
  • interface
  • array (System.Array)
  • delegate

Array and Struct


char[] vowels  = new char[5];
char[] vowels2 = new char[] {'a','e','i','o','u'};
char[] vowels3 = {'a','e','i','o','u'};
                    
for(int i = 0; i < vowels.Length; i++)
{
    Console.Write(vowels[i]);
}
                    
public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
}

Point p = new Point(4,5);
				        

Method Parameters

Method parameters

using System;

class Test         // ref modifier
{
    static void Foo(ref int p)
    {
        Console.WriteLine(p);
        p = p + 1;
    }
    
    static void Main()
    {
        int x = 8;
        Foo(ref x);
        Console.WriteLine(x); // x is now 9
    }
}
				        

using System;

class Test         // out modifier
{
    static void Split (string name, out string firstNames, out string lastName)
    {
       int i = name.LastIndexOf (' ');
       firstNames = name.Substring (0, i);
       lastName   = name.Substring (i + 1);
    }

    static void Main()
    {
        string a, b;
        Split ("Stevie Ray Vaughan", out a, out b);
        Console.WriteLine (a);
        Console.WriteLine (b);
    }
}
// outputs:
//     Stevie Ray
//     Vaughan
				        

using System;

class Test     // params modifier
{
    static int Sum (params int[] ints)
    {
        int sum = 0;
        for (int i = 0; i < ints.Length; i++)
            sum += ints[i];
        return sum;
    }
    static void Main()
    {
        int total = Sum (1, 2, 3, 4);
        Console.WriteLine (total);
    }
}
				        

using System;

class Test         // Optional parameters
{
    static string JoinWith(char a, char b, string del = ",")
    {
        // C# 6 "interpolated string literal
        return $"{a}{del}{b}";
    }
    
    static void Main()
    {
        Console.WriteLine( JoinWith('u','v') );
        Console.WriteLine( JoinWith('u','v',"___") );
    }
}
// outputs:
//  u,v
//  u___v
				        

using System;

class Test      // Named arguments
{
    static void Foo(int x, int y)
    {
        Console.WriteLine(x + ", " + y);
    }
    
    static void Main()
    {
        Foo(x:1, y:2);
        Foo(y:4, x:9);
    }
}
// outputs:
//  1, 2
//  9, 4
				        

// Expression-bodied function members
                    
    public int AddTwo(int a, int b) => a + b;
				        

Var and Nulls


// Implicitly typed local variables

var i = 5;
                    
var adj = "a superlative";
                    
var arr = new[] {1,2,3};

var expr =
    from c in customers
    where c.City == "London"
    select c;
				        

Null-Coalescing Operator


string s = null;
string s1 = s ?? "something else";
				        

Null-Conditional Operator


// "Elvis" operator (?:), prevents NullReferenceException
// AKA: Safe navigation operator
System.Text.StringBuilder sb = null;
string s = sb?.ToString();

// equivalent to
string s = (sb == null ? null : sb.ToString());
                    
// short circuits and is safe
x?.y?.z;

System.Text.StringBuilder sb = null;
string s = sb?.ToString() ?? "something else";
				        

Nullable Types


string s = null;    // just fine
int a = null;       // does not compile

int? id = null;     // OK
System.Nullable<int> id = null;
                    
// common MVC pattern
public ActionResult Details(int? id)
{
    if(id == null)        // or !id.HasValue
    {
        return new HttpStatusCodeResult(400, "Missing user identifier in request");
    }
    User user = db.Users.Find(id);
    // ...
}
				        

Operator Lifting with Nullable Types


int? x = 8;
int? y = 100;
int? z = null;      // i.e. System.Nullable<int> z

// operators are lifted from int
// Normal:
x == y
x + y
x < y

// But must worry about effect of null
x == z     // False
x + z      // null
x < z      // False
x > z      // False
				        

Naming Conventions

Namespaces


namespace SomeNameSpaceName
{
    class Class1 {}
    // other members                
}

namespace Outer {
    namespace Middle {
        namespace Inner {
            class Class2{}
        }
    }
}

using SomeNameSpaceName;
using Outer.Middle.Inner;
				        

// Auto generated code in: file1.cs
namespace MyApp
{
    partial class MyClass { public void MyMethod(){} }
    // other members
}
                    
// Your code in: file2.cs
namespace MyApp
{
    partial class MyClass { public void OtherMember(){} }
}
				        

Classes


using System;

public class Wolf : Canine, IEquatable<Wolf>
{
    public string Name = "Wolfie";
    public string Owner;
    public int Legs;
    private static int totalCount;
    private DateTime birthday;
    
    public Wolf() {}
    public Wolf(string name)
    {
        this.name = name;
    }
    //...
}
				        

Object Initializers


Wolf w1 = new Wolf("Sharp Teeth") { Owner="Me", Legs=4 };
Wolf w2 = new Wolf { Name="Ghost", Owner="John Snow", Legs=4 };
				        

Properties


public class Stock
{
    decimal maxPrice;        // private "backing field"
    
    public decimal MaxPrice
    {
        get { return maxPrice; }
        set { maxPrice = value; }
    }
    
    // Automatic property
    public decimal CurrentPrice { get; set; }
}
				        

var s = new Stock();
s.MaxPrice = 99.99M;
Console.WriteLine(s.CurrentPrice);
				        

    // Read-only property
    string symbol;            // set in the constructor
    
    public string Symbol
    {
        get { return symbol; }
    }
   
    // Expression-bodied property (also read-only)
    public decimal Worth => currentPrice * sharesOwned;
                    
    // Initializer
    public int Volume { get; set; } = 100;
				        

Finalizers


class Class1
{
    ~Class1()
    {
        // release resources?
    }
}
				            

Overriding Inherited Methods


public class Asset
{
    public string Name;
    public virtual decimal Liability => 0;
}
                    
public class Stock : Asset
{
    public long SharesOwned;
}
                    
public class House : Asset
{
    public decimal Mortgage;
    public override decimal Liability => Mortgage;
    public override string ToString() { return "A House"; }
}
				        

Inheritance & Constructors


public class SubClass : BaseClass
{
    public SubClass( int x ) : base (x) { }
}

    // Can also use base like this (no super)
    int a = base.someNum;
				        

Object and Boxing/Unboxing


// System.Object or object is the base of the object hierarchy
object o = new House();
                    
// C# has boxing and unboxing
int age = 32;
object obj = age;
                    
int myAge = (int)obj;
				        

Delegates


    // Declare a new type
    public delegate double BinaryOperator( double a, double b );

    // Create methods we want to use
    public static double Add( double a, double b ) => a + b;
    public static double Sub( double a, double b ) => a - b;
    public static double Div( double a, double b ) => a / b;
    public static double Mul( double a, double b ) => a * b;

        // Create an instance of the delegate type
        BinaryOperator bop = Sub;

        // Use it
        Console.WriteLine( "7 - 9.3 = " + bop(7,9.3) );
                        
  • Similar to "pointer to function" in C, C++
  • Is type safe
  • Used to create callback functions
  • Integral to implementing Observer-Observable pattern
  • Used in lambda functions (expressions) and LINQ
  • Useful in MVC and with testing
  • Has other features
    • Multi-cast
    • Integrates with events
    • Can use generics

Lambda Functions


// Expression Lambdas
// (input parameters) => expression

x => x * x
(x,y) => x == y
(int x, string s) => s.Length > x
				        

// Statement Lambdas
// (input parameters) => { statement1; statement2; statement3; }

() => {Console.WriteLine("Hello Lambda!");}
(x,y) => { return x == y; }      // weird way to write that!
				        

Consider Generic Delegates


// C# 3.0 defined
namespace System
{
    public delegate TResult Func<out TResult>();
    public delegate TResult Func<in T, out TResult>(T arg);
    public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
}
				        

Func<double, double, double> sum = (x,y) => x + y;

public static IEnumerable<U> Map(Func<T, U> fn, IEnumerable<T> list)
{
    //apply fn to list and return resulting new list
}

var output = Map( x => x * x, nums );
				        

Extension Methods

  • Extend an existing type whith new methods
  • Doesn't alter original type
  • Need to add a using statement for extension class in order to use it (i.e. using System.Linq; for LINQ operators)
  • Needs to be a static method in a static class
  • this modifier as first parameter
  • Works for interface types too
// "Add" to string class
public static class StringHelper
{
    public static bool IsCapitalized (this string s)
    {
        if (string.IsNullOrEmpty(s)) 
            return false;
        return char.IsUpper (s[0]);
    }
}               
// Call it as a built-in method
"Perth".IsCapitalized();
// or as a static method
StringHelper.IsCapitalized("Perth");
                    
// How it's translated:
arg0.Method(arg1, arg2, ...);              // Extension method call
StaticClass.Method(arg0, arg1, arg2, ...); // Static method call
				        
// Map example from previous slide
// written as an extension method
Func<double, double, double> sum = (x,y) => x + y;

public static IEnumerable<U> Map(this IEnumerable<T> list, Func<T, U> fn)
{
    //apply fn to list and return resulting new list
}

var output = nums.Map( x => x * x );
				        

Chaining

Look at some definitions in IEnumerable<T>

int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g).Take(4).Average();

// Versus
var result = Average(Take(OrderBy(ints, g=>g),4));
				        

Anonymous Types

  • Simple un-named reference type; inherits directly from object
  • Compier generates code using a template to create the class
  • Must use a var keyword to create new objects of this type
  • You automatically get an .Equals() that compares members for equality
  • NOT dynamic like Javascript object types
  • Access by name (property), i.e. like Name/Value pairs
var obj = new {Name = "Jane", Age = 28, CellNumber = "555-555-1111" };

 // or
  
var obj2 = new { 
    Store = "ShoesForLess", 
    Categories = new String[]{"Running","Leisure","Dress","Sandals"},
    Date = DateTime.Now
    }

Console.WriteLine(obj2.Store);
                

Useful in LINQ select queries


var categories = db.ProductCategories
                   .OrderBy( pc => pc.Name )
                   .Select( pc => new { Name = pc.Name,
                                        Id   = pc.ProductCategoryID } );

Attributes

“Attributes are an extensible mechanism for adding custom information to code elements (assemblies, types, members, return values, parameters and generic type parameters).”

i.e. decorating code elements with metadata

Used extensively in ASP.NET MVC


// For specifying SQL attributes
public partial class SomeClass
{
    [Key]
    [StringLength(4)]
    public string GuID { get; set; }

    [Required, StringLength(64)]
    public string ModelName { get; set; }
    
    [Required]
    [Phone]
    [Display(Name = "Phone Number")]
    public string Number { get; set; }
}
				        

Used extensively in ASP.NET MVC


// For specifying behavior in controller action methods
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult Apply(MemberInfoViewModel newMember)
{
    if (ModelState.IsValid)
    {
        //...
        return RedirectToAction("Index", "Manage", new { success = true });
    }

    return View(newMember);
}
				        

Adding an attribute causes an instance of the attribute class to be created and attached to the element. At runtime, code can use reflection to inquire about available attribute objects and use them accordingly.


// Creating an attribute to manage HTTP's Basic Authentication
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    public string BasicRealm { get; set; }
    protected string Username { get; set; }
    protected string Password { get; set; }

    public BasicAuthenticationAttribute(string username)
    {
        //...
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //...
    }
}

				        

Collections

Built-in data structures of both generic and non-generic types

  • List, ArrayList, LinkedList, ImmutableList, ...
  • Queue, Stack
  • HashSet, SortedSet, Dictionary, OrderedDictionary, ...
  • Generic versions: LinkedList<T>

Yup, the usual:


using System;
using System.Collections;
public class SamplesArrayList  
{
   public static void Main() 
   {
      // Creates and initializes a new ArrayList.
      ArrayList myAL = new ArrayList();
      myAL.Add("Hello");
      myAL.Add("World");
      myAL.Add("!");

      // Displays the properties and values of the ArrayList.
      Console.WriteLine( "myAL" );
      Console.WriteLine( "    Count:    {0}", myAL.Count );
      Console.WriteLine( "    Capacity: {0}", myAL.Capacity );
      Console.Write( "    Values:" );
      PrintValues( myAL );
   }

   public static void PrintValues( IEnumerable myList )  
   {
      foreach ( object obj in myList )
         Console.Write( "   {0}", obj );
      Console.WriteLine();
   }
}
                        

And in generic form


// using System.Collections.Generic
List<string> dinosaurs = new List<string>();

Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);

dinosaurs.Add("Tyrannosaurus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Mamenchisaurus");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Compsognathus");
Console.WriteLine();
foreach(string dinosaur in dinosaurs)
{
    Console.WriteLine(dinosaur);
}
                        

We frequently use objects of these types:

and should look closely at these interfaces

LINQ

Language Integrated Query

  • Built-in to the language
  • Supported by the framework for local objects and remote data connections
  • Type safe
  • Operate on IEnumerable<T> and/or IQueryable
  • Found in System.Linq and System.Linq.Expressions
  • LINQ-to-Objects
  • LINQ-to-SQL
  • LINQ-to-XML

Sequences and Operators


 string[] names = { "Tom", "Dick", "Harry" };
 
 IEnumerable<string> out = names.Where(n => n.Length >= 4);
 
 foreach (string name in out) 
    Console.WriteLine (name);

// Dick
// Harry
				        

Using Fluent Syntax

Chaining Query Operators


string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };

IEnumerable<string> out = names.Where(n => n.Contains("a"))
                               .OrderBy(n => n.Length)
                               .Select(n => n.ToUpper());
foreach (string name in out)
    Console.WriteLine (name);

// JAY
// MARY
// HARRY
				        
Image of chaining query operators
Classification Operators
Filtering Where, OfType
Sorting OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse
Grouping GroupBy, ToLookup
Join GroupJoin, Join
Projection Select, SelectMany
Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum
Classification Operators
Quantifiers All, Any, Contains
Elements ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
Set Distinct, Except, Intersect, Union
Partitioning Skip, SkipWhile, Take, TakeWhile
Concatenation Concat
Equality SequenceEqual
Generation DefaultEmpty, Empty, Range, Repeat
Conversion AsEnumerable, AsQueryable, Cast, ToArray, ToDictionary, ToList

// Pagination

public ViewResult List(int page = 1) 
{
    return View(db.Products.OrderBy(p => p.ProductID)
                           .Skip((page - 1) * PageSize)
                           .Take(PageSize));
}
				        

Types

  • Lambda expressions
  • IEnumerable<T> (local queries)
  • IQueryable<T> (interpreted queries)

Standard Query Operators, DbSet

Things to pay attention to:

  • Deferred execution (See here)
  • Captured variables
  • Subqueries
  • Fluent (dot) or query syntax?
  • Returning anonymous types

The Web Application Landscape

Web Server

LAMP Stack

Diagram of LAMP components By Shmuel Csaba Otto Traian, CC BY-SA 3.0, Link

PHP

http://www.example.com/somepath/hello.php


<!-- hello.php -->
<html>
<head>
    <title>Hello PHP!</title>
</head>
    <body>

        <?php   
        echo "<h1>Hello World!</h1>";
        ?>

    </body>
</html>
				        

Software Platforms

  • LAMP: Linux, Apache, MySQL, PHP
  • MEAN: MongoDB, Express.js, Angular.js, Node.js
  • OpenStack: (many, modular)
  • WINS: Windows Server, IIS, .NET, SQL Server
  • Choose your own pieces

Web Application Frameworks

  • Ruby on Rails (Ruby)
  • Django (Python)
  • ASP.NET & ASP.NET MVC (C#)
  • Spring MVC (Java)
  • Node.js (Javascript)
  • Zend (PHP)
  • See list

ASP.NET Web Forms (>2002)

ASP.NET 2002

http://www.oregon.gov/ODOT/Pages/index.aspx

ASP.NET MVC

  • v. 1.0 in 2009, Current stable v. 5
  • Open Source
  • C# or VisualBasic
  • Extensible
  • Standards compliant
  • Plays nice with Javascript & CSS, jQuery, Bootstrap
  • Overview
  • Easy to build a REST api
  • Test friendly
  • Customizable routing, clean URL's:

    http://www.thingiverse.com/thing:776259

    not

    http://www.autotrader.com/cars-for-sale/Used+Cars/Porsche/Cayman/Albany+OR-97321?endYear=2008&firstRecord=0&listingType=used&listingTypes=used&makeCode1=POR& mmt=%5BPOR%5BCAYMAN%5B%5D%5D%5B%5D%5D&modelCode1=CAYMAN&searchRadius=25& showcaseOwnerId=68403481&startYear=2000&transmissionCode=MAN& transmissionCodes=MAN&Log=0&showcaseListingId=438099248& captureSearch=true&fromSIP=C07B36E73BF24F8EDCE2D641DB137905& showToolbar=true

  • Professional components: security & authentication, database access, ...
  • Uses Model - View - Controller pattern/paradigm

Model - View - Controller

Model View Controller diagram
ASP.NET's Version of MVC

Terminology

  • CLR
  • .NET
  • ASP.NET (Framework)
  • ASP.NET WebForms
  • ASP.NET Web Pages
  • ASP.NET MVC 1-5
  • ASP.NET Core (was vNext)
  • .NET Core

ASP.NET MVC project setup with local database (i.e. HW5)

Order of events

DIY Procedure

  1. Create database schema and database with UP script
  2. Add connection string to Web.config
  3. Write data model classes
  4. Write DbContext subclass
  5. Add Entity Framework using NuGet
  6. Write Controller and action methods
  7. Write Views

Entity Framework

Entity Framework (EF) is an object-relational mapper that enables .NET developers to work with relational data using domain-specific objects. It eliminates the need for most of the data-access code that developers usually need to write.

Entity Framework

Entity Framework Development Workflows Video

Model Contents

EF Relationships and Navigation Properties

Within a database-backed model class:

  • Simple properties: columns in the table, including keys
  • Navigation Properties (virtual)
    • Model reference types: “to-one” relationship
    • Collection types: “to-many” relationship

URL Routing
in an MVC Application

See Pro ASP.NET MVC 5 Book, Ch. 15

An Independent Component

Technically separate from MVC.
Is used in Web API, Forms, etc.
Very configurable.

// in Global.asax.cs 
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}
//in App_Start\RouteConfig.cs
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { 
                controller = "Home", 
                action = "Index", 
                id = UrlParameter.Optional }
        );
    }
}

{controller}/{action}/{id}

Incoming URL Maps To
~/Controller: Home
Action: Index
id:
~/UserController: User
Action: Index
id:

{controller}/{action}/{id}

Incoming URL Maps To
~/User/DetailsController: User
Action: Details
id:
~/User/Details/53Controller: User
Action: Details
id: 53

{controller}/{action}/{id}

Incoming URL Maps To
~/User/Details/JulieController: User
Action: Details
id: Julie
~/User/Details/Julie/AddNo match, too many segments

{controller}/{action}/{id}
Remove defaults

Incoming URL Maps To
~/No match, not enough segments
~/HomeNo match, not enough segments
~/Home/ContactsNo match, not enough segments
~/Home/Contacts/3Controller: Home
Action: Contacts
id: 3

Custom Routes: Go Beyond Default MVC Routing

  • Routes are tested for matches in order, first to last as defined in RegisterRoutes
  • Put more specific patterns first, more general last
  • Routing patterns use "segment variables"
  • controller and action "variables" have special meaning in an MVC app, otherwise can make up new variables
  • These variables are passed to your action method

Custom Routes: Go Beyond Default MVC Routing

  • Has many features
  • Route constraints:
    • By Method: GET, POST, ...
    • By Regular Expression: "^H.*"
    • Type and Value: can match datetime, double, int, numerical range, max length, min length, ...
    • Completely custom made constraints
routes.MapRoute(
    name: "API Routes",
    url: "api/{controller}/{action}/{version}",
    defaults: new { 
        controller = "ExternalAPI", 
        action = "Handler", 
        version = "v2" }
);
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { 
        controller = "Home", 
        action = "Index", 
        id = UrlParameter.Optional }
);
Incoming URL Maps To
~/Controller: Home
Action: Index
id:
~/apiController: ExternalAPI
Action: Handler
version: v2
~/api/RequestsController: Requests
Action: Handler
version: v2
~/apisController: Apis
Action: Index
id:

Routes like this

~/2011/ (all posts from 2011)
~/2011/11/ (all posts from November 2011)
~/2011/11/07 (all posts from November 7th 2011)
~/2011/11/07/exact-post-title
~/exact-post-title
~/about
~/archive
~/tag/whatever-tag

From: ASP.NET MVC Blog URLs via Routing

Segment Variables Map to Action Method Parameters

public ActionResult Details()
{
    object id = RouteData.Values["id"];
    return View();
}

// or better yet

public ActionResult Details(int? id)
{
    return View();
}

// parameter and segment variable must match exactly, i.e. cannot be
public ActionResult Details(int? value)

For Blog Post routes above

public ActionResult Details(int? yyyy, string mm, string dd, string title) {}

public ActionResult ByDay(int? yyyy, string mm, string dd) {}

// or

public ActionResult ByDay(int yyyy, int mm, int dd)
// if you can be sure single digit numbers like 04 are parsed correctly
// and that no-one makes these segment variables optional in routing table
// at a future time
                        

Controllers & Action Methods

See Pro ASP.NET MVC 5 Book, Ch. 17

Controllers

  • DON'T contain or store data
  • DON'T generate user interfaces
  • DO execute logic required to handle a request
  • DO encapsulate, or drive, application logic
    • Respond to incoming HTTP requests
    • Perform operations on the domain model
    • Select views to render
    • Redirect or control the application flow
Class diagram of controllers subsystem

Controller: Uncovered

// ControllersAndActionMethods project
public class BasicController : IController
{
    public void Execute(RequestContext requestContext)
    {

    }
}

Controller: The normal way

public class HomeController : Controller
{
    // GET: Home
    public ActionResult Index()
    {
        return View();
    }
}
Diagram for processing a request

Request Data

  • Extract it from a set of context objects
  • Have the data passed as parameters to your action method
  • Explicitly invoke the framework's model binding feature

Inherited Objects

Useful objects provided by the Controller class when subclassing

How Parameter Objects are Found

public ActionResult Gimme(int id)
// Search in order:
Request.Form["id"]
RouteData.Values["id"]
Request.QueryString["id"]
Request.Files["id"]
  • Parameters are searched by name
  • Case insensitively
  • An IModelBinder will try to convert to the type required by the parameter
  • May throw an exception if it can't convert it
  • Sets ModelState
  • If DataAnnotations are used in the model, will set validation errors in ModelState.Values

Even for complex objects, collections and arrays

public ActionResult GimmeAPerson(Models.Person person)
public class Person
{
    public int PersonID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public Address HomeAddress { get; set; }
    public bool IsApproved { get; set; }
}

public class Address
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
}

Selectively bind properties

Include or exclude values from binding and from validation

public ActionResult Update([Bind(Exclude = "PersonID")] Person person)

// or e.g. in the Entity Framework scaffolded code from HW 6
public ActionResult Create([Bind(Include = "PersonID,FullName,PreferredName,SearchName,IsPermittedToLogon,LogonName,IsExternalLogonProvider,HashedPassword,IsSystemUser,IsEmployee,IsSalesperson,UserPreferences,PhoneNumber,FaxNumber,EmailAddress,Photo,CustomFields,OtherLanguages,LastEditedBy,ValidFrom,ValidTo")] Person person)
                            

Always!

  • Validate parameters server-side
  • Use nullable types for value types or use default parameter values
  • Check the ModelState

Output from the Controller

  • Cause a View to be constructed (producing HTML)
  • Cause another kind of ActionResult to be created, including
    • Return an error code
    • Redirect the client

Action Method Indirection

  • Action methods don't directly build a result
  • They return an object that is itself capable of building the desired result/output
  • These ActionResults are built on the Command Pattern (discussed next term)
Class diagram of ActionResult hierarchy

Specifying a View to Build

// The default.  Search for "Index" in 
// ~/Views/ControllerName/"ViewName".aspx
// ~/Views/ControllerName/"ViewName".ascx
// ~/Views/Shared/"Viewname".aspx
// ~/Views/Shared/"Viewname".ascx
// ~/Views/ControllerName/"ViewName".cshtml
// ~/Views/ControllerName/"ViewName".vbhtml
// ~/Views/Shared/"Viewname".cshtml
// ~/Views/Shared/"Viewname".vbhtml
public ActionResult Index() {return View();}

// Or can specify "ViewName"
return View("HomePage");

// Or full path
return View("~/Views/Other/Index.cshtml");

Passing Data to Views

  • ViewBag
  • ViewData
  • TempData (persist data across a redirection)
  • ModelState
  • ViewContext

Asynchronous Programming

Image from Splot by Eugene Kirpichov, img

Web Framework Benchmarks

Benchmarking MVC on IIS vs. Node.js

Consider this action method

public ActionResult Index()
{		
  WebRequest request   = WebRequest.Create(@"https://example.com/resource");
  WebResponse response = request.GetResponse();
  Stream dataStream    = response.GetResponseStream();
  StreamReader reader  = new StreamReader(dataStream);
  string responseFromServer = reader.ReadToEnd();
	
  reader.Close();
  dataStream.Close();
  response.Close();

  var data = ProcessData(responseFromServer);

  return View(data);
}

See: System.Net.WebRequest

Compare to this

public async Task<ActionResult> Index()
{		
  WebRequest request   = WebRequest.Create(@"https://example.com/resource");
  WebResponse response = await request.GetResponseAsync();
  Stream dataStream    = response.GetResponseStream();
  StreamReader reader  = new StreamReader(dataStream);
  string responseFromServer = reader.ReadToEnd();
	
  reader.Close();
  dataStream.Close();
  response.Close();

  var data = ProcessData(responseFromServer);

  return View(data);
}

Or this from Identity?

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
  if (ModelState.IsValid)
  {
    var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
    var result = await UserManager.CreateAsync(user, model.Password);
    if (result.Succeeded)
    {
      await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
      return RedirectToAction("Index", "Home");
    }
    AddErrors(result);
  }

  // If we got this far, something failed, redisplay form
  return View(model);
}

Synchronicity

  • A synchronous operation does its work before returning to the caller.
  • An asynchronous operation does (most or all of) its work after returning to the caller.
  • Asynchronous methods typically return quickly (or immediately) to the caller; hence they are also called nonblocking methods.

Source: C# 6.0 in a Nutshell, Ch. 14

What is Asynchronous Programming (from Albahari and Albahari, p. 590)
What is Asynchronous Programming (from Albahari and Albahari, p. 591)

Task-based Asynchronous Pattern (TAP)

  • .NET Framework 4.5 and later (C# 5.0 and later)
  • Preferred way to do asynchronous programming
  • Not manual multi-threading
  • async and await keywords
  • Use for both I/O-bound and CPU-bound code, in event driven architectures
  • Implements the Futures and Promises pattern of parallel programming

Analyze this:

Example of controller action method using asynchronous calls
Example of controller action method using asynchronous calls

Recommendations

No, I didn't make this up. It's from Asynchronous programming [in .NET]

Javascript?

"Javascript is a single-threaded non-blocking asynchronous concurrent language"

Philip Roberts: What the heck is the event loop anyway? JSConf EU 2014
Loupe

Node.js Hello World!

//https://nodejs.org/en/docs/guides/getting-started-guide/
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
						    

http.createServer( ), http.server.listen( )

Express.js Hello World!

//https://expressjs.com/en/starter/hello-world.html
const express = require('express')
const app = express()

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(3000, () => console.log('Example app listening on port 3000!'))