Pro ASP.NET MVC 3 Framework

3rd Edition

By Steven Sanderson , Adam Freeman

Pro ASP.NET MVC 3 Framework Cover Image

The ASP.NET MVC 3 Framework is the latest evolution of Microsoft’s ASP.NET web platform. It provides a high-productivity programming model that promotes cleaner code architecture, test-driven development, and powerful extensibility, combined with all the benefits of ASP.NET 4.

Full Description

  • ISBN13: 978-1-4302-3404-3
  • 852 Pages
  • User Level: Intermediate to Advanced
  • Publication Date: July 10, 2011
  • Available eBook Formats: EPUB, MOBI, PDF
  • Print Book Price: $54.99
  • eBook Price: $38.99
Buy eBook Buy Print Book Add to Wishlist

Related Titles

Full Description

The ASP.NET MVC 3 Framework is the latest evolution of Microsoft’s ASP.NET web platform. It provides a high-productivity programming model that promotes cleaner code architecture, test-driven development, and powerful extensibility, combined with all the benefits of ASP.NET 4.

In this third edition, the core model-view-controller (MVC) architectural concepts are not simply explained or discussed in isolation, but are demonstrated in action. You’ll work through an extended tutorial to create a working e-commerce web application that combines ASP.NET MVC with the latest C# language features and unit-testing best practices. By gaining this invaluable, practical experience, you’ll discover MVC’s strengths and weaknesses for yourself—and put your best-learned theory into practice.

The book's authors Steve Sanderson and Adam Freeman have both watched the growth of ASP.NET MVC since its first release. Steve is a well-known blogger on the MVC Framework and a member of the Microsoft Web Platform and Tools team. Adam started designing and building web applications 15 years ago and has been responsible for some of the world's largest and most ambitious projects. You can be sure you are in safe hands.

What you’ll learn

  • Gain a solid architectural understanding of ASP.NET MVC 3, including basic MVC
  • Explore the entire ASP.NET MVC Framework
  • See how MVC and test-driven development work in action
  • Capitalize on your existing knowledge quickly and easily through comparison of features in classic ASP.NET to those in ASP.NET MVC
  • Learn about the latest security and deployment issues, including those related to IIS 7

Who this book is for

This book is for web developers with a basic knowledge of ASP.NET and C# who want (or need) to start using the new ASP.NET MVC 3 Framework.

Table of Contents

Table of Contents

Part 1
1. The Big Idea
2. Getting Ready
3. Your First MVC Application
4. The MVC Pattern
5. Essential Language Features
6. Essential Tools for MVC
7. SportsStore I – A Real Application
8. SportsStore II – Navigation & Cart
9. SportsStore III - Administration

Part 2
10. Overview of MVC projects
11. URLs, Routing & Areas
12. Controllers & Actions
13. Filters
14. Controller Extensibility
15. Views
16. Model Templates
17. Model Binding
18. Model Validation
19. Unobtrusive Ajax
20. jQuery

Part 3.
21. Security
22. Authentication & Authorization
23. Deployment
Source Code/Downloads

Downloads are available to accompany this book.

Your operating system can likely extract zipped downloads automatically, but you may require software such as WinZip for PC, or StuffIt on a Mac.

Errata

Please Login to submit errata.

On page Many (eg. 227):
For methods of Assert class in Unit Testing, expected value should be the first methods and actual the second.

On page Chpater 9 Page 42:
Product entity field definition SHOULD BE

public byte[] ImageData [ get; set; }

The current field definition is missing the array [] and displays:

public byte ImageData { get; set; }

On page 5:
In Chapter 7 section “Adding References” (page 5) you describe the commands that we must use if we want to add the required project dependencies, Ninject and Moq, using the Visual Studio Package Manager Console.

You have something like this:

Install-Package Ninject -Project SportsStore.WebUI
Install-Package Ninject -Project SportsStore.Domain
Install-Package Moq -Project SportsStore.WebUI
Install-Package Moq -Project SportsStore.Domain

If you read the table 7-2, it seems that the info doesn’t match with the result of executing the previous commands.

Additionally, as a comment, the figure 7-15 (page 19 of the same Chapter) has a look & feel that doesn’t correspond with the rest of the images in the chapter.

On page 6:
In Chapter 8 section “Refining the URL Scheme” (page 6) says:

“Prior to this change, the links we were generating for the pagination links we like this”

I think that it must be:

“Prior to this change, the links we were generating for the pagination links were like this”

