40540 ASP.netmvc4 Wb Newfeatures

67
ASP.NET MVC 4 New Features in ASP.Net MVC 4 V1.0 Released: April 13, 2012

Transcript of 40540 ASP.netmvc4 Wb Newfeatures

Page 1: 40540 ASP.netmvc4 Wb Newfeatures

Released:

Page 2: 40540 ASP.netmvc4 Wb Newfeatures

Conditions and Terms of Use

This training package content is proprietary and confidential, and is intended only for users described in the training materials. This content and information is provided to you under a Non-Disclosure Agreement and cannot be distributed. Copying or disclosing all or any portion of the content and/or information included in this package is strictly prohibited.

The contents of this package are for informational and training purposes only and are provided "as is" without warranty of any kind, whether express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, and non-infringement.

Training package content, including URL and other Internet Web site references, is subject to change without notice. Because Microsoft must respond to changing market conditions, the content should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. Unless otherwise noted, the companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred.

Copyright and Trademarks © Microsoft Corporation. All rights reserved.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation.

For more information, see Use of Microsoft Copyrighted Content at http://www.microsoft.com/about/legal/permissions/

Microsoft®, Internet Explorer®, and Windows® are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Microsoft products mentioned herein may be either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. All other trademarks are property of their respective owners.

Page 3: 40540 ASP.netmvc4 Wb Newfeatures

Table of ContentsNEW FEATURES OF MVC 4................................................................................................................................... 1

INSTALLATION AND DEFAULT PROJECT TEMPLATES...................................................................................................... 2Enhancements to Default Project Templates.......................................................................................................2

BUNDLING/MINIFICATION SUPPORT........................................................................................................................ 5DATABASE MIGRATIONS....................................................................................................................................... 9

Walkthrough........................................................................................................................................................9ASP.NET WEB API........................................................................................................................................... 13

Walkthrough - Adding Web API in an Existing Project.......................................................................................14Calling a HTTP Service From JavaScript and jQuery...........................................................................................18Routing in ASP.Net Web API..............................................................................................................................19

Routing Variations.........................................................................................................................................21RAZOR ENHANCEMENTS...................................................................................................................................... 23ASP.NET SINGLE PAGE APPLICATION..................................................................................................................... 24

Walkthrough - Creating Our First Single Page Application.................................................................................25Walkthrough - Building Data Services................................................................................................................28Walkthrough - Building a User Interface Using Knockout and Upshot...............................................................33Walkthrough - Using Display Modes With SPA..................................................................................................40

RECIPES TO CUSTOMIZE CODE GENERATION............................................................................................................. 45Walkthrough - Creating a Recipe.......................................................................................................................45

A Package to Create a Recipe........................................................................................................................45Packaging it Up..............................................................................................................................................47Using a Recipe...............................................................................................................................................47

TASK SUPPORT FOR ASYNCHRONOUS CONTROLLERS..................................................................................................48MODULE REVIEW.............................................................................................................................................. 49

Page 4: 40540 ASP.netmvc4 Wb Newfeatures

New Features of MVC 4This training discusses about the new features introduced in MVC 4 Beta. ASP.Net MVC 4 can be installed side by side with ASP.Net MVC 3 on the same computer, which gives you flexibility in choosing when to upgrade an ASP.Net MVC 3 application to ASP.Net MVC 4.

The basic themes that the product group kept in mind while planning for the next release were:

Development and Deployment: A consistent effort was made to keep the development and deployment workflow easier and more productive.

One ASP.Net: The frameworks and components that make up ASP.NET should seamlessly integrate with each other and enhance the overall web platform. As new features are added throughout the web platform, they can be used in ASP.Net MVC.

Ajax: Whether it is adding a dash of Ajax to an existing web application or implementing a full-fledged single-page application (like Gmail), MVC 4 tries to improve the Ajax development story in ASP.NET MVC.

HTML5, tablet and mobile: There is an industry trend towards building mobile and tablet applications by simply using HTML5. MVC 4 makes it easier to get started building such applications.

Cloud ready: The task of deploying and hosting web applications in the cloud (such as on Windows Azure) needs to be quick and easy. In order to get the most from the cloud, the focus was on performance, security and scalability.

Before You BeginBefore starting this module, you should:

Understand the basic concepts of MVC, such as Models, Views and Controllers.

Be familiar with the features of ASP.Net MVC 3.

What You Will LearnAfter completing this module, you will be able to:

Understand the enhancements in ASP.Net MVC 4.

Create, manage and maintain MVC 4 projects.

1

Page 5: 40540 ASP.netmvc4 Wb Newfeatures

Installation and Default Project TemplatesThere are two options for installing MVC 4.

ASP.Net MVC 4 Beta for Microsoft Visual Studio 2010

Note:You can install the MVC 4 beta from http://www.asp.net/mvc/mvc4 using the Web Platform Installer.

The ASP.NET MVC 4 components for Visual Studio require PowerShell 2.0 and either Visual Studio 2010 with Service Pack 1 or Visual Web Developer Express 2010 with Service Pack 1.

Microsoft Visual Studio 11 Beta (includes ASP.Net MVC 4 Beta)

o Microsoft Visual Studio 11 Ultimate Beta

o Microsoft Visual Studio 11 Express Beta

Enhancements to Default Project TemplatesWhen you open Visual Studio and start a new MVC 4 web application, the following project templates are provided.

Figure 1: Project Templates

© Microsoft Corporation. All rights reserved.2

Page 6: 40540 ASP.netmvc4 Wb Newfeatures

We will look at each of the project templates in detail later.

The look and feel of the new MVC 4 project has been updated to create a more modern-looking website.

Figure 2: ASP.NET MVC Application Home Page

In addition to cosmetic improvements, there is improved functionality in the new templates. The templates employ a technique called adaptive, rendering to look good in both desktop browsers and mobile browsers without any customization.

Another enhancement to the default project template is the use of JavaScript to provide a richer UI. The login and register links that are used in the template are examples of how to use the jQuery UI Dialog to present a rich login screen. If the client does not support JavaScript, razor views are used.

3

Page 7: 40540 ASP.netmvc4 Wb Newfeatures

Figure 3: Log in Page

© Microsoft Corporation. All rights reserved.4

Page 8: 40540 ASP.netmvc4 Wb Newfeatures

Bundling/Minification SupportBundling and Minification features enable you to build web applications that load faster and feel more responsive to the users.

More:For more information, see:

http://msdn.microsoft.com/en-us/vs11trainingcourse_aspnetandvisualstudio_topic5#_Toc319053052

They minimize the number and size of HTTP requests that your pages make to retrieve JavaScript and CSS resources. All MVC project templates now enable bundling and minification by default.

Bundling is a feature that makes it easy to “bundle” or “combine” multiple CSS and JavaScript files into fewer files and therefore fewer HTTP requests. Modern browsers have a limit of six concurrent HTTP requests, so bundling can improve request performance.

