infuerno.github.io

Pluralsight: Building applications with ASP.NET MVC 4

Shortcuts

Introduction to ASP.NET MVC 4

Controllers in ASP.NET MVC 4

Routes and Controllers

The routing engine is a core part of ASP.NET - it isn’t tied to the MVC framework, you can use the routing engine to route requests for ASP.NET web forms, MVC services, any type of resource.

The routing engine is given a “map” to follow using the MapRoute API to specify: friendly name; pattern; default parameters. After the request passes through the routing engine, a RouteData data structure is populated with the details and available throughout the request not only to the MVC framework but also in controllers and views.

RouteData.Values["controller"]
RouteData.Values["action"]
RouteData.Values["id"]

The order in which routes are added to the global route collection is significant. The first route the URL matches, wins.

If there is a file on the file system matching the URL, then the MVC framework doesn’t interfere. However some virtual .axd files which don’t really exist can be troublesome, so for this it explicity ignore in the RegisterRoutes method. i.e. routes.IgnoreRoute("{resource}.axd/{*pathInfo)"

Action and Parameters

Action Results

Name Framework Behaviour Producing Method
ContentResult Returns a literal string Content
EmptyResult No response
FileContentResult / FilePathResult / FileStreamResult Returns the contents of a file File
HttpUnauthorizedResult Returns an HTTP 403 status
JavaScriptResult Returns a script to execute JavaScript
JsonResult Returns data in a JSON format Json
RedirectResult Redirects the client to a new URL Redirect
RedirectToRouteResult Redirect to another action, or another controller’s action RedirectToRoute / RedirectToAction
ViewResult / PartialViewResult Response is the responsibility of the view engine View / PartialView

Action Selectors

ActionName selector attributes decorate public action methods and alter the name by which the action can be invoked. The below method is now invoked using Modify and can’t be invoked using Edit.

[ActionName("Modify")]
[HttpPost]
public ActionResult Edit(string departmentName)
{
	// ...
}

AcceptVerbs selector attributes specify the HTTP verb which is allowed to invoke an action e.g. [HttpPost]

Action Filters

Action filter attributes apply pre and post processing to an action, to add cross cutting logic - logic which needs to execute across multiple actions without duplicating code.

Name Description
OutputCache Cache the output of a controller
ValidateInput Turn off request validation and allow dangerous input
Authorize Restrict an action to authorized users or roles
ValidateAntiForgeryToken Helps prevent cross site request forgeries
HandleError Can specify a view to render in the event of an unhandled exception

Action filters can be applied at the method level, the class level OR the global level via FilterConfig.RegisterGlobalFilters e.g. the HandleError attribute. This uses the Error.cshtml view by default (when CustomErrors are on) - configured to use this by default.

Custom action filters can be created by creating a class which inherits from ActionFilterAttribute. There are 4 main methods availble to override:

  1. OnActionExecuting - look at the request before an action executes
  2. OnActionExecuted - after the action method executes
  3. OnResultExecuting - before the result is executed
  4. OnResultExecuted - after a result is executed.

These action filters are very powerful - change the environment, change results, change parameters. In each method, the filter context@ holds different information relevant to that particular scenario e.g. parameters

Razor Views

Code Expressions

Layout Views

HTML Helpers

Partial Views

Working with Data (Part 1)

Schema first - existing database - graphical designer in VS, imports schema and generates classes needed to manipulate the schema - thereafter change the database and update the schema and the model Model first - use the graphical designer to draw a model - EF generates both the classes and the database schema Code first - write classes - EF uses these to generate the database schema using conventions (which can be overridden)

protected override void Dispose(bool disposing) {
    if (_db != null) _db.Dispose();
    base.Dispose(disposing);
}

LINQ

Two different styles:

There are numerous extension methods available

Use a projection to create a new anonymous type with the exact fields required e.g.

var model = from r in _db.Restaurants where r.country == "USA" orderby r.Name
    select new { r.Id, r.Name, r.City, r.Country, NumberOfReviews = r.Reviews.Count() };

Passing this to the view is difficult since it is an anonymous type. Instead create a view model object with these fields and create an instance of this type instead.

Alternative syntax using Extension Methods Syntax:

var model = _db.Restaurants.Where(r => r.Country == "USA").OrderBy(r => r.Name)
    .Select(r => new { r.Id, r.Name, r.City, r.Country, NumberOfReviews = r.Reviews.Count() });

To filter using a parameter which may be null use: .Where(searchTerm == null || r.Country.StartsWith(searchTerm))

Working with Data (Part 2)

Listing Reviews

Creating a Review

Editing a Review

Security implications of model binding

Validation Annotations

Custom Validations

AJAX and ASP.NET MVC

AJAX Helpers

@using(Ajax.BeginForm(new AjaxOptions(HttpMethod="get", InsertionMode = InsertionMode.Replace, UpdateTargetId = "restaurantList")) {
    <input type="search" name="searchTerm"/>
    <input type="submit" value="Search By Name" />
}
<div id="restaurantList"> ... </div>

Just by itself this will draw a page within a page. To correct this, first put the <div id="restaurantList"> ... </div> inside a partial view e.g. _Restaurants.cshtml and add the @model directive to strongly type it. The controller will then need to decide to either return the whole page view e.g. Index.cshtml or just the partial. In the controller add:

if (Request.IsAjaxPartial()) {
    return PartialView("_Restaurants", model);
}
return View(model);

Behind the scenes

Autocomplete

Paging

To convert the paging from a full post back to partial post backs using JavaScript, as with search we could wire up an event on the anchor tags. However this is part of the HTML in the partial view which gets rerendered each time we search, so they would have to be rewired with every partial page load. Instead wire up the event to something outside of this section e.g. the main-content div, specifying how to filter the events:

$(".main-content").on("click", ".pagedList a", getPage)

The getPage function has been written to be generic:

var getPage = function() {
    var $a = $(this); // wrap the 'a' with jQuery so we can
    var options = {
        url: $a.attr("href"),
        data: $("form").serialize(), // add the form vars to the request so anything in the search box is taken into account
        type: "get"
    };
    $.ajax(options).done(function(data)) {
        var target = $a.parents("div.pagedList").attr("data-otf-target"); // generic way of doing this
        $(target).replaceWith(data);
    });
    return false;
}

Security and ASP.NET MVC

Authentication

There are 3 ways to identify a user in ASP.NET:

  1. Forms authentication - the website provides a page with an input form, user enters username and password, application checks password - relies on cookies and SSL
  2. OpenID / OAuth - rely on a third party to authenticate the user and then tell you who they are
  3. Windows authentication - also know as “Integrated Auth”, for intranets

Windows Authentication

Forms Authentication

Authorisation

Seeding Membership

    WebSecurity.InitializeDatabaseConnection( ... )
    var roles = (SimpleRoleProvider)Roles.Provider; // use to check and create roles
    var membership = (SimpleMembershipProvider)Membership.Provider; // used to check and create users

    // add actual data checks and insert

Cross Site Request Forgery CSRF (C-Serf)

OpenID / OAuth

ASP.NET MVC Infrastructure

Caching

Localisation and Culture

Diagnostics

Unit Testing with ASP.NET MVC

Deployment and Configuration

Configuration Files

The machine.config and machine level web.config are in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config. The Views’s folders web.config contains a FileNotFound handler which returns a 404 if anyone tries to request a view file directly in the URL (rather than going via a controller).

Hosting

MVC compiles to a DLL and requires a host process to execute, to deliver HTTP requests to the logic inside the dll. w3wp.exe - per app pool

Preparation for Deployment

using System.Data.Entity.Migrations;

var migrator = new DbMigrator(new Configuration()); // Configuration is in the Migrations folder
migrator.Update();