Subscribe Now: Feed Icon

Monday, February 25, 2013

HTML5+MVC Course, Day 2

Continued from day 1.

Last class we learned about the client side, today we are going to go over the server and talking to the server. In the past it was done with Forms and the method Post. Today there is Ajax.

If you want to skip the history lesson you can just go straight to “ASP.NET MVC 4” title.

General

There are 3 option to build Web Applications:

1. Html rendering in the Server side

Every action from changing the color of the text to filtering a table is done by calling the server and getting the result to the client. If you wanted to see the Current Movies, Current Traffic, something from the DB/File system the server renders it.

The server is a “Factory” for Html.

Technological History: CGI, ASP (allowed saving data in the server using the Session object), Sun did something similar with Java.

The Code is build into a Dll, you get to write in a real language (.Net or Java), you get memory management, variables, …

You want to do something, you fill out a Form and data goes to the server. But doing something like Filtering required going to the server as well. Microsoft added a lot of libraries to help this pragma: Rendering, Caching, Database, Controls. All of them for the server side.

 

The Browsers became stronger, so they moved to option 2:

2. Ajax: Html Rendering in the Server but some parts call the server for updates

In the past there was a Frame that you could use to receive updates to just part of the page (most of the Portals inside organizations are still built like this). But Frames are in the past and HTML5 doesn’t include them. Frames are windows that work independently – like opening a different browser per frame, but with frames you can have one frame ask another to do some action. Every frame has a different DOM.

Inner objects in the Html page are calling the server with Ajax to receive updates. The whole page is not updated just the inner part.

Ajax Call – Microsoft has invented a component called XML Http (later the other Browsers implemented it as well) that is  an Object that lives in the DOM (it is actually part of the DOM), it resembles a Frame, it has an inner Form, it sends a request and gets back a response asynchronously (without asking – it’s default way). XML Http was later renamed Ajax, they first believed that you will just transfer XML data and in the client transform it using XSL – joining them both will result in HTML (it was called B2C - Business to Consumer). For a long time no one used that object because ASP got in and made use of option 1, only a few people actually worked with it.

Then Mozilla-Firefox and Google-Chrome adopted this object and gave it the name Ajax - Asynchronously JavaScript And Xml: Asynchronously because that’s how it worked, JavaScript because that the language that consumed it, And Xml that was back then. Today the only part left is asynchronously (JavaScript is a given) no one uses Xml…

ASP.NET Ajax is Microsoft adoption of option 2: it uses a hidden field named ViewState to pass data from the server to the client, they built the ViewState in the Client and passed it to the Server, then built in the Server and passed it to the Client… It worked well: Render in the server and update increments. Sorting some table for example sent Ajax to the server, the server returned a small Html part, then you took a “knife” and cut out the old Html and put instead the new Html. All you had to do was mark which Control you wanted and the system would disable the submit for those controls, do an Ajax request, receive an Ajax response with just the Html needed and replace the control.The problem is it was all done automatically, architecturally wrong: just “drag and drop” and the system patched all the component together. This system was easy for starting users but annoying to advanced users: even changing the design of a button might cause headaches.

ASP.NET came in 2001 to solve the then problem of memory. The Session was a problematic object (the Enemy) that was kept for 20 minutes (by default). So to solve that problem ASP.NET transformed the session to an object that was passed from the server to the client called the ViewState. Since that time memory became less of an enemy, storage has became cheaper but Microsoft was stuck with the ViewState (not using it was an equitant to going back to ASP).

Then came PHP that Facebook was built using a spinoff of PHP. PHP came with the attitude of not using the ViewState hidden field. After that in 2010 Microsoft came up with ASP.NET MVC.

2.1. ASP.NET MVC

