- ISBN13: 978-1-4302-1007-8
- ISBN10: 1-4302-1007-9
- 550 pp.
- Published Apr 2009
- Print Book Price: $49.99
- eBook Price: $34.99
Errata Submission
If you think that you've found an error in Pro ASP.NET MVC Framework, please let us know about it. You will find any confirmed erratum below, so you can check if your concern has already been addressed.
Errata
| Issue | Author's Response |
|---|---|
| I get this error in ProdutcControllerTest.cs. All the code is exactly as in the book Error 14 'object' does not contain a definition for 'ViewData' and no extension method 'ViewData' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) C:\Users\XXXX\Documents\Visual Studio 2008\XXXX\SportStore\Tests\ProductscontrollerTest.cs 33 35 Tests |
Can you download the completed SportsStore code from the Apress.com website and compare it with your implementation? The book code and the downloadable code have been verified as working. Thanks. |
| Chapter 5, Page 132, Microsoft.Web.Mvc I downloaded, added the reference, and added the namespace. Still when I run, I get error error CS1501: No overload for method 'RenderAction' takes '2' arguments ---------------------------------------- %@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title> <link rel=Stylesheet href="~/Content/styles.css" /> </head> <body> <div id="header"> <div class="title">SPORTS STORE </div> </div> <div id="categories"> <% Html.RenderAction("Menu", "Nav"); %> </div> <div id="content"> <asp:ContentPlaceHolder ID="MainContent" runat="server" /> </div> </body> </html> |
This book is based on ASP.NET MVC 1. I think you must be using ASP.NET MVC 2. In this case, you can probably just remove the reference to Microsoft.Web.Mvc.dll (and the associated namespace) and it may work. |
| Chapter 4, Page 98 protected override IController GetControllerInstance(Type controllerType) { return (IController)container.Resovle(controllerType); } won't compile. Says that this method does not allow for returns. |
I think you must be using ASP.NET MVC 2. This book is based on ASP.NET MVC 1. We are in the process of producing an updated book for ASP.NET MVC 2. |
| Someone has already submitted this however I'd like clarification on your anwser. Ch 15, page 553: Code snippet at top, line in bold. Should not "HttpContext.Items" be "HttpContext.Current.Items"? Former does not compile. **** Your Answer ****** It depends where you're calling this code from. If it's inside an action method, you can write HttpContext.Items. You would only need System.Web.HttpContext.Current.Items (where System.Web.HttpContext.Current is a static variable) if you were outside an action method. Bear in mind that using System.Web.HttpContext.Current leads to untestable code - you can't mock this static value. **************************** In order in integrate this code into the SportsStore example one would need to add the indicated line to the SqlProductsRepository.cs file because that is where you call your data context NOT in the controllers action method as you indicated. As the provious reader indicates the line you gave will not compile as is. If you change it to dc.Log =(StringWriter) HttpContext.Current.Items["lingtoSqlLog"]; it will compile however I still can't get the LINQ to SQL to reneder. The section shows up on the page but it says zero (0) queries. Is there something else we are missing? Thank's in advnce for any assistance. -MARK- |
Hi Mark - Yes, you're right that if you're going to put this code into SqlProductsRepository.cs, then you'll need to change HttpContext to HttpContext.Current. Once you've done that, it should work fine, and indeed it does when I've tried it. I'm not sure what you might be missing, except perhaps you might have a typo in your code. For example, in your errara report you mention HttpContext.Current.Items["lingtoSqlLog"] - I think that should be HttpContext.Current.Items["linqToSqlLog"]; |
| Chapter 5, page 133 Hi Steve, When creating the navigation for the first time, there is a call to the MVC futures function like so: <% Html.RenderAction("Menu", "Nav"); %> I believe calling the function this way may actually be deprecated now. Can you confirm and provide an updated line of code? Cheers! |
I'm working on a 2nd edition that will update all the code for ASP.NET MVC 2. |
| Hi- Page 162 the tests: Submitting_Order_With_No_Lines_Displays_Default_View_With_Error() and: Submitting_Empty_Shipping_Details_Displays_Default_View_With_Error are both getting errors with I run the test from NUnit at the lines with the same statement: Assert.IsFalse(result.ViewData.ModelState.IsValid); The error is: Tests.CartControllerTests.Submitting_Order_With_No_Lines_Displays_Default_View_With_Error: System.NullReferenceException : Object reference not set to an instance of an object. I downloaded your source code. It's the same as mine and the book. Any idea what's going on? Thanks! -jason. |
Are you using ASP.NET MVC version 1? This example code definitely works with ASP.NET MVC 1. |
| Chapter 2 pg 31 The input validation code in the example with throw a null argument exception if a user submits a form with an empty email field. Regex.IsMatch do not like an null Email object line should be if((propName == "Email" ) && ( Email == null || !Regex.IsMatch(Email, ".+\\@.+\\..+"))) |
The book refers to ASP.NET MVC 1, which will not supply a null value for Email - it will supply an empty string if the user hasn't entered anything. I know this has changed in ASP.NET MVC 2. The forthcoming 2nd edition of the book will account for this. |
| Html.RenderAction is changed in the updated ASP.NET MVC Future. Could you please post the updated code for that? | I'm working on a 2nd edition of the book that will have all the code updated for ASP.NET MVC 2. |
| Chapter 4 (pages 97 - 100) Regarding WindsorControllerFactory implementation - controller objects are never released if Transient lifestyle is used. This can be fixed by either overriding the DefaultControllerFactory's ReleaseController method (and releasing objects manually) or by setting release policy to NoTrackingReleasePolicy. |
Thanks for the feedback. I've been told that this is actually a bug in Windsor (preventing GC on transient instances), but in any case, for the 2nd edition, I'll be dropping Windsor in favour of Ninject anyway. |
| Thanks for the great book. Two questions/issues: 1) Chapter 5 pages 136/137 - when creating the partial view it is stated for "view data class" to be set to "IEnumerable<WebUI.Controllers.NavLink>" ... shouldn't this be set to "IEnumerable<WebUI.Controllers.NavController.NavLink>"? 2) I have followed the setup in Chapter 5 up through page 137. My links are generating and functional however I am not getting friendly URLs. My URLs come out as "http://localhost:55232/Page1?category=Chess" instead. I've checked my project vs the source code and looked around and cannot figure it out. Any clues? Possibly a bug with RouteUrl? Thanks! |
(1) It seems that you've put NavLink inside the NavController class. I know it isn't obvious because of how the code is typeset with a page break in it, but in the book, NavLink is *outside* the NavController class. (2) It certainly works in the downloadable completed code. Can you use a tool such as Beyond Compare to see how your implementation differs? |
| On Chapter 5, Page 137: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<WebUI.Controllers.NavLink>>" %> Didn't work for me. I kept getting: The type or namespace name 'NavLink' does not exist in the namespace 'WebUI.Controllers' I had to change "... Controllers.NavLink..." to "... Controllers.NavController.NavLink..." in order for it to work. Like this: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<WebUI.Controllers.NavController.NavLink>>" %> |
It seems that you've put NavLink inside the NavController class. I know it isn't obvious because of how the code is typeset with a page break in it, but in the book, NavLink is *outside* the NavController class. |
| In Chapter 10, the section on ViewData.Eval. The first list of examples is missing the .Eval | Actually they weren't meant to say .Eval - these are lists of ViewData[] items that can be found using Eval(), not examples of how to call Eval(). Thanks for the feedback though. |
| Chapter 5, Page 147 "You'll learn more model binding in detail in Chapter 12,..." I'm pretty sure you meant chapter 11, did you? |
Yes, you're right. Thanks for the report. I'll update this in the 2nd edition. |
| Chapter 5, Location 2277 on Kindle (approx.) I downloaded the MVC futures component, and the signature for RenderAction seems to have changed from what's in the book. The call to Html.RenderAction("Menu", "Nav") now gets an error, "No overload for method 'RenderAction' takes '2' arguments". The signature for RenderAction seems to be: void HtmlHelper.RenderAction<TController>(System.Linq.Expressions.Expression<Action<TController>> action) |
Thanks for the information. I'm working on an MVC 2 version of the book at the moment and will account for those changes in it. |
| Hi Steve, After adding the line Model.Binders.Add(typeof(Cart), new CartModelBinder()); to Global.asax.cs (as directed in Chapter 5 p148) The Inbound and Outbound routing tests no longer work properly. The first one you run after (re-)compiling passes but then all subsequent ones fail until a recompile (which presumably causes the Mvc framework to do a refresh or something). I have resolved this (at least in terms of getting the tests to pass) by adding the line ModelBinders.Binders.Clear() before the Add line above. Is this the correct solution? Thanks Simon |
I think you must have accidentally added the line to RegisterRoutes(), whereas it should be added to Application_Start(). |
| Chapter 5, page 134. For the NavControllerTest for the following line (second from bottom) var links = ((IEnumerable<NavLink>)result.ViewData.Model).ToList(); I had to specify NavController to get it to compile like this: var links = ((IEnumerable<NavController.NavLink>)result.ViewData.Model).ToList(); I've gone over the text about 100 times and can't find what I'm missing. |
I think you must have put the NavLink class inside the NavController class. The book shows NavLink being outside that class (I know it is a bit confusing because of the page break between pages 135 and 136 - you have to count the braces to see for certain). |
| Hi Steve, Excellent book! I extracted "Pro_ASP_NET_MVC_Framework-4389.zip", setup the database and connection string and successfully ran all the unit tests. However, when I press F5 to run the application, I see "http://localhost:56815/Views/Products/List.aspx" in my browser address bar and an HTTP 404 message which says "/Views/Products/List.aspx" cannot be found. When I go the Products controller, and right click on the List method, and select "Go to the Definition" it displays "...\Views\Products\List.aspx" I would appreciate any troubleshooting ideas you might have to resolve this issue. Thank you very much, Philip |
Try visiting the root URL (http://localhost:56815/) instead. In ASP.NET MVC, you're not meant to be able to open view files in a browser directly. |
| I got an interesting problem... Chapter 5, p. 163, test case Valid_Order_Goes_To_Submitter_And_Displays_Completed_View() is failing deep in the MVC because ControllerContext is null. I have debug version of MVC, and the call stack is this: System.ArgumentNullException : Value cannot be null. Parameter name: context at System.Web.Mvc.AssociatedValidatorProvider.GetValidators(ModelMetadata metadata, ControllerContext context) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\AssociatedValidatorProvider.cs:line 23 at System.Web.Mvc.ModelMetadata.GetValidators(ControllerContext context) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\ModelMetadata.cs:line 343 at System.Web.Mvc.DefaultModelBinder.OnPropertyValidating(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, Object value) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 438 at System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 209 at System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 181 at System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 59 at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 133 at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\DefaultModelBinder.cs:line 175 at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model, String prefix, String[] includeProperties, String[] excludeProperties, IDictionary`2 valueProvider) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\Controller.cs:line 402 at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model, IDictionary`2 valueProvider) in ...\mvc2-preview2\src\SystemWebMvc\Mvc\Controller.cs:line 369 at WebUI.Controllers.CartController.CheckOut(Cart cart, FormCollection form) in ...\SportStore\WebUI\Controllers\CartController.cs:line 57 at Tests.CartControllerTests.Valid_Order_Goes_To_Submitter_And_Displays_Completed_View() in ...\SportStore\Tests\CartControllerTests.cs:line 125 The web program runs fine, since ControllerContext is not null. I tried the code from download and the test runs fine. I tried to replace the bundled dll with the debug one, however, I was getting compilation errors. My MVC is MVC2 Preview 2; this might have something to do with it. Anyway, it's a small problem, and related more specifically to TryUpdateModel() functionality - so I moved on. If anybody has any comments, of course, would be very interesting! |
You're using ASP.NET MVC 2. The book targets ASP.NET MVC 1 :) I'm working on an updated version for ASP.NET MVC 2 at the moment. |
| Chapter 11, pp. 392-394 Hi Steve, You introduce new Exception class - RuleException to fill Errors field with error messages. I'd like to suggest an alternative. We can use existent in Exception class Data field for this purpose. In this case example on the page 394 could look like: public void Save() { //......... try { // Todo: Actually save to the database } catch (SqlException ex) { if (ex.Message.Contains("IX_DATE_UNIQUE")) // Name of my DB constraint ex.Data["AppointmentDate"] = "Sorry, already booked"; throw ex; // Rethrow exception } } It's more consistent. We don't substitute exception class and still we can use this to fill in ModelStateDictionary. But this approach has one drawback (not very big as for me) - you can use only one message per key because Exception.Data is IDictionary interface. The main benefit is that you continue to use all sort of exceptions in your domain model. Thank you for your great book, Gennadiy |
Thanks for your suggestion. If your technique works better for you then of course you should use it. I'm only offering suggestions. As it happens I still prefer my approach because I don't want to expose persistence notions (like SqlException) into the UI parts of my code, and also as you point out, sometimes it's desirable to have a mechanism of describing multiple violations at once. |
| Chapter 5, page 133, using Html.RenderAction("Menu", "Nav"). VS2010 / MVC "1.1" WARNING This method consistently failed for me, presenting an error message that says: The controller for path '/' could not be found or it does not implement IController. I initially suspected an error in my routing, but even after copying directly from the downloaded sample I still received the error. After some more sleuthing and finally a decent google search, I happened on this thread: http://forums.asp.net/p/1440724/3350560.aspx If you use the 1.1 MVC DLL - which was retargeted to work in VS2010 - and the original 1.0 MVC Futures DLL, you will receive this error! The trick is to download the source of the MVC Futures, rebuild it, and use THAT dll. This is clearly a result of using a beta version of VS and a somewhat-unofficial (although it's from Microsoft) version of MVC, but wanted to warn everyone else who may come here as confused as I was. |
Thanks for the information. |
| Page 149, Chapter 5 Assert.AreEqual("someReturnUrl", result.RouteValues["returnUrl"]); Should be: Assert.AreEqual("someReturnUrl", result.RouteValues["controller"]); |
Actually, the code as given in the book is correct. I'm not sure why you'd think it should be changed in this way. If you're still convinced, please let us know why. |
| Chapter 5, p137. Not really a problem with the book per se, but using the latest release of MVC futures (for HTML.RenderAction()) means having download MVC 2 Preview and fix various references in the solution (i.e. Changing project references to System.Web.MVC to version 2.0.0.0 and web.config references). Also, the DefaultControllerFactory class has changed (in MVC 2 preview), so the signature for GetControllerInstance in WindsorControllerFactory needs to be "GetControllerInstance(RequestContext requestContext, Type controllerType)". Fairly obvious what to do, but someone might get stuck so I thought it might be worth posting here. Great book btw. Enjoying it very much! |
Thanks for the information. I'm working on an MVC 2 version of the book at the moment and will account for those changes in it. |
| Chapter 11, page 410. Captcha image rendering. I kept getting no image to display while using the captcha demo. i stepped through the code and found there was "A generic error occurred in GDI+" in the bmp.Save(Response.OutputStream, ImageFormat.Png); line in the CaptchaImageController. a little searching around the web and i found the fix was to save the image to an intermediate MemoryStream, and then pushing it to the response stream: Response.ContentType = "image/png"; using (MemoryStream stream = new MemoryStream()) { bmp.Save(stream, ImageFormat.Png); stream.WriteTo(Response.OutputStream); } |
Thanks for reporting this. Originally I was working with GIF files which suffered no such problems, but made a last-minute change to output PNGs without noticing it caused an extra problem. I'll fix this (using the MemoryStream, as you suggest) in the 2nd edition of the book. |
| Chapter 5 - Page 132 Download the ASP.NET MVC Futures assembly... Can't find any such thing on codeplex even through search. This is a stop point since without it you cannot use RenderAction. |
Currently, you can find it at http://aspnet.codeplex.com/releases/view/24471 |
| Chapter 5: Use of Assert.IsEmpty(result.ViewName) I am new to TDD. But the assertion Assert.IsEmpty(result.ViewName) does not seem like an clearly self describing test to me. One of many examples can be found in CartControllerTests method: Index_Action_Renders_Default_View_With_Cart_And_ReturnUrl() In this context, is there a more self describing assertion that would would allow us to test against an actual ViewName instead of an EmtpyString? Thanks, Mark |
If the action doesn't specify a view name (because you're saying "use the built-in convention") then you can't test for a view name - there isn't one. The unit test shows that the action specifies an empty view name to invoke the built-in convention. |
| Chapter 4, Html.PageLinks Behavior Hi, I am trying to contact the author, but the book's email and blog information does not seem to be accurate. Could you please pass this on to the author. I am trying to get some clarification on a portion of the book. Thanks, Mark *************************************************************************************************************************** ************************************************************************************************************************* Hi Steve, The book has been very enlightening so far. I really like it. But I'm confused about a portion of the Html.PageLinks behavior in Chapter 4. I do not understand why the link for Page 1 does not get an href of "Page1" . I suppose it's something about the interaction between the Url.Action method and the Routes. The PageLinks method uses the following function for each page link to be rendered. x => Url.Action("List", new { page = x }) On each call x represents the current value of the index in the PageLinks method. (In this case, 1-3). It appears that the page parameter is being sent into the Url.Action method each time. MSDN seems to confirm this assumption. So why would this not always use the Route that takes the Page parameter. routes.MapRoute( null, // Route name "Page{page}", // URL with parameters new { controller = "Products", action = "List" }, / / Parameter defaults new { page = @"\d+" } / / Parameter constraints); The other route has no page parameters. So I do not see how this is being called, but it apparently is for Page 1 only. routes.MapRoute( null, // Route name "", // URL with parameters new { controller = "Products", action = "List", page = 1 } / / Parameter defaults ); Could you please explain this? In addition, you are using a cool trick with null in the PageLinks_Produces_Anchors Test: string links = ((HtmlHelper)null).PageLinks(2,3, i => "Page" + i); Unfortunately, it's unclear to me why this generates correctly using a null cast to an HtmlHelper. What's going on here? Thanks, Mark |
Hi Mark The URL for page 1 is simply "/" and not "/Page1" because in addition to the route entry with URL "/Page{page}" that you mention, there is also a higher-priority one with URL "/" that applies when the controller is "Product", the action is "List", and the page number is "1" --- see page 107. Each time ASP.NET MVC generates a URL, it picks the first (i.e., highest priority) route entry that is compatible with the parameters you've supplied. --- >It's unclear to me why this generates correctly using > a null cast to an HtmlHelper Extension methods are really just an alternative way to call a static method, so they still work if you call them against a null variable of whatever type they extend. For more details, see http://stackoverflow.com/questions/847209/in-c-what-happens-when-you-call-an-extension-method-on-a-null-object |
| Pg 98 - Setting controller LifetstyleType.Transient Pg 101 - Setting web.config component to PerWebRequest Page 98 says that using LifestyleType.Transient creates a new controller on each web request. Why isn't the LifestyleType.PerWebRequest used here. If this change is possible, does PerWebRequest need to be set in web.config |
ASP.NET MVC will ask for a controller only once per request anyway, so the two lifestyles you mention will behave exactly the same. If you prefer to use LifestyleType.PerWebRequest, you'll need to register the PerWebRequest module as explained on page 102. Actually there is potentially a special case where if you use Html.RenderAction(), you can instantiate multiple controllers during a single request. In that case, you want a separate controller instance to handle each Html.RenderAction() call otherwise you could experience unexpected interactions, so it would be preferable to use LifestyleType.Transient. |
| Chapter 4: p. 97 "Its installer will register the Castle DLLs in your Global Assembly Cache (GAC)." p. 103 "from the Browse tab, because when you download Moq, you just get this assembly file—it’s not registered in your GAC" It is a common misconception that Visual Studio inspects the GAC to fill the "Add Reference" Dialog's ".NET" tab. It does not. Check: Andrew Troelsen, Pro C# 2008 and the .NET 3.5 Platform (Chapter 15, page 489) Registry keys under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders identify directories that contain relevant assemblies. "How to display an assembly in the "Add Reference" dialog box" http://support.microsoft.com/kb/306149 "it’s not registered in your GAC" perpetuates the "myth". The installer has to create the necessary registry entries to ensure that the assemblies show up in Visual Studio's "Add Reference" ".NET" tab. |
Thankyou for reminding me of this. In case these paragraphs permit any ambiguity, I'll rephrase them in any future edition of the book. |
| Hi, No code exists in download for the Chapter 3 Auction Application. Could you please provide this. Thanks |
The code snippet you're referring to is actually just to illustrate some of the points in that chapter and isn't a complete application that you can run. Sorry! |
| Chapter 4, Page 109-110, "Test.PagingHelperTests" Specifically, the test "PageLinks_Produces_Anchor_Tag" fails to resolve itself correctly giving the following error, attributable to the addition of a cariage return and newline combination "\r\n": ************************************************** Tests.PagingHelperTests.PageLinks_Produces_Anchor_Tags: Expected string length 82 but was 86. Strings differ at index 21. Expected: "<a href="Page1">1</a> <a class="selected" href="Page2">2</a> ..." But was: "<a href="Page1">1</a>\r\n<a class="selected" href="Page2">2</a>..." **************************************** While this isn't overly significant and the program runs as expected, since I'm new to TDD/BDD, the point I raise is that in such instances would you revise the test or modify the code? PS: the 30 pages for an unimpressive result were more than worth the effort. As someone who has read over 200 programming books, I can honestly say this was the best generalized overview of a design pattern I have ever read. It's especially nice that everything works as indicated. |
> would you revise the test or modify the code? Hi - I'd decide which behaviour I considered correct or most desirable, then if necessary modify the test to reflect that, and then if the test fails indicating that the code doesn't match the desired behaviour, modify the code so the test passes. Thanks for your kind compliments! |
| Chapter 4, page 98 "Incorrectly named/resolved variable" *************************************************** public class ProductsController : Controller { public int PageSize = 4; // Will change this later private IProductsRepository productsRepository; public ProductsController(IProductsRepository productsRepository) { this.productsRepository = productsRepository; } *************************************************** In the above code the same name "productsRepository" is used in the assignment and althouhg the compiler only generates a warning, it results in passing a null value. I was able to resolve this by changing the name of the parameter passed to the ProductsController. |
Hi These kinds of assignments are perfectly legal and won't in themselves result in assigning a null value. The compiler can distinguish between "productsRepository" (the formal method parameter) and "this.productsRepository" (the instance variable). It doesn't cause a compiler warning for me (VS 2008 SP1). I name my variables and parameters like this frequently, mainly because that's how ReSharper does it by default. I'm not sure why you were getting nulls, but I'm glad you managed to fix it. Regards |
| Ch 5 pp 125-131: (Not strictly a bug but moving from one side of the Atlantic to the other) SportsStore table data (Ch4, p94) has category "Soccer" as have subsequent screenshots. Ch5 URL Schema examples are for "Football". I'm also from the UK and a pedant to boot so I prefer "Football" but I guess it would be best to be consistent? |
Hi - you're referring to the difference between the data in the database and the sample data used by the unit tests, right? You can try to use real data in unit tests, though of course it will work just the same whatever data you use in the unit tests. In practise, I usually prefer to make my unit test data totally different to real data to avoid any confusion about where that data is coming from. For example, I would usually write something like "TestRoute("~/testCategory/Page12345", new { controller = "testController" ... })" to make clear that the code should work regardless of the data supplied. I didn't do that in the book because I thought it would be hard for a human to read and stay interested if all the test data was that boring and unrecognisable. |
| Ch 15, page 553: Code snippet at top, line in bold. Should not "HttpContext.Items" be "HttpContext.Current.Items"? Former does not compile. | It depends where you're calling this code from. If it's inside an action method, you can write HttpContext.Items. You would only need System.Web.HttpContext.Current.Items (where System.Web.HttpContext.Current is a static variable) if you were outside an action method. Bear in mind that using System.Web.HttpContext.Current leads to untestable code - you can't mock this static value. |
| Ch5, p132: In the third paragraph “...download the ASP.NET MVC Futures assembly from www.codeplex.com/aspnet/ (look on the Releases tab)...”. No Releases tab present, but can go to Downloads tab and choose (on right) “ASP.NET MVC v1.0 Source”. This page (http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471) has a link to download “ASP.NET MVC v1.0 Futures”, which seems to be the correct dll. | Thanks for the update. |
| Ch 4, p103: In the sidebar, “System.Web.Mvc.dll” should be “System.Web.Mvc”? | Yes, you're right! Thanks for reporting this. We'll correct this in any future edition of the book. |
| Chapter 5; Page 167; At the bottom of the page, where cart.Lines is iterated over, the open parenthesis is not closed in the format string and a new line isn't inserted. Here's what I did to fix it: foreach (var line in cart.Lines) { var subtotal = line.Product.Price * line.Quantity; body.AppendFormat("{0} x {1} (subtotal: {2:c})", line.Quantity, line.Product.Name, subtotal); body.AppendLine(); } |
Thanks for the report! We'll correct this in any future edition of the book. |
| chapter 5, page 125, first line reads: "To make the List.aspx view render an appropriate page title, as shown in the preceding screen shot...", but the preceding screenshot shows the old rendering, not the updated one (with the ": <category name>"). |
Actually, the preceding screenshot (Figure 5-1) *does* show "Sports Store : Watersports" as the title (i.e., right at the top of the browser window, above the address bar). I guess when I say "title" it's ambiguous. In this case I mean the TITLE element in the HEAD section of the HTML document which the browser will display right at the top of the window above the address bar. However I guess you have interpreted "title" to mean the big white text which still just says "SPORTS STORE". Sorry for the confusion. |
| Chapter 9, page 305 In the Creating a Custom Controller Factory section, you talk about implementing IController which should be IControllerFactory |
You're right! Thanks for reporting this typo. We'll fix this in any future edition of the book. |
| Not an error as such, but on Page 155 in Chapter 5 where we build the cart summary header block, why is <% Model.Lines.Sum(x=>x.Quantity) %> item(s) in the partial view? Surely this would be better implemented as part of the cart business object, along the lines of ComputeTotalValue. This would then be unit testable and would be available if we needed to show total items anywhere else where we had a cart without duplicating logic |
Yes, that's a fair point. Thanks for the feedback. |
| Chapter 12, page 444 I tried .replaceWith($("#summits",response)) and it did not work. It worked with .replaceWith(response) |
Hmm, strange! Perhaps you're using a different version of jQuery. Did you try the downloadable code samples for this chapter, which shows that code working? |
| P102. I can't get the app to compile with ", Castle.MicroKernal" added to the end of the httpModule. If I take that out it compiles and seems to work. | I think you've made a typo - it's MicroKernel, not MicroKernal :) |
| P26. I think "new SelectListItem { Text" should read "new SelectListItem() { Text" I've only just started so I can't say for certain, but that's what Intellisense suggests, and makes sense from a C# point of view. |
Actually it will work either way - the "()" parentheses are optional if you're using an object initializer block (i.e., the "{ ... }" block). You can write it whichever way looks best to you. |
| Chapter 4, page 98. Function: WindsorContainer.AddComponentWithLifestyle does not exist. Chapter 4, page 99. Before section "Using Your IoC Container", running the code generates an error at "return (IController) container.Resolve(controllerType)". Error: "Value cannot be null. Parameter name: service" |
Castle Windsor's AddComponentWithLifeStyle() method was replaced by AddComponentLifeStyle() in Castle v2 (which was released after this book went to print). Regarding the "Value cannot be null" error - that won't happen on any request that maps to a valid controller, but if for some reason you do get requests for a controller that doesn't exist, you could update GetControllerInstance's method body to: if(controllerType == null) return null; else return (IController)container.Resolve(controllerType); |
| The Delete action in Chapter 6 (page 188) is implemented as an HTTP GET. This is a dangerous technique as you already made note of earlier in the book (talking about idempotent GET requests). | You're absolutely right. The risk is minimised in this example because it requires authentication to reach this action (so a search engine crawler can't hit it), but you're absolutely right that I should have made this a POST-only action to avoid any unwanted interference from a web accelerator running on the administrator's PC. I'll alter this in any future edition of the book. Thanks for the feedback! |
| Chapter 4, pg. 100 The bullet point in the bullet list of benefits says "You can trivially hook it up to any other IProductsController (e.g., for a different database or ORM technology) without even having to change the compiled assembly. IProductsController should be IProductsRepository |
Well spotted! I'll fix this in any future edition of the book. Thanks for letting us know. |
| I am encountering an error in NUnit testing of the List_Presents_Correct_Page_Of_Products (found on pages 103 and 104) which states: Object reference not set to an instance of an object. The error points to the following portion of the code: { // Generate an implementor of IProductsRepository at runtime using Moq var mockProductsRepos = new Moq.Mock<IProductsRepository>(); mockProductsRepos.Setup(x => x.Products).Returns(prods.AsQueryable()); return mockProductsRepos.Object; } Particularly the var mockProductsRepos = new line. I have tried this using both versions 3.0 and 3.1.416.3 of Moq - both with the same issue. Any ideas to what might be the issue? Everything else has run just fine (including other tests). Wasn't sure if something didn't make it into the printed page or just something that I was overlooking. Thanks a ton for writing such an excellent book. Todd Banister tbanister@primarycapital.com |
Hi Todd. I'm really not sure how the line "var mockProductsRepos = new Moq.Mock<IProductsRepository>();" could possibly cause an "Object reference not set..." exception, and it certainly didn't when I tried it. Could you get hold of the downloadable source code (from http://apress.com/book/downloadfile/4389) and see if there's something different about your implementation? Please let me know if the downloadable version of this application suffers the same problem against your version of Moq. |
| Chapter 4 - page 98 In later versions of the castle Windsor framework (I'm using version 2) it appears that the AddComponentWithLifestyle method has been replaced by the AddComponentLifeStyle method. Only a little change but I thought you might like to know. |
Thanks very much for letting us know - much appreciated! |
| Chapter 5, page 122... Where is the MockProductsRepository method defined for the PagingHelperTests class? For the ProductsControllerTests class it is defined as a private static method, are we to define this again in the PagingHelperTest class? Or am I missing something? Thank you |
The unit tests on page 122 go into ProductsControllerTests (not into PagingHelperTests), since they are testing ProductController's behaviour (not the behaviour of Html.PageLinks). As such, you'll be referencing the existing MockProductsRepository() method and don't need to copy it. I think this is mentioned in the sentence that starts "Make a test for the first..." but I appreciate it may not have been as clearly phrased as it could have been. Sorry for any confusion! |
| Some of the CSS presented in the book doesn't seem to render properly in IE7. For example ch.5 pg.145: FORM { margin:0; padding:0; } DIV.item FORM { float:right; } DIV.item INPUT { color:White; background-color:#333; border:1px solid black; cursor:pointer; } This doesn't seem to apply to the Add to Cart button properly in IE7, but works perfectly fine in Firefox. |
I wonder if this might be a browser cache issue. Could you try clearing your browser's cache to see if the styles are then applied as expected? I suggest this because the screenshots in the book were actually taken from IE7, which makes me confident that this CSS works on IE7! :) |
| Ch5, pg 127: The FootballGoesToFootballPage1() unit test will not work properly. The first argument to TestRoute is "~/Football", which will result in null RouteData. The correct value seems to be "~/Football/", GetRouteData() resolves the correct route from this string. | Thanks for your feedback. However, I believe the argument "~/Football" does in fact work. This is TDD, so we're writing tests that fail at first, and then implement the desired behaviour (so the tests pass) later. The routing configuration is not fully implemented until page 130. Please see the downloadable source code for an example of this working. |
| Chapter 4 - page 98 Class WinsorControllerFactory Relies on the Castle Version 1.0.3.0 dll and not the May 5th 2009 V2 release on the website url. No AddComponentWithLifeStyle in 2.0 I pulled the proper dll's out of the source for my code as I read project. |
That's correct - the AddComponentWithLifeStyle() method was replaced by AddComponentLifeStyle() in Castle v2. Unfortunately Castle v2 was released after the book was published, but I'll be sure to update this in any future new edition of the book. |
| I was working through chapter 2 source code and the Post method would never work, I couldn't ever hit a breakpoint etc. Spent about 1 hour making sure the source code was identical. Moved the code out of the Documents/vs projects folder into some normal folder and it runs like a charm, breakpoints, views, etc. Standard Win 7 / vs 2008 pro / etc nothing fancy about the setup. Wanted to pass this on to save others some time. I know windows 7 is RC but still, many are probably using it. |
I haven't experienced this problem myself, but if there is a problem with the VS debugger under Windows 7, I would expect Microsoft to resolve it in time for the RTM. |
| How do you navigate to and from the admin section of the sports store demo app - not via the address bar I hope. This navigation appears to be missing? |
For this application there was no requirement to navigate from the public pages to the admin pages. Administrators would be given a login link which they would bookmark. Of course you can edit the public master page to add a link to the admin login page if you wish! |
| Where is the downloadable material cited in the book? | The source code has been submitted to Apress and should become available on the Apress website imminently. |
| Ch 4, pg. 97: URL for Castle includes the number 9 (footnote number) in the URL producing "page not found" | The URL as printed is correct; however, the clickable hyperlink in the PDF incorrectly treats the following few characters as part of the URL. eBook readers should copy and paste this particular URL into their browser manuallly. |