Minification is a process that removes whitespace, comments and other unneeded characters from both CSS and JavaScript. The result is smaller files, which will download and load in a browser faster.

Let us consider that we have a view, which refers to several CSS files and JavaScript files.

<html><head> <meta name="viewport" content="width=device-width" /> <title>Bundling and Minification</title> <link href="~/Styles/jquery.ui.all.css" rel="Stylesheet" /> <link href="~/Styles/jquery.ui.base.css" rel="Stylesheet" /> <link href="~/Styles/jquery.ui.core.css" rel="Stylesheet" /> <link href="~/Styles/jquery.ui.theme.css" rel="Stylesheet" /></head><body> <div> <h2>Bundling and Minification</h2> <script src="~/Scripts/knockout-2.0.0.js" /> <script src="~/Scripts/jquery-1.6.2.js" /> </div></body></html>

If we browse the view, we would see multiple HTTP requests going to the webserver.

5

Page 9: 40540 ASP.netmvc4 Wb Newfeatures

Figure 4: Browsing the View

The new bundling/minification feature now allows you to bundle and minify all of the .css files in the Content folder – simply by sending a URL request to the folder (in this case “Content”) with an appended “/css” path after it.

Note:"css" is an arbitrary string. It is the name used to create the bundle and can be anything. To enable bundling, you would first need to add this line to your Application_Start event in Global.asax

BundleTable.Bundles.RegisterTemplateBundles();

Then you can add the link tag in your view.

<head> <meta name="viewport" content="width=device-width" /> <title>Bundling and Minification</title> <link href="~/Content/CSS" rel="Stylesheet" /></head>

This will cause ASP.NET to scan the directory, bundle and minify the .css files within it, and send back a single HTTP response with all of the CSS content to the browser.

Figure 5: Scanning the Directory, Bundling and Minification and Sending Back a Single HTTP Response

Similar to the CSS approach above, if we wanted to bundle and minify all of our JavaScript into a single response, we could send a URL request to the folder (in this case “scripts”) with an appended “/js” path after it:

<script src="~/Scripts/js"></script>

© Microsoft Corporation. All rights reserved.6

Page 10: 40540 ASP.netmvc4 Wb Newfeatures

If you look at the content, you will see that all white spaces have been stripped out to make the payload size much smaller.

html{background-color:#e2e2e2;margin:0;padding:0}body{background-color:#fff;border-top:solid 10px #000;color:#333;font-size:.85em;font-family:"Segoe UI",Verdana,Helvetica,Sans…

Instead of using the standard HTML tags, we can also use some helpers that have been created such as shown below:<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" rel="stylesheet" type="text/css" /><link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/themes/base/css")" rel="stylesheet" type="text/css" /><script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>

The advantage of using helpers is that when you view source, you will see an output such as:

<link href="/Content/css?v=oI5uNwN5NWmYrn8EXEybCIbINNBbTM_DnIdXDUL5RwE1" rel="stylesheet" type="text/css" /> <link href="/Content/themes/base/css?v=UM624qf1uFt8dYtiIV9PCmYhsyeewBIwY4Ob0i8OdW81" rel="stylesheet" type="text/css" /> <script src="/Scripts/js?v=GP89PKpk2iEmdQxZTRyBnKWSLjO7XdNG4QC1rv6LPxw1"></script>

ASP.Net will examine the directory and add a hash to the URL. Now these files will be served from cache until they have been changed and a new hash has been generated.

Note:By default, IIS caches the files for 1 year.

You can use the bundling/minification support across any number of directories or sub-directories in your project – this makes it easy to structure your code to maximize the bundling/minification benefits. Each directory by default can be accessed as a separate URL addressable bundle.

7

Page 11: 40540 ASP.netmvc4 Wb Newfeatures

Note:Bundling and Minification is a feature, which is exposed by the web platform and MVC just takes advantage of it.

Figure 6: ASP.NET Optimization - Bundling Install

© Microsoft Corporation. All rights reserved.8

Page 12: 40540 ASP.netmvc4 Wb Newfeatures

Database MigrationsASP.NET MVC 4 includes the new Entity Framework 4.3 release, which includes a bunch of great new features. One of the most eagerly anticipated features it provides is database migration support. This enables you to evolve your database schema using a code focused migration approach, while preserving the data within your database.

The Database Migration uses Entity Framework Code-First where you can change your code and then via Package Manager, add migrations and update your database as your code evolves.

We will see this feature using a walkthrough.

Walkthrough1. Create a new ASP.Net MVC 4 Internet website called MoviesSite.

2. Once the project has been created, click Visual Studio Tools, click Library Package Manager and then click Package Manager Console.

3. At the console prompt, run:

Update-package EntityFramework

By default, MVC 4 comes with EF 4.1. The update package command will update it to EF 4.3, which includes the Database Migrations.

4. Add a class to the Models folder in the project and name the class as Movie.cs.

5. Add a couple of properties to the class such as mentioned below:

namespace MoviesSite.Models{ public class Movie { public int ID { get; set; } public string Name { get; set; } }}

6. Starting with MVC 3, we can now build scaffolded controllers for our models.

7. Click Controllers folder and add a new scaffolded controller.

9

Page 13: 40540 ASP.netmvc4 Wb Newfeatures

Figure 7: Add Controller

This will create the controller and the corresponding view for the model. You can run the project now and browse to http://localhost:<your port>/Movie and you will see an interface as shown in the following figure:

Figure 8: Sample Web Page

You can add some records and the records will automatically be added into a SQL Server Express database. You can open the database in Server Explorer in the project and view the table structure and the records.

© Microsoft Corporation. All rights reserved.10

Page 14: 40540 ASP.netmvc4 Wb Newfeatures

Now let us consider that you want to add another field in the database schema called Genre. However, you want to preserve the existing data. To do that you would need to enable migrations.

8. Click Tools, click Library Package Manager, and then click Package Manager Console.

At the prompt, type:

Enable-Migrations

Enabling database migrations creates a new Migrations Folder in your Visual Studio Solution as well as an InitialCreate Target Migration that has both an Up and Down Migration. The Up Migration creates the Movie Table while the Down Migration drops the Movie Table.

namespace MoviesSite.Migrations{ using System.Data.Entity.Migrations; public partial class InitialCreate : DbMigration { public override void Up() { CreateTable( "Movies", c => new { ID = c.Int(nullable: false, identity: true), Name = c.String(), }) .PrimaryKey(t => t.ID); } public override void Down() { DropTable("Movies"); } }}

9. Now, you can add another field in your class.

namespace MoviesSite.Models{ public class Movie { public int ID { get; set; } public string Name { get; set; }

11

Page 15: 40540 ASP.netmvc4 Wb Newfeatures

public string Genre { get; set; } }}

10. Go back to your Package Manager console and type:

Add-Migration AddMovieGenreUpdate-Database

The Add-Migration command creates another file in the Migrations Folder of our ASP.NET MVC 4 Project and the Update-Database command updates the database with the new Genre column.

11. You can now either regenerate the scaffolding or just manually add the Genre field to the views and run the project.