On page 6:
In Chapter 8 section “Refining the URL Scheme” (page 6) says:

“Prior to this change, the links we were generating for the pagination links we like this”

I think that it must be:

“Prior to this change, the links we were generating for the pagination links were like this”

On page 15:
In Chapter 8 section “Highlighting the Current Category” (page 15) says:

“we are using a C# feature to avoid a class between the HTML keyword class (used to assign a CSS style to an element) and the C# use of the same word (used to create a class).”

I think that it must be:

“we are using a C# feature to avoid a clash between the HTML keyword class (used to assign a CSS style to an element) and the C# use of the same word (used to create a class).”

On page 23:
Listing 3-12
Model.Will Attend is nullable therefore you have to verify the Has Value property.
Same thing on listing 3-16


On page 24:
In Chapter 7 section “Creating the Entity Framework Context” (page 24) you say something related with Entity Framework 4.1 (in particular with the Code First library):

“Unfortunately, the Code First library is at an early stage of development as we write this and not stable enough to use in this book”

The EF 4.1 (with Code First Library) was released the last week. It would be nice if you could update the text (I’m not saying that you must rewrite the entire chapter to use EF 4.1, only the comment).

On page 30:
I Chapter 8 section “Displaying the Contents of the Cart” (page 30) says:

“We more work to do—being able to remove items from a cart and complete a purchase, for example.”

I think that it must be:

“We have more work to do—being able to remove items from a cart and complete a purchase, for example.”

On page 35:
In Listing 3-2, "View()" should be in bold since it was a string literal in the previous version of the code

On page 44-55:
Maybe the working pattern of MVC has changed but the first project doesn't work in the manner described in the book.

"BeginForm" method now requires Action and Controller.

<link rel="Stylesheet" ...

this requires url and the recommended "better" method is "@Url"

Also there is a lot of repetition about MVC not using viewstate.


On page 45:

Creating the Action Method
You’ll see a 404 Not Found error if you click the link. Tat’s because we haven’t created the action method that corresponds to the /Home/RsvpForm URL. We do this by adding a method called RsvpForm to our HomeController class, as shown in Listing 3-9.

On page 46:

In the source code ViewData["greeting"] should change to ViewBag.Greeting

On page 46 :
If you follow the instructions in the text on page 46 "Uncheck Use a layout or master page" you will receive a compilation error.

The text should state "Leave Checked Use a layout or master page".

Figure 3.13 on page 47 is correct.

On page 47:

Figure 3-13 shows the "Use a layout or master page" checked but in the text on page 46 is says to "Uncheck Use a layout or master page"

On page 48:
<p>Your name: @Html.TextBoxFor(x => x.Name) </p>

Generates compilation error:

Compiler Error Message: CS1660: Cannot convert lambda expression to type 'string' because it is not a delegate type

Source Error:

Line 14: @using (Html.BeginForm())
Line 15: {
Line 16: <p>Your name: @Html.TextBox(x => x.Name)</p>
Line 17: <p>Your email: @Html.TextBox(x => x.Email)</p>
Line 18: <p>Your phone: @Html.TextBox(x => x.Phone)</p>

On page 52:
[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResponse)
{
// ToDo: Email guestResponse to the Part => should be "Party" organizer
return View("Thanks", guestResponse);
}

On page 53:

The instructions for setting up the "Thanks" view shown in Figure 3-16 say "Ensure that the Select master page option is not checked...". However, the screen shot given actually shows that checkbox selected.


On page 97:
decimal cartTotal = products.TotalPrices();
decimal arrayTotal = products.TotalPrices();

->
decimal cartTotal = products.TotalPrices();
decimal arrayTotal = productArray.TotalPrices();

On page 104 - 105:
Listing 5-28 is a rewrite of listing, 5-27, in which you justify using dot notation because you cannot apply Take to the LINQ query in listing 5-27. However, you can replace the bolded portion of listing 5-28 with the following LINQ query, which is much simpler than what you have written:

var results = (from product in products
orderby product.Price descending
select new {
product.Name,
product.Price
}).Take(3);

On page 114:
The end of the penultimate line of the first paragraph under "Setting the Default Route" starts the sentence, "Change the value assigned to the controller property from Default to Product, ..." This phrase is repeated as the start of the last paragraph in the section. In both places, the value "Default" is incorrect. By default, the value is actually "Home" not "Default".

On page 117:

extra closing <p /> tag in Listing 5-39

On page 124:

System.Web.Mvc.ActionResult does not contain a definition for 'ViewData' and no extension method 'ViewData' accepting a first argument of type 'System.Web.Mvc.ActionResult'

//This line below caused the error
var ViewModel = (ProductsListViewModel) result.ViewData.Model;

On page 125-154:

I had a lot of trouble because I added Ninject and then System.Web before changing the Target Framework - took forever to figure out - kept getting the error that OnePerRequestModule wasn't available.

Changing the Target Framework before anything else did the trick

On page 129:
In Listing 6-4, the following line has an opening angle bracket instead of a closing angle bracket for the To parameter.

ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator<();


On page 130:

// get the interface implementation IValueCalculator calcImpl = ninjectKernel.Get<IValueCalculator>();

All the text starting from IValueCalculator should appear on a new line.

On page 139:

Listing 6-24

Wrong:
[TestMethod]
public void All_Prices_Are_Changed) {...}