The Controller (written in C# and can be debugged and unit tested) creates/puts data into the View and renders the Html in the Server. The controller also allows returning JSON to the client without rendering the Html (the + 0.1). As opposed to ASP.NET Web Forms:

  • No more Ajax
  • Works with jQuery (in it’s orientation)
  • Total separation between the client side and the server side

No longer uses the ViewState, instead uses the Session.

In 2012 Microsoft adds ASP.NET Web API, Mobile, Facebook extension,…

3. Html Rendered in the Client, the Server supplies the data

The application is written with a static Html page, the Server supplies the data with the Business Model. No Html is rendered in the Server. The rendering is done in the Client. The first template might come statically from the server but nothing is rendered in the server.

jQuery was build in the same time as ASP.NET Ajax by John Resig, started as a library that supplied selectors by Id, Class name, Element name, etc. (Original JavaScript code). Minimal code that rely on CSS3. Supports all the Browsers (from IE8 and on, Firefox, Chrome…). Then he added some elementary actions like toggle, style, etc. And (of course) provided support for Ajax (in a property that has a url to which you can GET or POST with a name-value array).

jQuery became a Must Have for every Web Developer in the industry. On top of that came the jQueryUI group that build it’s control on top of jQuery as an alternative to Microsoft’s ASP.NET Ajax (like the AutoComplete box that is available at both libraries).

At around that time JavaScript Framework started appearing that enabled OOP JavaScript, with MVVM or MV* (MV Something): Model you always need, View you always need, now you need something that connects them – in MVC it’s the controller and in MVVM it’s the View Model. The Frameworks were built in GitHub where entire communities were built around those projects. One of those is Knockout by Steve Sanderson who is now a Microsoft employee (though the code is not owned by Microsoft). Knockout gives Templates and is very similar to Silverlight.

 

ASP.NET MVC 4

We will start with ASP.NET MVC of option 2 (fully rendering in the server side: looking briefly at the Controllers of MVC, the routing mechanism, the view, the Razor engine that help the view. The model will be built using Entity Framework. First by hand then using a wizard) and upgrade it to option 3 (with a html page that calls the server for JSON data, with jQueryUI AutoComplete).

Create empty MVC Project with Empty Project Template (or just use the one from last lesson):

CreateEmptyMvcProject

Add Controller named HomeController – by right clicking the Controllers folder-> Add-> Controller… (or Ctrl+M,Ctrl+C):

AddingHomeController

Template: Empty MVC controller

Note: Controller names must end with Controller, MVC at the server works with naming conventions.

In HomeController we get a default method of Index():

MvcBasicUrlFormat

Trying to run it will return an error “The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched…”:

MvcErrorNoViewCreated

The method:

public ActionResult Index()
{
    return View();
}

leads us to the default View of the method named Index. MVC looks for the view Home-Index at a lot of location but doesn’t find it, because it doesn’t exist we get an Error. We have a Controller Home with Index that returns View() – which is the default view for that action.

Another way of thinking about it is: The Controller is C# code, the View is HTML script. The code we have cannot be translated to HTML.

The View method has several overrides:

  • View() – default view: the same name as the method that calls View(), in our case Index
  • View(object) – object that he can shove into the default view as it’s data (in the future it will be the Model)
  • View(IView) – using a custom view object
  • View(IView, object) - using a custom view object with object data
  • View(string) – the value of the string is the name of a different view that will be the View
  • View(string, object) – view name with object data
  • View(string, string) – view name with master name
  • View(string, string, object) - view name with master name and object data

Adding a View is as easy as right clicking the Index method and clicking Add view (or Ctrl+M, Ctrl+V):

BasicMvcAddViewDialog

For now we will uncheck the “Use a layout or master page”, because we don’t have one. The view was added at:

View\Home\Index.cshtml

(the location is a very important part)

Now running the application won’t cause any error. But the View is static, the Controller doesn’t do anything.

Note: CSHTML (the extension of the view file) doesn’t have a built in designer. You can use a designer to build the HTML and just copy paste that to the CSHTML.

 

Passing data from the Controller to the View:

For that we will use a dynamic object named ViewBag that is defined in MVC.

In the Controller writing:

ViewBag.Msg = "Hello";

In the View:

<body>
    <div>
        @ViewBag.Msg
    </div>
</body>

The result is a page displaying Hello.

 

Configuring the default page in MVC:

AppStart\RouteConfig.cs

Contains the code that tell MVC that the default Controller is Home and the default Action is Index:

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 }
        );
    }
}

The first row just tells the server to ignore all requests with .axd. Because ASP.NET uses urls with .axd extension internally.

The second row tells us what the default url is – Home\Index. it also tells us that it receives an Id and that it is optional.