12. You can modify your model and add as many named migrations as you want to and corresponding to each, a .cs file would be created like 201203112106276_AddMovieGenre.cs.

One of the advantages of this is that you can roll back to any named migration like this.

Update-database -TargetMigration "201203112106276_AddMovieGenre"

That would roll back the database to the named migration.

13. Database Migrations provide you with many features such as running SQL scripts against it, using a provider model so that you can use it for Oracle and MySQL.

Note:You can use Database Migrations outside of MVC as well. This is another web platform feature.

© Microsoft Corporation. All rights reserved.12

Page 16: 40540 ASP.netmvc4 Wb Newfeatures

ASP.Net Web APIASP.NET MVC 4 includes support for creating “Web APIs”. This enables you to easily create HTTP services and APIs that can be programmatically called from a broad range of clients (ranging from browsers using JavaScript, to native apps on any mobile/client platform).

The new Web API support also provides an ideal platform for building RESTful services.

Modern HTTP programming model: Directly access and manipulate HTTP requests and responses in your Web APIs using a new, strongly typed HTTP object model. The same programming model and HTTP pipeline is symmetrically available on the client through the new HttpClient type.

Full support for routes: Web APIs now support the full set of route capabilities that have always been a part of the Web stack, including route parameters and constraints. Additionally, mapping to actions has full support for conventions, therefore, you no longer need to apply attributes such as [HttpPost] to your classes and methods.

Content negotiation: The client and server can work together to determine the right format for data being returned from an API. We provide default support for XML, JSON, and Form URL-encoded formats, and you can extend this support by adding your own formatters, or even replace the default content negotiation strategy.

Model binding and validation: Model binders provide an easy way to extract data from various parts of an HTTP request and convert those message parts into .NET objects, which can be used by the Web API actions.

Filters: Web APIs now supports filters, including well-known filters such as the [Authorize] attribute. You can author and plug in your own filters for actions, authorization and exception handling.

Query composition: By simply returning IQueryable<T>, your Web API will support querying via the OData URL conventions.

Improved testability of HTTP details: Rather than setting HTTP details in static context objects, Web API actions can now work with instances of HttpRequestMessage and HttpResponseMessage. Generic versions of these objects also exist to let you work with your custom types in addition to the HTTP types.

Improved Inversion of Control (IoC) via DependencyResolver: Web API now uses the service locator pattern implemented by MVC’s dependency resolver to obtain instances for many different facilities.

Code-based configuration: Web API configuration is accomplished solely through code, leaving your configuration files clean.

13

Page 17: 40540 ASP.netmvc4 Wb Newfeatures

Self-host: Web APIs can be hosted in your own process in addition to IIS while still using the full power of routes and other features of Web API.

Walkthrough - Adding Web API in an Existing ProjectIn this walkthrough, we are going to expose our Movies as HTTP Web APIs.

1. Open the MoviesSite project that you created in the last section and add a folder called "APIs".

You can add the Web APIs anywhere in the project. However, we are going to put in a separate folder for logical grouping.

2. Add a new item of type Web API Controller Class (it is a new class template in MVC 4) to the APIs folder. We can call it MoviesController.cs.

You would have a class like this:

namespace MoviesSite.apis.Controllers{ public class MoviesController : ApiController { }}

This class inherits from the ApiController class which is a base class provided in MVC 4

3. Now we would implement action methods to expose web APIs. We will add to get methods to return our movies from the database. This is what the class looks like.

using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.Web.Http;using MoviesSite.Models;

namespace MoviesSite.apis.Controllers{ public class MoviesController : ApiController { MovieDBContext db = new MovieDBContext();

public IQueryable<Movie> Get() { return db.Movies; }

public Movie Get(int id)

© Microsoft Corporation. All rights reserved.14

Page 18: 40540 ASP.netmvc4 Wb Newfeatures

{ return db.Movies.Single(p=>p.ID == id); } }}

4. We can run this project now but we would be using Fiddler to call our REST APIs.

a. Start Fiddler.

b. Go to composer.

c. Put in a URL as shown below.

i. http://localhost:45182/api/movies

You should see a JSON view as shown in the following figure:

Figure 9: JSON View

You can also look at the Raw view which would look something like below.

HTTP/1.1 200 OKServer: ASP.NET Development Server/10.0.0.0Date: Sun, 11 Mar 2012 23:08:41 GMTX-AspNet-Version: 4.0.30319Transfer-Encoding: chunkedCache-Control: no-cachePragma: no-cacheExpires: -1Content-Type: application/json; charset=utf-8Connection: Close

66[{"Genre":null,"ID":1,"Name":"Silence of the Lamb"},{"Genre":null,"ID":2,"Name":"North by Northwest"}]0

15

Page 19: 40540 ASP.netmvc4 Wb Newfeatures

5. If you want an XML output instead of JSON, you can pass in an Accept header to indicate what kind of output you want.

User-Agent: FiddlerHost: localhost:45182Accept: application/xml

Now, you would get an output as shown below.

HTTP/1.1 200 OKServer: ASP.NET Development Server/10.0.0.0Date: Sun, 11 Mar 2012 23:18:15 GMTX-AspNet-Version: 4.0.30319Transfer-Encoding: chunkedCache-Control: no-cachePragma: no-cacheExpires: -1Content-Type: application/xml; charset=utf-8Connection: Close

117<?xml version="1.0" encoding="utf-8"?><ArrayOfMovie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Movie><ID>1</ID><Name>Silence of the Lamb</Name></Movie><Movie><ID>2</ID><Name>North by Northwest</Name></Movie></ArrayOfMovie>0

The main advantage, as you can see, is that we did not have to make any changes in the application to display different formats.

6. We can implement a generic HTTP based format and it can be consumed by different clients in whatever format it is acceptable to them.

7. Doing a POST to the service is equally simple. Create a method in the class shown below.

public Movie Post(Movie m){ db.Movies.Add(m); db.SaveChanges();

return m;}

8. Now you can go back to Fiddler > Composer and change the request type to POST and the request URL to http://localhost:45182/api/Movies.

© Microsoft Corporation. All rights reserved.16

Page 20: 40540 ASP.netmvc4 Wb Newfeatures

In the request body, you can put in some JSON content like this.

{"Name":"Pirates of the Caribbean","Genre":"Adventure"}And add a header Content-type: application/json

Now when you execute the request, it would be posted and saved to the database. You can later browse the website to verify that the new record has been added.

9. The Web API also lets you specify custom HTTP headers and HTTP Response codes in accordance with the REST protocol. In our example, we can specify some additional options in the code as shown below.

public HttpResponseMessage<Movie> Post(Movie m) { db.Movies.Add(m); db.SaveChanges(); var result = new HttpResponseMessage<Movie>(m, HttpStatusCode.Created); result.Headers.Location = new Uri(Request.RequestUri, "/api/Movies/" + m.ID.ToString());

return result; }

This code snippet is doing two things.