Correct:
[TestMethod]
public void All_Prices_Are_Changed() {...}

On page 143:

public void All_Prices_Are_Changed) {

should be

public void All_Prices_Are_Changed() {

On page 146:
This is referred to several times going forward from here (page 146) in the section on unit testing ... you refer to the four test methods, however I only see three test methods. You refer to a test method that checks whether the Update method was called the appropriate number of times (page 148), so I assume this is the one that is missing from the book. I see it in the test results screen shots, but the code for this method is not shown in the book.

On page 151:
In Listing 6-32, only part of changes have been marked in bold. In fact, the declaration of products should be in bold as should portions of the declaration of initialTotal and the Assert.AReEqual.

On page 156:
it's not really an error, but to save people from the brink of madness, before trying to create a blank vs solution with multilple projects, and seeing the solution magicaly disappear after creating the first project, it would be a good idea to warn developers to check their vs settings and make sure that the option 'always show solution' is checked.

On page 158-159:
Under the Adding References section the install-package commands and Table 7-2 do not match. And they also don't match the later code.

The Install commands should be:
Install-Package Ninject -Project SportsStore.WebUI
Install-Package Moq -Project SportsStore.WebUI
Install-Package Moq -Project SportsStore.UnitTests

(Maybe also Ninject for the UnitTests project but I haven't encountered a use yet.)

Table 7-2 should be updated to list Moq and Ninject as Tool Dependencies of SportsStore.WebUI.


On page 163:
In the 2nd paragraph the instructions are to create a new interface IProductsRepository (Product*s* plural)

In Listing 7-5 this interface is then referenced as IProductRepository (Product singular)


Also, i appreciate the book is targetted at advanced C# programmers (rather than newbies like me), but a one-liner about adding the requisite reference to the SportsStore.Domain.Abstract namespace would help avoid intense head-scratching ;-)

On page 174:

Wrong:
......Create a new top-level folder inside the SportsStore.Domain project called Abstract and a new
interface called IProductsRepository......

Right:
......Create a new top-level folder inside the SportsStore.Domain project called Abstract and a new
interface called IProductRepository......

(IProductsRepository ===> IProductRepository)

On page 175:
<connectionStrings>
<add name="EFDbContext" connectionString="Data Source=.\SQLEXPRESS;Initial
Catalog=SportsStore; "Integrated Security=SSPI"
providerName="System.Data.SqlClient"/>
</connectionStrings>

==>
<connectionStrings>
<add name="EFDbContext" connectionString="Data Source=.\SQLEXPRESS;Initial
Catalog=SportsStore; Integrated Security=SSPI"
providerName="System.Data.SqlClient" />
</connectionStrings>

On page 176:
Listing 7-14. Adding the Real Repository Binding
private void AddBindings() {
// put additional bindings here
ninjectKernel.Bind<IProductRepository>().To<EFProductRepository>();
}

This won't compile, we are getting this error :


Error 1 The type 'Name.Domain.Concrete.EFProductRepository' cannot be used as type parameter 'TImplementation' in the generic type or method 'Ninject.Syntax.IBindingToSyntax<T>.To<TImplementation>()'. There is no implicit reference conversion
from 'AGlobi.Domain.Concrete.EFProductRepository' to 'Name.Domain.Abstract.IProductRepository'.



On page 177:
Route for Product controller has to be updated in order to run the example (id --> page).

On page 178:
UNIT Test: PAGINATION section:

The arguments to Assert.AreEqual are reversed, the first argument should be the expected value while the second is the actual value.

On page 178:

The line:

IEnumerable<Product> result = (IEnumerable<Product>)controller.List(2).Model;

results in an invalid cast exception. The line should read:

IEnumerable<Prodcut> result = ((ProductsListViewModel)controller.List(2).Model).Products;

On page 183:

Listing 7-20

ItemsPerPage = PageSize

should be

ItemsPerPage = pageSize

On page 195:
The LINQ syntax for filtering the products by category for the ProductsListViewModel ViewResult does not properly return results when category = null. I think a revision like the following is required:

var productsToShow = (category == null)
? repository.Products.OrderBy(p => p.ProductID)
: repository.Products.Where(x => x.Category == category).OrderBy(p => p.ProductID);


ProductsListViewModel viewModel = new ProductsListViewModel
{
Products = productsToShow.Skip((page - 1) * PageSize).Take(PageSize),
PagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = productsToShow.Count()
},
CurrentCategory = category
};

On page 198:

Thoughout this book the author uses the peramiters of "Assert.AreEqual()" the wrong way around.

The correct order (acording to the popup help etc) is:

public static void AreEqual(object expected, object actual);

but they are all used like this:

public static void AreEqual(object actual, object expected);

this may seem trivial and the check does work BUT IF the test does fail it tells you that it expected "10" and got "9" when it means it expected "9" and got "10"... So could send you (and did send me) down the wrong path thinking that the value was lower than it should be but it was really higher!

On page 205:

after changing return type of function (Menu) in in (NavController) to ViewResult instead of PartialViewResult, portal goes into infinite loop

On page 207:

Listing 8-10 not all changes are highlighted. The original function is:

public PartialViewResult Menu()
{
IEnumerable<string> categories = repository.Products
.Select(x => x.Category)
.Distinct()
.OrderBy(x => x);

return PartialView(categories);
}

the revised is:


public ViewResult Menu(string category =null)
{
ViewBag.SelectedCategory = category;

IEnumerable<string> categories = repository.Products
.Select(x => x.Category)
.Distinct()
.OrderBy(x => x);

return View(categories);
}

i.e., the ViewResult and View need to be highlighted.

On page 208:

The unit test on page 208 has a line that reads
new Product {ProductID = 4, Name = "P2", Category = "Orange"},

The comma at the end of the line shouldn't be there.

On page 208:

The CSS code you give lists the HTML elements in UPPER CASE e.g. BODY. Whilst this appears fine in IE9, FireFox 4.0.1 didn't render the cart summary (as per figure 8.13) correctly.

On page 215:

CartLine[] results = target.Lines.ToArray();
This line of code in book causing UNKNOWN ERROR.

On page 224:
This is more of a suggestion than error.
The great side of the book is that it is showing how everything is testable with MVC. Yet, creating model binders w/o tests is contrary to the statement of testability. Something like cart model binder could be easily tested with the following snippet of code (using MoQ):

var binder = new CartModelBinder();
var cart = new Cart();
var httpContextBase = Mock.Of<HttpContextBase>(x => x.Session == Mock.Of<HttpSessionStateBase>(s => s["Cart"] == cart));
var result = binder.BindModel(new ControllerContext(httpContextBase, new RouteData(), Mock.Of<ControllerBase>()), new ModelBindingContext());
Assert.AreSame(cart, result);

On page 230:
In Adding The Cart Summary : first paragraph - Line 3 :
view the cart summary screen only by adding --> ( a new a new ) item to the cart.

On page 240:

missing "}" at the end of the code that starts on the page before. It should have an extra "}" after the "smtpClient.Send(mailMessage);"


On page 243:

Listing 9-13. Implementing the SaveProduct Method need this line of code to work with edit page:
context.Entry(product).State = System.Data.EntityState.Modified;

On page 253:
Where it reads,

// Action.
Product[] result = ((IEnumerable<Product>) adminController.Index().ViewData.Model).ToArray();

It should read,

// Action.
Product[] result = ((IEnumerable<Product>) adminController.ViewData.Model).ToArray();

On page 256:

I can't browse Product List via Index action of AdminController until i removed this route:

routes.MapRoute( null, "{category}", new { controller = "Product", action = "List", page = 1 });

i used:

http://localhost:1475/Admin/
http://localhost:1475/Admin/Index

On page 262:
the SaveProduct(Product product) method will not work as implemented if you are editing an existing record. To fix: remove the code between the { } and replace with the following:

context.Entry(product).State = product.ProductID == 0 ? EntityState.Added : EntityState.Modified;
context.SaveChanges();

On page 267:
Listing 9-13, the definition for SaveProduct(), doesn't seem to work. Unless I'm missing something, the "product" object passed to this method isn't the same Product that exists in the context. To get the method to work, I modified the code as follows:

if (product.ProductID == 0)
{
context.Products.Add(product);
}
else
{
Product productToUpdate = context.Products.First(p => p.ProductID == product.ProductID);

productToUpdate.Category = product.Category;
productToUpdate.Description = product.Description;
productToUpdate.Name = product.Name;
productToUpdate.Price = product.Price;
}

context.SaveChanges();

On page 268:
SaveProduct doesn't update products in the database, context.SaveChanges isn't recognising that the product passed in is in the context.

I've noticed there is an errata for this already, but the solution given is long winded, and there is a slightly simpler way I've found:

public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
else
{
context.Products.Attach(product);
context.Entry(product).State = EntityState.Modified;
}

context.SaveChanges();
}

On page 272:

Listing 9-16 Applying Validation Attributes.

When I apply the attributes to the Product class it raises the following error:

"The model backing the 'EFDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database"

If I don't apply them it works.

On page 274:

I think the line

<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")"
type="text/javascript"></script>

needs to be bold (like the next two script tags) as this is the first time it has been used.

On page 279:
I think there's an incorrect comment in the usit testing section for DELETE Product.

In method Cannot_Delete_Invalid_Products(), you

// assert - ensure that the repository delete method is was called with the correct product

thing is, that's not what the test is for. I think it should be something like:

// assert - ensure that repository delete method is never called

Great book though!

On page 291:
I'm pretty sure that the new field ImageData should be a byte array and not a single byte

public byte[] ImageData { get; set; }

On page 291 - top of 292:
Section title "Updating the Entity Framework Conceptual Model". Describes how to open and update the edmx file but the project doesn't have one.

Also, starting on the bottom of 223, "Using Model Binding", a feature of MVC 3 is used to create class objects. This, however, causes the update or edit to not work because it creates a new instance of the product class to pass into the edit function. When "SaveProduct" is called and passes in an existing "product" object it is not tied to the record in the database. No error is produced but no update occurs. The "add" and "delete" work. To prove this I changed it to the following code:

if (product.ProductID == 0) context.Products.Add(product);
else
{
Product prod = context.Products.Where(p => p.ProductID == product.ProductID).FirstOrDefault();
prod.Category = product.Category;
prod.Description = product.Description;
prod.ImageData = product.ImageData;
prod.ImageMimeType = product.ImageMimeType;
prod.Name = product.Name;
prod.Price = product.Price;
}

On page 292:
public byte ImageData { get; set; }

should read:

public byte[] ImageData { get; set; }

On page 294:

The following code will not work.
if (image != null) {
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}

the new proporty ImageData need to be defined as array. byte[] ImageData. Cannot convet byte[image.ContentLength] to byte.

On page 294:

The Edit controller methos must be changed to something like this:
if (image != null)
{
mvcImages img = db.mvcImages.Where(p => p.p_id == prod.p_id).FirstOrDefault();
prod.p_imageMimeType = image.ContentType;
byte[] buffer = new byte[image.ContentLength];
image.InputStream.Read(buffer, 0, image.ContentLength);
prod.p_imageData = buffer;
img.p_imageMimeType = prod.p_imageMimeType;
img.p_imageData = prod.p_imageData;
db.SaveChanges();
}

Otherwise it won't upload to base. Also SaveChanges() within same brackets as "if"

On page 297:

Running the code up to this point. If you create a new product with an image, it gets written to the db. If you edit an existing product and add an image, it never seems to get written out.

On page 333:
Method Signature At Top Of Page:
private void TestRouteFail(string url)

Does not work at bottom of Page 352 with call to TestRouteFail("~/", "POST");

Page 333 method signature needs to be changed to:
private void TestRouteFail(string url, string httpMethod = "GET")


On page 337:
The first paragraph says the first segment in the code listed above it must match "Customers", but the first segment uses the word "Public", not "Customers". The code and the text explaining thay code need to be reconciled. It would also be good to consider the url at the bottom of pg 336 since it is part of the same example.

On page 342:
A few problems here:
1. Repeated mention of "Listing 11-8" should be "Listing 11-10"
2. Mention is made of "the custom variable index" when it should actually be "the custom variable id"
3. In relation to #2, note that the code in listing 11-13 refers to this variable "index" when it is actually "id" in the method signature.

On page 352:

Unit Testing:

Page 152 TestRouteFail("~/Home/OtherAction"); Does not seem to work with the Route defined in listing 11-20.

Fails at: Assert.IsTrue


On page 355-358:
The section on RouteExistingFiles (page 355-358) needs some work. It should say never set it to true (or at least warn about setting it to true).

In several places it states:
Setting the RouteExistingFiles property (makes the routing system more inclusive.)

When it should say:
Setting the RouteExistingFiles property To true (or false)

357
We can use segment variables like {filename} to match a range of URLs. In this case, the URL pattern will match any two-segment URL where the first segment is Content and the second content segment has the .html extension.

358
Manually defined URLs are quick and simple. They are also extremely dangerous. Fragile
The biggest problem with hard coded URLs is they’re not portable between IIS and IISx/Cassini – book doesn’t even mention that.

On page 356:

The Code in listing 11-27 Is:

routes.MapRoute("DiskFile", "Content/StaticContent.htm",
new { controller = "Account", action = "LogOn" },
new { customConstraint = new UserAgentConstraint("IE") });

However, the paragraph at the top of page 356 mentions "that it will match requests that are made from browsers whose user-agent string Contains 'Chrome'.

Thus: the code should read:

routes.MapRoute("DiskFile", "Content/StaticContent.htm",
new { controller = "Account", action = "LogOn" },
new { customConstraint = new UserAgentConstraint("Chrome") });


On page 361:
TestOutgoingRoutes fails on Assert.AreEqual("/", result).
This is using source code and Listing 11-29 as mentioned in the book. "/Home/Index " is returned not "/". Listing 11-29 is wrong.

On page 401:
// Act - call the action method
ActionResult result = target.Index();

I think it must be
ViewResult result = target.Index();

the ActionResult type doesn't have a ViewName property


On page 407:

ActionResult result = target.Index()

//....
Assert.AreEqual("Hello", result.ViewBag.Message)

ActionResult should be ViewResult. ActionResult doesn't have a ViewBag property.

On page 433,434:
On pg 433 Says that the CustomAuthAttribute example "contains a method called PerformAuthenticationCheck." It doesn't, only has AuthorizeCore method.

Pg 433: Mentions CustomAuthAttribute implemention of OnAuthorization whereas the listing implements AuthorizeCore

The example then used on page 434 doesn't match the listing 13-6:

listing 13-6: httpContext.Request.IsAuthenticated
Pg 434: filterContext.HttpContext.Request.IsAuthenticated


On page 479:
should be:

public override SessionBehavior GetControllerSessionBehavior(

You forgot the override.

On page 534:

RenderBody() does not seem to work with an explicit definition of "@section Body { ... }". Error message is: 'The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/SectionsLayout.cshtml": "Body".'

On page 566:
when [UIHint("Enum")] is used and you try to scaffold the the model the property with the enum type is skipped by the scaffolder

On page 621:
The creation of new ValidationResult objects should include property names in the "memberNames" argument of the respective constructor overload. For example:

if (string.IsNullOrEmpty(ClientName)) {
errors.Add(new ValidationResult("Please enter your name"));
}

should be

if (string.IsNullOrEmpty(ClientName))
{
errors.Add(new ValidationResult("Please enter your name",
new[] { "ClientName" }));
}

so that the validation message is properly associated with the ClientName property. The validation result for the "Joe cannot book appointments on Mondays" rule is good as-is as it will associate as a model-level validation instead of a property-level validation.

On page 642-645:
There is no mention of how to hook up remote validation to the Date field.

It appears to be simple. On the Date property of the Appointment class, add a Remote attribute with the action and controller as arguments. e.g.

[DataType(DataType.Date)]
[Remote("ValidateDate", "Appointment")]
public DateTime Date { get; set; }

On page 648/649:
In the example, the foreach loop is coming up with an error as it can't find the type "Appointment", I needed to change it from
"@foreach (Appointment appt in Model)"

to

"@foreach (MvcApp.Models.Appointment appt in Model)"

On page 662:

In the table 19-2, Descriptions for OnComplete and OnSuccess are swapped.

On page 685:

ALL of the Attribute Selectors are wrong.
$('[attr]="val"') for example.
It should be
$('[attr="val"]) notice the position of the closing ']'

On page 687:
Line 3: The expression $('h1 h2 h3') should be comma separated to select all.