Note: the Home Controller is the default Controller (it isn’t because we added a Controller named Home, it was like this before hand). And Index is the default action.

 

Passing Id to an Action:

In the Controller:

public ActionResult Test(int? id)
{
    ViewBag.Msg = id.HasValue ? id.Value.ToString() : "Hello test";
    return View("Index");
}

View(“Index”) tells MVC to use the Index view for this action.

Calling from the Browser:

\Home\Test\123

(Better for GET request if you need the extra length of GET)

or

\Home\Test?id=123

Note: Passing something that isn’t an int (like ABC) to Test will be the same as not passing a value, i.e. passing null.

 

What is better Get or Post?

GET wakes the server and does the request at the same time.

  • Limited in it’s length.
  • Security: The talk about being insecure is wrong since POST without encryption is just as insecure as GET (passing a user+password in the url is the same as passing it in POST since using any sniffer you can see the variables, it should be preferred to put it in the url so that it could be fixed).
  • If you can get – GET: Much better at the performance. Google uses GET.

POST calls the server, the server opens a socket, the server returns HTTP 100 response and then start passing the data.

  • Security: Data can be encrypted. But if it doesn’t then just use GET.
  • We used POST in ASP.NET because of the ViewState – just saying “hello” caused the GET data to be filled.
  • Not limited in length

 

MVC with Entity Framework Model

Create a new MVC 4 project with a template of Internet Application:

AddProjectMvcWithInternet

Exercise: changing the default layout:
  • Add a tag of test in the home controller
  • Add a tag of test2 in the WhatEver controller

 

The default layout is configured at _ViewStart.cshtml:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

In Razor the file _ViewStart.cshtml determines what is the default layout. You can define a different layout when adding a view:

MvcChoosingLayout

(what I wrote is the same as leaving it empty, both point to the same file)

The code added will contain the layout specified:

@{
    ViewBag.Title = "Test";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Test</h2>

The code for leaving the text box empty (using the default layout):

@{
    ViewBag.Title = "Test";
}

The code for not checking the checkbox (not using a layout):

@{
    Layout = null;
}

Self study: Partial views.

 

Installing Northwinds DB:

  • Download Northwinds.sql.zip
  • Using SQL Server Management and a SA account add a new database named: Northwind
  • Run the script Northwinds.sql using SQL Server Management and the SA account

     

    Under Model folder add ADO.NET Entity Data Model and connect it to the Northwind DB with:

  • Table: Customers
  • Table: Orders
  • Stored Procedure: CustOrderHist

    Note: it is advised to separate the Model from the ORM (when there are many-to-one or many-to-many relationships a JSON parser might cause an infinite loop, separating it to simple classes without outside relations solves the problem), but for this demo we won’t.

    Reference: AutoMapper that helps mapping between the ORM Model to MVC Model.

     

    Add new controller:

  • Template: MVC controller with read/write actions TODO using EF
  • Model: Customer
  • Data Context NorthwindEntities

    AddMvcControllerWithEF

    Just adding an EF Controller gives out of the box a controller and view for actions such as Index with a list of customers that allows viewing, editing, creating and deleting of rows. Though some of the functionality doesn’t work- for example create.

    For example the Index view looks like this:

    MvcWithEfIndexView

    (clicking on each link passes you to the different views, for example clicking on the first row details the browser redirects to BaseUrl/Customer/Details/ALFKI)

     

    The Create action is divided to two methods:

    GET for a blank page(the default is an attribute of HttpGet):

    public ActionResult Create()
    {
        return View();
    }

     

    Http Post that after the submit saves the data (it is like in ASP.NET Web Forms PostBack):

    [HttpPost]
    public ActionResult Create(Customer customer)
    {
        if (ModelState.IsValid)
        {
            db.Customers.Add(customer);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(customer);
    }

    ModelState.IsValid makes sure that all the fields are correct by checking the data types and more advanced the Data Annotations of the model: one property below another, one is times two another, checking the data against data in the DB… For all of those there will be a nice validation error shown to the user.

    Reference Data Validation:

  • With UI
  • More on Validations

     

    After submitting the Create form an Error “pops”:

    MvcEfCreateError

    The Create method failed in saving to the DB. It doesn’t work because the view is missing the CustomerID field (which the system “thought” that in the DB that field is Auto Increment – it isn’t!).

    Exercise: Make create work by adding the CustomerID field to the UI.

     

    Side note on Entity Framework:

    NorthwindEntities should inherit from DbContext (and not from ObjectContext)

    public partial class NorthwindEntities : DbContext

    Using ObjectContext means that the entities inherit from ObjectData, are not POCO and has a lot of extra code (like INotifyChanges that WPF loved).

    Yair advised to start from the code and let EF generate the DB (unless you are in good terms with the DBA).

     

     

    Returning JSON results:
    public JsonResult GetCustomersDetail(string term)
    {
        var results = from c in db.Customers
                      where c.CustomerID.StartsWith(term)
                      select new { Id = c.CustomerID, name = c.ContactTitle, other = c.CompanyName};

        return Json(results.ToList(), JsonRequestBehavior.AllowGet);
    }

    JsonRequestBehaviour enum:

  • DenyGet – the default option from a security point view, though using Fiddler you can quite easily see the POST request/response.
  • AllowGet – usually not turning this on causes the system to not work. Just turn it on! 

    Calling it:

    /Customer/GetCustomersDetail?term=a

    JsonNotPretty

    The results can be made more readable using the Chrome Extension JSONView from Developer Tools:

    JsonChromeExtension

    Note: We can’t use /Customer/GetCustomersDetail/a because we want to pass the term parameter not the id parameter.

     

    JSON Syntax:
  • […] array
  • {…} a type
  • Instead of = we use :
  • Commas to separate types/properties

     

    Exercise: Add a text box that creates a combo box of auto complete using a JSON method. Using the event OnChange when 2 seconds pass we will request the data from the server with a GET, receive the data asynchronously, create a type out of the data returned, and set the result in the view as a list items below the TextBox. The only missing information we need is how to make an Ajax call using jQuery.

    The JSON method:

    public JsonResult GetCustomers(string term)
    {
        var results = from c in db.Customers
                      where c.CustomerID.StartsWith(term)
                      select c.CustomerID;

        return Json(results.ToList(), JsonRequestBehavior.AllowGet);
    }

    In the Documentation we will use the following demo as our base:

    $.ajax({
        url: "http://fiddle.jshell.net/favicon.png",
        beforeSend: function (xhr) {
            xhr.overrideMimeType("text/plain; charset=x-user-defined");
        }
    }).done(function (data) {
        if (console && console.log) {
            console.log("Sample of data:", data.slice(0, 100));
        }
    });

    We will change it to:

    $(document).ready(function () {
        $("#btnGetCustomers").click(function () {
            var strUrl = "Customer/GetCustomers?term=" + $("#txtCustomer").val();
            $.ajax({
                url: strUrl,
                beforeSend: function (xhr) {
                    alert("Good Luck");
                }
            }).done(function (data) {
                alert("Done");
            });
        });
    });

    The Body looks like:

    <input id="txtCustomer" />
    <button id="btnGetCustomers">Click Me</button>

    Note: The first example from here show using jQuery Ajax with POST. If you want to use the data parameter you must work with a POST. GET doesn’t know how to work with the data parameter.

    Now lets debug it to see what the data returns.

     

    Debugging JavaScript:

    1. Using IE:

    Add break point in VS2012

    Set the current browser to IE (on the HTML page right click –> Browse With…):

    Vs2012BrowseWith

    Choose Internet Explorer and set it as the default browser.

    And then just start debugging:

    DebuggingJavaScriptIE

    2. Using Chrome F12: Open Sources tab

    When you open it it will be empty simply click on this thingy (“Show navigator”):

    ChromeF12SourcesTab

    Choose the file you want to debug:

    ChromeF12SourcesHtml

    In our case the HTML page and right click to add break points (you might have to refresh the page).

    ChromeDebuggerBreakpoint

     

    Now the only thing left as homework is changing the Done alert to display the results as HTML list items below txtCustomer.

     

    jQuery Tip:

    $(function() {

    is a shortcut to:

    $(document).ready(function () {

     

    jQueryUI

    Instead of doing all that work we will use jQueryUI for AutoComplete.

    You can see at jQueryUI.com an interactive demo of the different Widgets and Effects available at jQueryUI. One of the Widget available is the Autocomplete, you should start by looking at the source code.

    The application has only one important line of code – the input tag:

    <label for="tags">Tags: </label>
    <input id="tags" />

    Note: the for="tags" in the label is a HTML5 effect that when the tags is unavailable the label becomes unavailable as well.

    Updating our Customers example jQuery code to use jQueryUI:

    Step 1: AutoComplete from a constant array (just like the example on the site):

    $(function () {
        var customers = [
          "ActionScript",
          "AppleScript",
          "Asp",
          "BASIC",
        ];
        $("#txtCustomer").autocomplete({
            source: customers
        });

    Running it with “a” and we get:

    jQueryUiAutoCompleteWithoutCss

    Clicking on a list item will cause the text to “Magically” appear in the textbox. But the UI is a bit ugly.

    Looking at the tag in Chrome F12, we see that when we used .autocomplete on our textbox jQueryUI changed our HTML to:

    <input id="txtCustomer" class="ui-autocomplete-input" autocomplete="off" role="textbox"
        aria-autocomplete="list" aria-haspopup="true">
    <ul class="ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all" role="listbox"
        aria-activedescendant="ui-active-menuitem"
        style="z-index: 1; top: 0px; left: 0px; display: none;"></ul>

    class=”ui-autocomplete-input” - if we used a CSS then the autocomplete would have looked nice

    autocomplete="off" - jQueryUI uses this variable and set it to “on” when it is working, so that when it is on it “knows” not to work.

    When results arrive (for example by entering “a”):

    <ul class="ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all" role="listbox"
        aria-activedescendant="ui-active-menuitem"
        style="z-index: 1; top: 29.88888931274414px; left: 8.88888931274414px; display: none; width: 136.78472208976746px;">
        <li class="ui-menu-item" role="menuitem">
            <a class="ui-corner-all" tabindex="-1">ActionScript</a>
        </li>
        <li class="ui-menu-item" role="menuitem">
            <a class="ui-corner-all" tabindex="-1">AppleScript</a>
        </li>
        <li class="ui-menu-item" role="menuitem">
            <a class="ui-corner-all" tabindex="-1">Asp</a>
        </li>
        <li class="ui-menu-item" role="menuitem">
            <a class="ui-corner-all" tabindex="-1">BASIC</a>
        </li>
    </ul>

    To add CSS to the application simply drag Content/themes/base/jQuery-Ui.css above the <script> in <head>. When developing a real application you should use just the css that you need, in this case we could have just used Content\themes\base\jquery.ui.autocomplete.css.

    Note: There are tools that analyze your page and give it a score that test you among other things on your CSS usage. For example W3C Validation Service checks for markup validity and helium-css tests for unused CSS classes.

    When using the AutoComplete we only used the source property, but there are others which can be viewed at the documentation.

    If we wanted an event such as search:

    $("#txtCustomer").autocomplete({
        source: customers,
        search: function (event, ui) {
            alert("Go");
        }
    });

    We can also interfere with the regular function by changing the event (for example if we don’t want to allow the user to search for a certain term):

    $("#txtCustomer").autocomplete({
        source: customers,
        search: function (event, ui) {
            event.isDefaultPrevented = true;
        }
    });

    In the source parameter you can pass:

  • an array of values: [ "Choice1", "Choice2" ]
  • an array of objects with value+label pairs: [ { label: "Choice1", value: "value1" }, ... ]
  • a string url to a service with a parameter of term: SomeUrl?term=X that return an array of values or an array of objects with value+label pairs
  • a function that returns the data

     

    So using the JSON action we already defined (how lucky was that Smile):

    $(function () {
        $("#txtCustomer").autocomplete({
            source: "Customer/GetCustomers"
        });

    And the end result:

    jQueryUiAutoCompleteResult

     

     

    Homework:

    1. Use a Textbox AutoComplete with a JSON method that returns an array of objects with value+label pairs

    2. Textbox with AutoComplete with select event that goes to the server and gets data. Then put that control in the existing view.

    3. Two Controllers with a hierarchy: Customer and Orders. Form Order add AutoComplete against Customer.

    4. From Customer add AutoComplete of Orders with select event that opens the Customer