o Changing the HTTP status code to 201 indicating that an object has been created.

o Adding a location header to the request headers, which allows you to browse to that entry directly.

HTTP/1.1 201 CreatedServer: ASP.NET Development Server/10.0.0.0Date: Mon, 12 Mar 2012 20:18:29 GMTX-AspNet-Version: 4.0.30319Location: http://localhost:45182/api/Movies/5Cache-Control: no-cachePragma: no-cacheExpires: -1Content-Type: application/json; charset=utf-8Connection: Close

{"Genre":"Adventure","ID":5,"Name":"Harry Potter and the Chamber of Secrets"}

17

Page 21: 40540 ASP.netmvc4 Wb Newfeatures

The purpose of this walkthrough was to demonstrate that Web API provides a clean and easy way to build REST services in your application, which can be consumed by multiple clients. You can use the standard ASP.Net features such as URL authorization.

Calling a HTTP Service From JavaScript and jQuery1. For your MoviesSite project, in the Solution Explorer, expand the Views folder

and the Home folder under it.

a. You should see a file named Index.cshtml.

b. Open the file for editing and remove all content from it.

c. We will use JavaScript and jQuery to build the view.

2. Add the following HTML to the page.

<!DOCTYPE html> <html lang="en"> <head> <title>ASP.NET Web API</title> <script src="../../Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>

</head> <body> <div> <h1>All Movies</h1> <ul id='movies' /> </div> </body> </html>

3. To get a list of products, we need to send a HTTP GET request to "/api/movies".

You can do this with jQuery as follows:

<script type="text/javascript"> $(document).ready(function () { // Send an AJAX request $.getJSON("api/movies/", function (data) { // On success, 'data' contains a list of movies. $.each(data, function (key, val) {

// Format the text to display. var str = val.Name + ': ' + val.Genre;

// Add a list item for the movie. $('<li/>', { html: str }) .appendTo($('#movies')); });

© Microsoft Corporation. All rights reserved.18

Page 22: 40540 ASP.netmvc4 Wb Newfeatures

}); }); </script>

The getJSON function sends the AJAX request. The response will be an array of JSON objects. The second parameter to getJSON is a callback function that is invoked when the request successfully completes.

4. Now, you can run the application and you would see an output as shown below.

Figure 10: Output View

Routing in ASP.Net Web APIThe Web API routing is very similar to routing in ASP.Net MVC. The main difference is that Web API uses the HTTP method, not the URI path, to select the action. We can also use MVC-style routing in Web API.

To determine which action to invoke, the framework uses a routing table. If you are hosting Web API from ASP.NET, the routing table is located in the Global.asax file. By default when you use Visual Studio to create a new Web API project, the project template creates a default route for us.

routes.MapHttpRoute(

19

Page 23: 40540 ASP.netmvc4 Wb Newfeatures

name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );

Each entry in the routing table contains a route template. The default route template for Web API is "api/{controller}/{id}". In this template, "api" is a literal path segment, and {controller} and {id} are placeholder variables.

When the Web API framework receives an HTTP request, it tries to match the URI against one of the route templates in the routing table. If no route matches, the client receives a 404 error.

For example, the following URIs match the default route.

/api/contacts /api/contacts/1 /api/products/gizmo1

However, the following URI does not match, because it lacks the "api" segment.

/contacts/1

Note:The reason for using "api" in the route is to avoid collisions with the ASP.Net MVC routing. That way we can have "/contacts" go to a MVC controller, and "/api/contacts" go to a Web API controller. Of course, if we do not like this convention, we can always change the default route table.

Once a matching route is found, Web API selects the controller and the action.

To find the controller, Web API adds "Controller" to the value of the {controller} variable.

To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name.

For example, with a GET request, Web API looks for an action that starts with "Get...", such as "GetContact" or "GetAllContacts". This convention applies only to GET, POST, PUT, and DELETE methods. We can enable other HTTP methods by using attributes on your controller. We will see an example of that later.

Other placeholder variables in the route template, such as {id}, are mapped to action parameters.

© Microsoft Corporation. All rights reserved.20

Page 24: 40540 ASP.netmvc4 Wb Newfeatures

Table 1: Some Possible HTTP Requests Along With the Action That Gets Invoked for Each

HTTP Method URI Path Action Parameter

GET Api/movies GetAllMovies (none)

GET Api/movies/4 GetMovieById 4

DELETE Api/movies/4 DeleteMovie 4

POST Api/movies Post

Routing VariationsHTTP Methods

Instead of using the naming convention for HTTP methods, you can explicitly specify the HTTP method for an action by decorating the action method with the HttpGet, HttpPut, HttpPost, or HttpDelete attribute.

[HttpGet]public Movie FindMovie(int id) { return db.Movies.Single(p=>p.ID == id); }

To allow multiple HTTP methods for an action, or to allow HTTP methods other than GET, PUT, POST and DELETE, we can use the AcceptVerbs attribute, which takes a list of HTTP methods:

[AcceptVerbs("GET", "HEAD")]public Movie Get(int id) { return db.Movies.Single(p=>p.ID == id); }

Routing by Action NameWith the default routing template, Web API uses the HTTP method to select the action. However, you can also create a route where the action name is included in the URI:

routes.MapHttpRoute( name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } );

21

Page 25: 40540 ASP.netmvc4 Wb Newfeatures

In this route template, the {action} parameter names the action method on the controller. With this style of routing, you must use attributes to specify the allowed HTTP methods. For example, suppose your controller has the following method:

public class MoviesController : ApiController { [HttpGet] public string Details(int id);

In this case, a GET request for "api/movies/details/1" would map to the details method. This style of routing is similar to ASP.NET MVC, and may be appropriate for an RPC-style API. For a RESTful API, you should avoid using verbs in the URIs, because a URI should identify a resource, not an action.

© Microsoft Corporation. All rights reserved.22

Page 26: 40540 ASP.netmvc4 Wb Newfeatures

Razor EnhancementsASP.Net MVC 4 includes V2 of the Razor View engine. Razor V2 includes a bunch of enhancements that enable you to make your view templates even cleaner and more concise - including better support for resolving URL references and selectively rendering HTML attributes. We will discuss about a couple of enhancements in this training.

1. The new "~/" feature of Razor 2

Till MVC 3, we had to use Url.Content("~/…") or @Href("~/…") when specifying relative paths in the View. Now you can just use "~/" which eliminates a lot of noise in your Razor Views.

You can open up _Layout.cshtml in your default project and you will see a reference as shown below.

<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />

Razor will automatically convert this relative path into an absolute path for you.

2. Conditional attribute rendering

If you have an attribute that might be null, in the past you will need to do a null check to avoid writing out an empty attribute, as shown below:

<div @{if (myClass != null) { <text>class="@myClass"</text> } }>Content</div>

Now Razor is able to handle that automatically, so you can just write out the attribute. If it is null, the attribute is not written:

<div class="@myClass">Content</div>

Therefore, if @myClass is null, the output is just this:

<div>Content</div>

23

Page 27: 40540 ASP.netmvc4 Wb Newfeatures

ASP.Net Single Page ApplicationSingle Page applications are rich, responsive applications combining the best of web and desktop, built with HTML5 and JavaScript.

Some of the benefits of using SPA are:

Great user experience in terms of speed so that when you navigate around it feels like a native application.

Since it is built with HTML and JavaScript, it can run on any device starting from IE 6 onwards.

Can work offline.

App-store deployable.

To provide a better end-to-end experience for building applications, it provides:

1. A set of JavaScript libraries for richer local interactions with cached data.

The JavaScript libraries include existing popular ones such as Knockout and History and a relatively new library called Upshot (formerly previewed as RIA/JS). Together they support presentation and editing of data across a set of pages that interact with local and remote data. They illustrate one prescriptive pattern of using distinct libraries together. You could also use them independently or replace one or more of them.

For example, Upshot could be used with JsViews or jQuery UI or ISV controls and jQuery could be replaced with XUI. Some of the replacements may require some adaptation via a small library.

2. Additional Web API components for unit of work and DAL support.

On the server-side, a new class called DataController, which derives from ApiController, provides:

Support for insert.

Update and delete operations in a unit of work with transaction support and automatic validations.

A way to get the total count for paging along with the first page.

A foundation for DAL-specific implementation of the features above.

For example, DbController is a DataController that implements the above for Entity Framework Code First style of data access.

3. A MVC project template with scaffolding to get started quickly.

© Microsoft Corporation. All rights reserved.24

Page 28: 40540 ASP.netmvc4 Wb Newfeatures

A new MVC project template for Single Page Application provides an educational tool and a way to start quickly. The template includes:

Scaffolding to generate a skeletal app that includes a DataController, optionally an Entity Framework DbContext and the scripts for basic query and edit tasks (CRUD operations).

A sample model class that you could use as is or replace with your favorite one to get started.

Figure 11: SPA Architecture

Walkthrough - Creating Our First Single Page Application1. Create a new MVC 4 application and name it as SPASample, and then select the

Single Page Application template.

25

Page 29: 40540 ASP.netmvc4 Wb Newfeatures

Figure 12: Template Selection

2. Once the project is created, you will notice that it is similar to any MVC application. The only difference is that it has a few move JavaScript libraries which are listed below.

Navigation and history - history.js and nav.js

MVVM - knockout.js

Rich data access and caching - upshot.js

DOM/Ajax basics - jQuery/XUI

It also provides a Model class called ToDoItem.cs, which provides instructions on how you can get started with creating a SPA application. We are going to use that sample model class in our walkthrough.

3. To create the sample, we can just follow the instructions in ToDoItem.cs.

a. Right-click Controllers folder and select Add a Controller.

© Microsoft Corporation. All rights reserved.26

Page 30: 40540 ASP.netmvc4 Wb Newfeatures

Figure 13: Adding a Controller

Note:We now have a new template called Single Page Application with read/write actions and views using Entity Framework. Once we have the controller and corresponding files created, we can run the project and browse to:

http://localhost:58435/Todo

We should get a CRUD interface to add, edit and delete the To do items.

Figure 14: To Do Items

There is nothing fancy in this other than the fact that if we do any action or navigate back forth, no request is being sent to the server and it is all happening on the client

27

Page 31: 40540 ASP.netmvc4 Wb Newfeatures

side. You can easily verify that by running F12. Since we are not communicating back to the server, our page performance would be much better.

Walkthrough - Building Data ServicesThe figure below shows how the data service architecture looks like:

Figure 15: Data Service Architecture

On the server, we are exposing Web API to expose our model data. We have a standard class called DbDataController, which is an easy way to expose database functionality. We just need to point it to an Entity Framework database and it will do the rest.

On the client side to consume that data, we have a JavaScript library called upshot.js and the main class in it is called DataSource. We create an instance of DataSource and it knows how to talk to the server.

This and the next three walkthroughs will use a partially built project called DeliveryTracker:

1. Open DeliveryTracker.sln from the Labs folder.

2. Open the Package Manager console and run this command.

Install-Package SinglePageApplication.CSharp

The main model that we will be working with is a class called Delivery, which is in the DomainModels.cs.

namespace DeliveryTracker.Models{ public class Customer { public int CustomerId { get; set; }

© Microsoft Corporation. All rights reserved.28

Page 32: 40540 ASP.netmvc4 Wb Newfeatures

public string Name { get; set; } public string Address { get; set; } }

public class Delivery { // Primary key, and one-to-many relation with Customer public int DeliveryId { get; set; } public virtual int CustomerId { get; set; } public virtual Customer Customer { get; set; }

// Properties for this delivery public string Description { get; set; } public bool IsDelivered { get; set; } // <-- This is what we're mainly interested in }}

The database context is in AppDbContext.cs.

public partial class AppDbContext : DbContext{ public DbSet<Customer> Customers { get; set; } public DbSet<Delivery> Deliveries { get; set; }}

This is using the Entity Framework syntax for our model classes.

3. We are going to start by adding a new Web API controller, which is not scaffolded.

Figure 16: Adding New Web API Controller

29

Page 33: 40540 ASP.netmvc4 Wb Newfeatures

We are going to change the class from which this controller inherits to look as shown below:

public class DataServiceController : DbDataController<AppDbContext>{ }

4. We are going to create some action methods in this class.

public IQueryable<Delivery> GetDeliveriesForToday(){ // Could pre-filter by due date, delivery driver, etc... return DbContext.Deliveries.OrderBy(x => x.DeliveryId);}

This is a public method, which returns the deliveries for today.

5. We also want to allow users to add, update and delete deliveries so we need to add standard getter and setter methods for that.

// Put your custom access control logic in these methodspublic void InsertDelivery(Delivery delivery) { InsertEntity(delivery); }public void UpdateDelivery(Delivery delivery) { UpdateEntity(delivery); }public void DeleteDelivery(Delivery delivery) { DeleteEntity(delivery); }

Now, we are ready to run this application.

6. We can open up Fiddler and compose a URL as shown below:

http://localhost:2240/api/DataService/GetDeliveriesForToday

We should see a view as in figure 17:

© Microsoft Corporation. All rights reserved.30

Page 34: 40540 ASP.netmvc4 Wb Newfeatures

Figure 17: Request Headers TextView

Note:We specified Content-Type as application/xml. The default view in case we do not specify the content-type would be JSON.

We can also do some OData queries on the view in the link below:

http://localhost:2240/api/DataService/GetDeliveriesForToday?$filter=CustomerId+eq+1

This would filter out deliveries for Customer ID 1.

7. One thing that you would notice is that though we are returning the customer ID for each delivery, we are not displaying the customer information. We can do that by simply modifying query using standard Entity Framework syntax such as:

public IQueryable<Delivery> GetDeliveriesForToday() { // Could pre-filter by due date, delivery driver, etc... return DbContext.Deliveries.Include("Customer").OrderBy(x => x.DeliveryId); }

Now if you run the URL in Fiddler again, you would see the customer information together with the delivery information.

8. Now let us consider we want to build a proper user interface. We would need to write some JavaScript, which can consume our Web API and display all the deliveries. Open up Index.cshtml and we are going to write some code, which would bind Upshot to the data service. Insert this line of code in the View - index.cshtml.

31

Page 35: 40540 ASP.netmvc4 Wb Newfeatures

@(Html.UpshotContext().DataSource<DataServiceController>(x => x.GetDeliveriesForToday()))

In this line of code, we are binding Upshot to our Data service controller and specifying the endpoint as GetDeliveriesForToday.

9. Then we have to write some JavaScript that would display the following data.

<script type="text/javascript"> $(function () { var dataSource = upshot.dataSources.DeliveriesForToday; dataSource.refresh(function (results) { alert(results); }); });</script>

In this script, we are opening up a function context and grabbing a data source from upshot, which we registered earlier. Then we refresh the upshot data context, which returns the results of the asynchronous database call and we are printing the results to the screen using an alert.

When you run this, you will see the message shown in figure 18:

Figure 18: Message From Webpage

This is because the alert box does not really know how to interpret the data. However, if you run F12 or HttpWatch, you will see that we got back the results back in JSON format.

© Microsoft Corporation. All rights reserved.32

Page 36: 40540 ASP.netmvc4 Wb Newfeatures

Figure 19: Delivery Tracker

Walkthrough - Building a User Interface Using Knockout and Upshot

In this walkthrough, we are going to build a user interface to the last project that we build. To create the user interface, we are going to use a concept called MVVM, which stands for Model-View-ViewModel.

Figure 20: Model-View-ViewModel

In this, the model is provided my Upshot - the view, which is the HTML and something in the middle, which negotiates between the model and the view. The ViewModel will contain your

33

Page 37: 40540 ASP.netmvc4 Wb Newfeatures

application logic. We are going to use Knockout for our ViewModel, which exposes an API called observable.

1. Open the DeliveryTracker application that we built in the last walkthrough.

2. Open index.cshtml and replace the existing JavaScript function with this.

<script type="text/javascript"> $(function () { function DeliveriesViewModel() { // Private var self = this; var dataSource = upshot.dataSources.DeliveriesForToday.refresh();

// Public self.deliveries = dataSource.getEntities(); }

ko.applyBindings(new DeliveriesViewModel()); });</script>

Here we are defining a JavaScript function called DeliveriesViewModel that is also acting as a class constructor. This function is exposing a public member called deliveries that is populated from the Upshot data source. This time, we are returning entities, which are returned as an Observable array, which means that if the backend data source changes, the entities would change as well.

3. Now to actually display the data, we can add some HTML such as:

<ol data-bind="foreach: deliveries"> <li> <strong data-bind="text: Description"></strong> </li></ol>

You can now run the application and you would see a list of deliveries as shown in the following figure:

© Microsoft Corporation. All rights reserved.34

Page 38: 40540 ASP.netmvc4 Wb Newfeatures

Figure 21: List of Deliveries

Note:Since this is all declarative, you can easily make the user interface more sophisticated without doing any kind of DOM manipulations.

To add customer information to these deliveries, edit the HTML.

<ol data-bind="foreach: deliveries"> <li> <strong data-bind="text: Description"></strong> is for <em data-bind="text: Customer().Name"></em> </li></ol>

Now, you will get the customer name for each delivery as shown in the following figure:

35

Page 39: 40540 ASP.netmvc4 Wb Newfeatures

Figure 22: List of Deliveries With the Customer Name for Each

4. The real power of Upshot is the ability to render different kinds of views to the client without having to go to the server. Therefore, we want to group these deliveries by customer. Before we proceed, let us refactor the code a little to make it cleaner. Inside the Scripts folder create a new folder called Apps and add a new Jscript file to it called DeliveriesViewModel.js. Add our JavaScript class in it.

function DeliveriesViewModel() { // Data var self = this; self.dataSource = upshot.dataSources.DeliveriesForToday.refresh(); self.deliveries = self.dataSource.getEntities();}

5. Change the JavaScript in index.cshtml to add the reference.

<script src="~/Scripts/App/DeliveriesViewModel.js" type="text/javascript"></script><script type="text/javascript"> $(function () { ko.applyBindings(new DeliveriesViewModel()); });</script>

© Microsoft Corporation. All rights reserved.36

Page 40: 40540 ASP.netmvc4 Wb Newfeatures

At this point, your application should continue to work - just be a bit better refactored.

6. Now, to group the deliveries by customer, add a line to the DeliveriesViewModel JavaScript function.

function DeliveriesViewModel() { // Data var self = this; self.dataSource = upshot.dataSources.DeliveriesForToday.refresh(); self.deliveries = self.dataSource.getEntities(); self.deliveriesForCustomer = self.deliveries.groupBy("Customer");}

That line will return an array, which has a key called customer and contain the deliveries for that customer.

7. The next step is to create some view mockup that uses this. Go back to index.cshtml and add another unordered list for the grouping by customers.

<h3>Customers</h3><ul data-bind="foreach: deliveriesForCustomer"> <li> <div>Name: <strong data-bind="text: key.Name"></strong></div> <ul data-bind="foreach: values"> <li data-bind="text: Description"></li> </ul> </li></ul>

We should see the grouping by customer now as shown in the following figure.

37

Page 41: 40540 ASP.netmvc4 Wb Newfeatures

Figure 23: Grouping of Customers

8. One of the cool Upshot features is data editing. We want to add a checkbox to the interface that will let the drivers update the items, which have been delivered. Start by adding a checkbox to index.cshtml.

<ol data-bind="foreach: deliveries"> <li> <strong data-bind="text: Description"></strong> is for <em data-bind="text: Customer().Name"></em> <label> <input data-bind="checked: IsDelivered" type="checkbox" /> Delivered </label> </li></ol>

If you run the application now, it will show the checkbox indicating which items have been delivered or not.

9. If you want to highlight the items that have been delivered, you can use a CSS binding with any of the HTML elements. We are going to use a binding with our <li> element to highlight that the item has been delivered.

<li data-bind="css: { delivered: IsDelivered }">

This will toggle the CSS on or off depending on whether it is set or not.

© Microsoft Corporation. All rights reserved.38

Page 42: 40540 ASP.netmvc4 Wb Newfeatures

10. You can run the application, and check and uncheck deliveries that would change toggle the CSS. However, whatever changes you make will not be saved to the database as we have not yet written the code for it. You can use Upshot to save changes in one of 2 ways

a. Save changes implicitly

b. Save changes only when you ask it to. This is the default option.

11. To save changes immediately, edit the Upshot data source line to:

@(Html.UpshotContext(bufferChanges: false) .DataSource<DataServiceController>(x => x.GetDeliveriesForToday()))

Now you can run the application and make changes and it will be saved automatically to the database.

If you run F12 or any other tool, you would notice that each time you check/uncheck, a Submit method would be called as shown in figure 24.

Figure 24: Calling of the Submit Method

In other words, data is being immediately synchronized with the backend.

12. If you want to do an explicit save, change the Upshot data source binding and add buttons to perform the operation.

@(Html.UpshotContext(bufferChanges: true) .DataSource<DataServiceController>(x => x.GetDeliveriesForToday()))

<button data-bind="click: saveAll">Save All</button><button data-bind="click: revertAll">Revert All</button>

Now, we can define the methods for saveAll and revertAll as shown below:

function DeliveriesViewModel() { // Data var self = this; self.dataSource = upshot.dataSources.DeliveriesForToday.refresh(); self.deliveries = self.dataSource.getEntities(); self.deliveriesForCustomer = self.deliveries.groupBy("Customer");

39

Page 43: 40540 ASP.netmvc4 Wb Newfeatures

// Operations self.saveAll = function () { self.dataSource.commitChanges() }; self.revertAll = function () { self.dataSource.revertChanges() };}

Now, the Submit will happen only when you click Submit and all changes will be saved at one go.

13. The next step is to use filtering options provided by Upshot. We want to modify our application to exclude items that have been delivered. Add a checkbox to the interface.

<label><input data-bind="checked: excludeDelivered" type="checkbox"/> Hide delivered items</label>

We now need to create the excludeDelivered property in our View Model. Therefore, we can go over to DeliveriesViewModel.js and add.

self.excludeDelivered = ko.observable(false);

It is marked as observable since we want to be notified when it changes and we start out by excluding nothing.

The next step would be to subscribe to the notification and use the Upshot filter code. Add the following lines in your JavaScript method.

self.excludeDelivered.subscribe(function (shouldExcludeDelivered) { var filterRule = shouldExcludeDelivered ? { property: "IsDelivered", operation: "==", value: false } : null; self.dataSource.setFilter(filterRule); self.dataSource.refresh(); });

This function is setting the upshot filter based on the value of the checkbox. However, if you run F12, you will notice that every time you check/uncheck, it would make a backend call to the server to refresh the data source. Another nice feature of Upshot is that it can do queries locally since it has already fetched the data.

Create a local data source such as:

© Microsoft Corporation. All rights reserved.40

Page 44: 40540 ASP.netmvc4 Wb Newfeatures

self.localDataSource = upshot.LocalDataSource({ source: self.dataSource, autoRefresh: true });

Now you can do the filter of the local data source rather that of the server.

self.excludeDelivered.subscribe(function (shouldExcludeDelivered) { var filterRule = shouldExcludeDelivered ? { property: "IsDelivered", operation: "==", value: false } : null; self.localDataSource.setFilter(filterRule); self.localDataSource.refresh(); });

This would minimize the number of calls going to the backend database. Thus, we are achieving the goal of Single Page Application - the UI is rendered on the client and we talk to the server as little as possible.

Walkthrough - Using Display Modes With SPAMVC 4 introduces a new feature called Display Modes that lets an application select views depending on the browser that is making the request. For example, if a desktop browser requests the Home page, the application might use the Views\Home\Index.cshtml template. If a mobile browser requests the Home page, the application might return the Views\Home\Index.mobile.cshtml template.

Layouts and partials can also be overridden for particular browser types. We are going to create a Mobile View for our DeliveryTracker application.

1. Copy the index.cshtml and rename it to index.mobile.cshtml. The framework will now use that View for the requests that come from mobile devices.

2. In the index.mobile.cshtml, we will start by using a more simplified markup to indicate that this is a mobile device. We will add the following markup.

@using DeliveryTracker.Controllers@(Html.UpshotContext(bufferChanges: false).DataSource<DataServiceController>(x => x.GetDeliveriesForToday()))

<div class="content"> <h4>Hello</h4> This is the <strong>mobile</strong> layout</div>

<script src="~/Scripts/App/DeliveriesViewModel.js" type="text/javascript"></script><script type="text/javascript"> $(function () {

41

Page 45: 40540 ASP.netmvc4 Wb Newfeatures

ko.applyBindings(new DeliveriesViewModel()); });</script>

Now if you refresh the page on IE, you will still see the old page. However, if you browse to the page on a Windows Phone emulator, you should see the mockup.

3. Now instead of one large page, we want to display smaller pages, which fit into the mobile screen. Therefore, we need modify our ViewModel. Open DeliveriesViewModel.js and create a new function.

function MobileDeliveriesViewModel() { // Inherits from DeliveriesViewModel var self = this; DeliveriesViewModel.call(self);

// Data self.nav = new NavHistory({ params: { view: 'deliveries' } });

self.nav.Initailize({ linkToUrl: true });}

This function inherits from DeliveriesViewModel. We are using History.js and nav.js to provide navigation functionality in this function.

4. Copy the _Layout.cshtml and rename it to _Layout.mobile.cshtml. Put in this code into it.

<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8" /> <title>Deliveries</title> <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" /> <link href="~/Content/Site.Mobile.css" rel="stylesheet" type="text/css" /> @Html.Partial("_SpaScripts") </head> <body> <nav class="bar"> <ul> <li>Deliveries</li> </ul> </nav>

@RenderBody() </body></html>

© Microsoft Corporation. All rights reserved.42

Page 46: 40540 ASP.netmvc4 Wb Newfeatures

This simply puts in a different CSS for our mobile site.

5. We need to use the new function in Index.mobile.cshtml.

<div class="content"> <h4>Hello</h4> This is the <strong>mobile</strong> layout

Current View parameter is: <strong data-bind="text: nav.params().view"></strong></div>

<script src="~/Scripts/App/DeliveriesViewModel.js" type="text/javascript"></script><script type="text/javascript"> $(function () { ko.applyBindings(new MobileDeliveriesViewModel()); });</script>

Basically, we are displaying a view parameter and calling MobileDeliveriesViewModel.

If we run the application, it should show something like the following figure:

Figure 25: View Parameter

Note:We can also change the User-Agent string in IE9 to something like this Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; and we would switch to Mobile View.

6. Now, we will go and add multiple view parameters. On your layout.mobile.cshtml, add code to create another list element and call a JavaScript function on its click event.

43

Page 47: 40540 ASP.netmvc4 Wb Newfeatures

<nav class="bar"> <ul> <li data-bind="click: showDeliveries">Deliveries</li> <li data-bind="click: showCustomers">Customers</li> </ul></nav>

We will define these functions in our ViewModel.

function MobileDeliveriesViewModel() { // Inherits from DeliveriesViewModel var self = this; DeliveriesViewModel.call(self);

// Data self.nav = new NavHistory({ params: { view: 'deliveries' } });

// Operations self.showDeliveries = function() { self.nav.navigate({ view: 'deliveries' }) }; self.showCustomers = function () { self.nav.navigate({ view: 'customers' }) };

self.nav.initialize({ linkToUrl: true });}

Now if you run this application and click Customers, you would see that the URL changed and a different View parameter is displayed.

7. The only thing left to complete this application is to add the markup in Index.mobile.cshtml, which displays the actual data. You can open the completed project from the Labs folder. The logic remains the same as what we did in Index.cshtml. The only difference is the code such as the following.

<div data-bind="if: nav.params().view == 'deliveries'"> @Html.Partial("_DeliveriesList")</div>

We have created a couple of partial Views for deliveries and customers. The markup is checking for navigation parameter and displaying the appropriate view.

© Microsoft Corporation. All rights reserved.44

Page 48: 40540 ASP.netmvc4 Wb Newfeatures

Recipes to Customize Code GenerationThe new recipes feature enables Visual Studio to generate solution-specific code based on packages that you can install using NuGet. The recipes framework makes it easy for developers to write code-generation plugins, which you can also use to replace the built-in code generators for Add Area, Add Controller, and Add View. Since recipes are deployed as NuGet packages, they can easily be checked into source control and shared with all developers on the project automatically. They are also available on a per-solution basis.

Recipes are assemblies that are dynamically loaded into Visual Studio by the Managed Extensibility Framework, otherwise known as MEF. MEF provides a plugin model for applications and is one of the primary ways to extend Visual Studio.

Walkthrough - Creating a RecipeThe steps that we will follow to build a recipe are:

1. Create a class library.

2. Reference the assembly that contains the recipe framework types. At this time, the assembly is Microsoft.VisualStudio.Web.Mvc.Extensibility.1.0.dll.

3. Write a class that implements the IRecipe interface or one of the interfaces that derive from IRecipe such as IFolderRecipe or IFileRecipe. These interfaces are in the Microsoft.VisualStudio.Web.Mvc.Extensibility.Recipes namespace. These are the recipes that are launched from the context of a folder.

4. Implement the logic to show your recipe’s dialog. This could be a Windows Forms dialog or a Windows Presentation Foundation (WPF) dialog.

5. Add the MEF ExportAttribute to the class to export the IRecipe interface.

6. Package up the whole thing in a NuGet package and make sure the assembly ends up in the recipes folder of the package, rather than the usual lib folder.

A Package to Create a Recipe1. Create a new Class library project called RecipeLibrary.

2. Open up the Package Manager Console and run this command.

Install-package AspNetMvc4.RecipeSdk

Note:This updates the class library project with necessary files and assembly references to get started writing a recipe. Typically, it adds a reference to

45

Page 49: 40540 ASP.netmvc4 Wb Newfeatures

Microsoft.VisualStudio.Web.Mvc.Extensibility.1.0.dll and adds a MyRecipe.cs file and a MyRecipe.nuspec file. It also added a reference to System.Windows.Forms.

3. The following is the code for MyRecipe.cs.

using System;using System.ComponentModel.Composition;using System.Drawing;using Microsoft.VisualStudio.Web.Mvc.Extensibility;using Microsoft.VisualStudio.Web.Mvc.Extensibility.Recipes;

namespace RecipeLibrary { [Export(typeof(IRecipe))] public class MyRecipe : IFolderRecipe { public bool Execute(ProjectFolder folder) { throw new System.NotImplementedException(); }

public bool IsValidTarget(ProjectFolder folder) { throw new System.NotImplementedException(); }

public string Description { get { throw new NotImplementedException(); } }

public Icon Icon { get { throw new NotImplementedException(); } }

public string Name { get { throw new NotImplementedException(); } } }}

Most of these properties are self-explanatory. They provide metadata for a recipe that appear when a user launches the Add recipe dialog.

The two most interesting methods are IsValidTarget and Execute. The first method determines whether the folder that the recipe is launched from is valid for that recipe. This allows you to filter recipes. For example, suppose your recipe only makes sense when launched from a view folder. You can implement that method like so:

public bool IsValidTarget(ProjectFolder folder) { return folder.IsMvcViewsFolderOrDescendent();}

© Microsoft Corporation. All rights reserved.46

Page 50: 40540 ASP.netmvc4 Wb Newfeatures

The IsMvcViewsFolderOrDescendant is an extension method on the ProjectFolder type in the Microsoft.VisualStudio.Web.Mvc.Extensibility namespace.

The general approach we took was to keep the ProjectFolder interface generic and then add extension methods to layer on behavior specific to ASP.NET MVC. This provides a nice simple façade to the Visual Studio Design Time Environment.

4. The other important method to implement is Execute. This is where the meat of your recipe lives. The basic pattern here is to create a Windows Form (or WPF Form) to display to the user. That form might contain all the interactions that a user needs, or it might gather data from the user and then perform an action.

Packaging it UpYou can use NuGet.exe to run the following command:

Nuget pack MyRecipe.nuspec

After this, you can run NuGet push to publish the package to Nuget.org

Using a RecipeTo install the recipe:

1. Right click the solution node in Solution Explorer.

2. Select Manage NuGet Packages.

3. Find the package and click Install.

This installs the NuGet package with the recipe into the solution.

To run the recipe:

1. Right-click a folder and select Add.

2. Select Run Recipe.

47

Page 51: 40540 ASP.netmvc4 Wb Newfeatures

Task Support for Asynchronous ControllersYou can now write asynchronous action methods as single methods that return an object of type Task or Task<ActionResult>. Visual Studio Async is available in the Visual Studio 11 Developer Preview or as a separate CTP download for Visual Studio 2010 SP1. It provides streamlined syntax for asynchronous development in C# and Visual Basic.

For example, you can create an asynchronous method that looks like the following:

public async Task<ActionResult> Index(string city) { var newsService = new NewsService(); var sportsService = new SportsService(); return View("Common", new PortalViewModel { NewsHeadlines = await newsService.GetHeadlinesAsync(), SportsScores = await sportsService.GetScoresAsync() });}

The calls to newsService.GetHeadlinesAsync and sportsService.GetScoresAsync are called asynchronously and do not block a thread from the thread pool.

Asynchronous action methods that return Task instances can also support timeouts. To make your action method cancellable, add a parameter of type CancellationToken to the action method signature. The following example shows an asynchronous action method that has a timeout of 2500 milliseconds and that displays a TimedOut view to the client if a timeout occurs.

[AsyncTimeout(2500)] [HandleError(ExceptionType = typeof(TaskCanceledException), View = "TimedOut")]public async Task<ActionResult> Index(string city, CancellationToken cancellationToken) { var newsService = new NewsService(); var sportsService = new SportsService(); return View("Common", new PortalViewModel { NewsHeadlines = await newsService.GetHeadlinesAsync(cancellationToken), SportsScores = await sportsService.GetScoresAsync(cancellationToken) });}

The Visual Studio Async features are covered in more detail in a separate training.

© Microsoft Corporation. All rights reserved.48

Page 52: 40540 ASP.netmvc4 Wb Newfeatures

Module ReviewTopics covered in this module include the following:

New MVC Project Templates

Bundling and Minification features

Database Migrations

ASP.Net Web API

Razor enhancements

Single Page Applications

Creating Recipes

49