ASP.NET MVC4的移动应用程序的开发


ASP.NET MVC 4 Mobile App Development Create next-generation applications for smart phones, tablets, and mobile devices using the ASP.NET MVC development framework Andy Meadows BIRMINGHAM - MUMBAI ASP.NET MVC 4 Mobile App Development Copyright © 2013 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. First published: July 2013 Production Reference: 1160713 Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK. ISBN 978-1-84968-736-2 www.packtpub.com Cover Image by Abhishek Pandey (abhishek.pandey1210@gmail.com) Credits Author Andy Meadows Reviewers Shailendra Chauhan Shiju Varghese Acquisition Editor Mary Jasmine Nadar Commissioning Editor Llewellyn F. Rozario Lead Technical Editor Neeshma Ramakrishnan Technical Editors Mausam Kothari Rikita Poojari Amit Ramadas Project Coordinator Arshad Sopariwala Proofreader Christopher Smith Indexer Hemangini Bari Graphics Abhinash Sahu Production Coordinators Manu Joseph Nitesh Thakur Cover Work Nitesh Thakur About the Author Andy Meadows has been in a love affair with technology since his third-grade teacher introduced him to her TRS-80 Model III in 1981. After several months of typing "Go North" on the keyboard, he began his foray into BASIC programming. The TRS-80 Model III begat a Commodore 64 and an introduction to Pascal. By 1988, he was spending his summers earning money by writing software in C for local small businesses. While attending college at the University of Georgia, Andy developed his passion for web development and, of course, beer. His first web application was a series of CGI scripts that output content for NCSA Mosaic and by 1994, he was designing web interfaces for global information systems. After college, Andy wandered listlessly through the IT world spending time in several verticals using several different languages, but he always returned home to web development. In 2002, he began his foray into mobile development beginning with native Java development, and quickly moving into the mobile web space where he began marrying his two passions: mobile web development and .NET. Since then, Andy has worked on several projects involving mobile development, web development, or both. He is extremely excited about the future of the mobile web made possible by the newest generation of mobile devices. He is currently working at a startup in Atlanta, where he lives with his wife and two children. Acknowledgment Writing this book was one of the biggest challenges I have ever undertaken. When originally approached with the idea for this book, I was hesitant. I'd heard horror stories about the sheer level of effort and commitment it takes to complete this task, but after consulting with the family I decided to try. Let me tell you, those stories are wrong. It was much, much more difficult than I had heard, but more fulfilling than I could have imagined. The biggest commitment I had to make when writing this book was time. Lots and lots of time. Fortunately, I was blessed with a wonderful supporting cast. I would first like to thank the people at Packt Publishing for their gentle encouragement and guidance through this process. They were truly a pleasure to work with, and their level of commitment to their authors and a quality product is evident in every action they take. To my reviewers, thanks for the candid feedback—both critical and complimentary. This book is better because of you. To my wife, Amy, and my two children, Noah and Nate, who permitted me to undertake this venture, thank you for your patience and support. And thanks for letting me take over practically every room in the house at one point in time as I attempted to find my muse. I sure must have done something right at one point to deserve the unconditional love you have shown through the long days at work, followed by the long nights in front of the computer. I love you all. About the Reviewers Shailendra Chauhan is an N-Tier Application Developer & .NET Consultant in Noida, Delhi, Gurgaon NCR region, India. He has 4.5 years of experience in building web applications using Microsoft Technologies including ASP.NET, MVC, C#, jQuery, SQL Server, WCF, Web API, Entity Framework, and many more web things. He loves to work with Internet applications using Microsoft technology and other related technologies. He likes to share his experience and knowledge through his blogs www.dotnet-tricks.com and www.windowsappstutorial.com, which he started in Jan 2012. He strives to be the best he can be. He always tries to gain more knowledge and skills in Microsoft Technologies. He always keeps up with new technologies and learning new skills that allow him to provide better solutions to problems. Shiju Varghese is a Microsoft MVP and a Technical Architect, specializing in Cloud, Mobility, and Web technologies. His current technology focus is on Windows Azure, ASP.NET MVC, Node.js, HTML 5, and CQRS. Shiju is passionate about building Cloud apps on the Windows Azure Platform. His areas of interest include Cloud Computing, Enterprise Mobility, Agile software development, Domain-Driven Design (DDD), Test-Driven Development (TDD), and Web application scalability. Shiju has been working with .NET technologies since its inception. Shiju works as a Technical Architect in Marlabs Inc where he is focusing on Cloud apps with Windows Azure. Thanks to my lovely wife, Rosmi, for her support and motivation. I would also like to thank my daughter, Irene Rose. www.PacktPub.com Support files, eBooks, discount offers and more You might want to visit www.PacktPub.com for support files and downloads related to your book. Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at service@ packtpub.com for more details. At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks. TM http://PacktLib.PacktPub.com Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book library. Here, you can access, read and search across Packt's entire library of books.  Why Subscribe? • Fully searchable across every book published by Packt • Copy and paste, print and bookmark content • On demand and accessible via web browser Free Access for Packt account holders If you have an account with Packt at www.PacktPub.com, you can use this to access PacktLib today and view nine entirely free books. Simply use your login credentials for immediate access. Instant Updates on New Packt Books Get notified! Find out when new books are published by following @PacktEnterprise on Twitter, or the Packt Enterprise Facebook page. Table of Contents Preface 1 Chapter 1: Developing for the Mobile Web 9 History of the mobile web 10 The Nokia 9000 10 Market fragmentation 11 WAP 1.0 and WML 11 WAP 2.0 and XHTML MP 12 Continued development constraints 12 Processing constraints 12 Network constraints 13 Content compression 13 Image optimizations 14 Content Delivery Networks 17 Presentation constraints 18 Single window 18 Lower resolution 18 Content spacing 19 Viewing the mobile web 19 Market percentage 19 Browser variants and compatibility 19 WebKit 20 Trident 20 Gecko 20 Presto 20 Emulating the mobile web 20 Mobile device and browser emulators 20 The user agent 21 Support for the mobile web in ASP.NET MVC 4 27 Summary 28 Table of Contents [ ii ] Chapter 2: Homebrew and You 29 Understanding the homebrew domain 29 Knowing your ingredients 29 Malt 30 Yeast 30 Brewing 30 Fermentation 31 Bottling and kegging 31 About our mobile app 32 App requirements 32 Adding, editing, and deleting recipes 32 Adding recipes to a library 32 Rating recipes 32 Commenting on recipes 33 Anonymous browsing, authenticated contributing 33 The BrewHow solution 33 Creating the project 33 Choosing our template 34 The Empty template 35 The Basic template 35 The Internet Application template 35 The Intranet Application template 35 The Mobile Application template 35 The Web API template 35 Project changes in MVC 4 37 NuGet 37 Global.asax 38 Launching the BrewHow app 39 Responsive design 40 Configuring and launching an emulator 40 Summary 46 Chapter 3: Introducing ASP.NET MVC 4 47 The Model-View-Controller pattern 47 The controller 47 The view 48 The model 48 The MVC pattern and ASP.NET MVC 4 48 Controllers in ASP.NET MVC 48 Creating the Recipe controller 50 Introduction to routing 52 Action methods 53 ActionResults 54 Invoking the Recipe controller 56 Views in ASP.NET MVC 57 Razor 57 Table of Contents [ iii ] Shared views 60 Layouts 61 The _ViewStart file 61 Partial views 62 HTML helpers 62 Display templates 63 Editor templates 65 Creating our Recipe view 65 Returning a model to the view 69 Using ViewData 69 Using ViewBag 69 Using TempData 71 Strongly typed models 71 Returning a Recipe list 72 Summary 78 Chapter 4: Modeling BrewHow in EF5 79 What's new in Entity Framework 5.0? 80 Performance enhancements 80 LocalDB support 80 Enumeration support 81 The BrewHow model 81 Modeling data 82 Recipe 82 Review 82 Style 82 Category 83 The BrewHow context 83 Generating our database 84 Altering the model 86 Adding relationships 87 Overriding conventions 87 Enabling migrations 89 Adding seed data 92 Adding a migration 94 Applying migrations 95 Consuming the model 98 Pagination 99 Summary 102 Chapter 5: The BrewHow Domain and Domain-driven Design 103 Tenets of DDD 104 Domain model 104 Entities 104 Value objects 104 Aggregates 105 Factories 105 Table of Contents [ iv ] Repositories 105 Services 106 BrewHow design 106 BrewHow entities 107 BrewHow repositories 107 Consuming the domain 109 Recipe view model 109 Recipe controller 112 Recipe views 115 Summary 118 Chapter 6: Writing Maintainable Code 119 The SOLID principles 119 Single Responsibility Principle 120 Open Closed Principle 120 Liskov Substitution Principle 122 Interface Segregation Principle 122 Dependency Inversion Principle 124 SOLIDifying BrewHow 125 Adding interfaces 125 Infrastructure 126 Dependency Injection 127 Service locator 128 Managed Extensibility Framework 129 MEF Service Locator 130 Dependency Resolver 133 The MefDependencyResolver class 134 Completing the conversion 136 IBrewHowContext 136 Repositories 137 Registering dependencies 138 Summary 140 Chapter 7: Separating Functionality Using Routes and Areas 141 Routes 142 Locating by style 142 Routing constraints 143 Style interaction 146 Slugging BrewHow 149 Model slugs 150 Areas 154 Creating the review area 155 Registering the Review area 156 The Recipe review controller 158 Recipe review view models 158 Table of Contents [ v ] Recipe review action methods 158 Creating the views 160 Area route values 162 Routing namespaces 163 Summary 166 Chapter 8: Validating User Input 167 Data validation 167 Data annotations 168 MetadataType attribute 168 Updating the database 169 Validating the validations 170 Cross-Site Request Forgery (CSRF) 172 ValidateAntiForgeryToken 173 Cross-Site Scripting (XSS) 175 ValidateInput attribute 176 AllowHtml 177 Html.Raw 178 Summary 179 Chapter 9: Identifying and Authorizing Users 181 User authentication 181 Windows authentication 182 Forms authentication 182 Authenticating BrewHow users 182 SimpleMembership 183 Customizing authentication 185 SimpleMembership initialization 185 Unifying contexts 186 The UserProfile repository 188 AccountController contexts 189 Registering and logging in 191 External authentication 193 Registering with an external account 193 Associating an external account 196 Authorization 196 Restricting access 196 The Authorize attribute 197 Authorizing user contributions 197 Cleaning the UI 198 Content ownership 199 Enabling ownership 200 Assigning ownership 204 Enforcing ownership 205 A recipe library 207 The library data model 208 Table of Contents [ vi ] The library repository 209 The library controller 209 The library view 211 Summary 213 Chapter 10: Asynchronous Programming and Bundles 215 Asynchronous programming 215 Task Parallel Library 216 Task 216 Async 219 Await 220 Asynchronous controller action methods 221 Creating asynchronous actions 222 An asynchronous recipe controller 223 Bundles 224 Creating bundles 225 Bundle types 225 Wildcard support 226 Consuming bundles 227 Summary 232 Chapter 11: Coding for the Real-time Web 233 Simulating a connected state 234 Long polling 234 Forever Frame 234 Server-Sent Events 235 WebSockets 235 SignalR 236 Persistent connections 237 Hubs 238 Real-time recipe updates 238 Installing and configuring SignalR 239 Creating the recipe hub 240 Modifying the recipe list view 241 Publishing event notifications 243 Summary 245 Chapter 12: Designing Your App for Mobile Devices 247 HTML5 247 Markup changes 248 The DOCTYPE tag 248 The character set 249 Type attributes 249 Visual Studio 2012 support 250 Table of Contents [ vii ] Semantic tags 251 The article tag 252 The header tag 252 The section tag 252 The nav tag 252 The footer tag 253 Modifying recipe details 253 Custom data attributes 255 Form controls 256 Local storage 258 Geolocation 258 CSS3 259 Media types 259 CSS selectors 259 Type selectors 260 ID selectors 260 Attribute selectors 260 Class selectors 261 Universal selectors 262 Pseudo-class selectors 262 CSS media queries 263 Media features 263 The viewport meta tag 264 A responsive design 265 A responsive list 267 Summary 269 Chapter 13: Extending Support for the Mobile Web 271 Mobile views 272 A .Mobile layout 272 Mobilizing BrewHow 274 Removing content 275 Prioritizing content 277 How it works 278 Display modes 281 Supporting Asus Nexus 7 282 Creating the display mode 282 Registering the display mode 283 Testing with Nexus 7 284 Summary 285 Chapter 14: Improving the User Experience with jQuery Mobile 287 Installing jQuery Mobile 288 Enabling the jQuery Mobile bundle 289 Viewing the results 289 Table of Contents [ viii ] jQuery Mobile's layout 290 Data-roles and data attributes 291 Form elements 292 Themes 293 $.mobile 294 View switcher 295 Mobilizing BrewHow 295 Adjusting the header 296 The home button 298 Logging in users 299 Site navigation 299 Creating a footer 300 Desktop footer 300 Configuring content 301 Recipe list 301 Recipe details 306 Recipe edits 310 Reviews 312 Summary 317 Chapter 15: Reader Challenges 319 Full-text search 319 Embedded search 320 Search boxes 320 APIs 320 Lucene.NET 320 SQL Server Full-text Search 321 Socialization 321 Social media support 321 Recipe additions 322 Recipe sharing 322 Offline support 322 Push notifications 323 Going native 323 ASP.NET Web API 323 Developing native apps 324 PhoneGap and Appcelerator 324 Xamarin 324 Summary 325 Index 327 Preface Today's web developers are faced with a multitude of challenges in delivering their product to market. Once upon a time, applications only needed to look and function properly within Internet Explorer. Today's applications must not only function within multiple browsers, but on multiple operating systems running on multiple devices. ASP.NET MVC 4 Mobile App Development is meant to serve as a guide to successfully building web applications that target current desktop browsers and browsers meant to consume the mobile web. ASP.NET MVC 4 Mobile App Development walks you through the process of creating a web application from concept to delivery. What this book covers In the first section of this book, we build a fully functional sample application to manage and share recipes for homebrewed beers. Chapter 1, Developing for the Mobile Web, begins with a discussion on the importance of understanding how to develop for the mobile web. You are then given a brief history of how we arrived to at the mobile web of today. The chapter ends by discussing all of the constraints we, as developers, must acknowledge if we are to successfully develop applications for the mobile web. Chapter 2, Homebrew and You, introduces you to the domain of homebrewing and BrewHow—our homebrew recipe sharing application. From our understanding of this domain we build the requirements for our application and then examine how ASP.NET MVC 4 and its new features will help us develop it. We conclude the chapter by setting up our environment to launch our mobile emulator to design and test our application. Preface [ 2 ] Chapter 3, Introducing ASP.NET MVC 4, introduces the MVC pattern. We then discuss how it is implemented within ASP.NET MVC 4 as we begin to build our application. By the end of this chapter the initial shell of our application will be complete and running inside our desktop and mobile browsers. Chapter 4, Modeling BrewHow in EF5, walks us through creating a data model for BrewHow. We begin by discussing the new features and improvements of Entity framework and create a data model and database for our domain using the code-first model in EF. The model and database are continually refined through the use of migrations until the needs of our application are met and our application is consuming data from LocalDB. Chapter 5, The BrewHow Domain and Domain-driven Design, introduces us to the tenets of DDD. We apply these tenets to BrewHow by creating repositories, view models, and domain entities to enforce the boundaries between persistence, logic, and display. Chapter 6, Writing Maintainable Code, begins with a discussion on the SOLID principles of object-oriented design; principles that serve to facilitate the writing of maintainable code. We then review the topics of Dependency Injection and Inversion of Control as tools to help us SOLIDify the BrewHow codebase. This chapter ends by applying these principles and tools to the codebase leveraging the extension points provided to us by ASP.NET MVC 4. Chapter 7, Separating Functionality Using Routes and Areas, provides a detailed discussion on this key piece of technology in ASP.NET MVC 4. We examine how, by leveraging routing and areas, we can create meaningful SEO-friendly URLs and separate the functionality of BrewHow into discrete units of work for the content contained within BrewHow. We then exercise our knowledge by adding support for user reviews. Chapter 8, Validating User Input, looks at the server-side support for data validation contained within the .NET Framework's System.ComponentModel.DataAnnotations namespace. The data model and view models are modified to support the use of these attributes so we can validate input on the client side and again once the data has made it to the server. We also explore how these technologies help protect BrewHow from common web attacks such as CSRF and XSS. Chapter 9, Identifying and Authorizing Users, introduces the new membership functionality available in ASP.NET MVC 4. BrewHow is modified to support user authentication using the new membership functionality and we then modify the application to allow authentication using a Google login. We end the chapter by tying together the BrewHow data model with the membership data model so we can associate recipes and reviews with the users that created them. Preface [ 3 ] Our application is now functionally complete and has met all of the requirements set forth in Chapter 2, Homebrew and You. In the second section of the book we take a look at a few advanced features provided by ASP.NET MVC 4. Chapter 10, Asynchronous Programming and Bundles, explores how we can design the server-side portion of our application to get information to our users more efficiently and with less wait time—something critical for mobile applications. To accomplish this, we begin by examining and then implementing support for asynchronous actions. We then examine the support of minification provided to us in the form of bundles. Chapter 11, Coding for the Real-Time Web, investigates how we can use always-on connectivity to provide the illusion of a desktop application within BrewHow. We then leverage SignalR to simulate push notifications from the server to BrewHow. With our application fully optimized to deliver content to mobile devices, we can now begin the third part of the book. Chapter 12, Designing Your App for Mobile Devices, discusses how we can use the next-generation of web standards, HTML5 and CSS3, to create responsive markup to present our content to users in a manner best fitting the device on which they are viewing it. Chapter 13, Extending Support for the Mobile Web, extends the concept of mobile design to our servers as we explore the mobile view support built into ASP.NET MVC 4. We then extend this concept to target specific mobile devices using the new support for display modes. Chapter 14, Improving the User Experience with jQuery Mobile, shows how BrewHow can be converted to a mobile web application that looks and feels as if it were native to the device. We look at some of the controls provided by jQuery Mobile and apply them within the context of everything we have learned to build a fully polished and functional mobile application. Chapter 15, Reader Challenges, presents how BrewHow could be extended to be an even richer experience for the user. We discuss how full-text search technology could be integrated into BrewHow, how we might provide support for social networking, and how we might even extend BrewHow into a truly native mobile application. The readers are then encouraged to undertake these tasks themselves. What you need for this book To build the sample application within this book you will need a copy of Microsoft Visual Studio Express for Web 2012. To view the sample application you will need a web browser capable of supporting HTML5 and CSS3. The sample application in this book was tested using the current version of Google Chrome and Opera Mobile Emulator running on Windows 8. Preface [ 4 ] Who this book is for This book is for any individual wishing to learn ASP.NET MVC 4 and its role in developing applications that target the mobile web. The material in this book assumes the reader has familiarity with the .NET framework and exposure to C#. If you are new to ASP.NET MVC and want a good solid introduction, if you want to learn what's new in ASP.NET MVC 4, or if you want to learn how you can modify your web applications to support multiple devices this book is for you. Conventions In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meaning. Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: " In prior versions of MVC, all of the application bootstrap code was located in the Global.asax code-behind". A block of code is set as follows: .white-go { width:31px; background:url('img-sprite.png') 0 0; } .orange-go { width: 31px; background:url('img-sprite.png') -32px 0; } When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold: public interface IBrewHowContext { IDbSet Recipes { get; set; } IDbSet Reviews { get; set; } IDbSet Styles { get; set; } Preface [ 5 ] IDbSet UserProfiles { get; set; } int SaveChanges(); } public class BrewHowContext : DbContext, IBrewHowContext { public IDbSet Recipes { get; set; } public IDbSet Reviews { get; set; } public IDbSet Styles { get; set; } public IDbSet UserProfiles { get; set; } public BrewHowContext() : base("DefaultConnection") { } /* ... */ } New terms and important words are shown in bold. Words that you see on the screen, in menus or dialog boxes for example, appear in the text like this: "Select the ASP.NET MVC 4 Web Application icon and provide a name and location for the new project in the Name and Location text boxes respectively". Warnings or important notes appear in a box like this. Tips and tricks appear like this. Preface [ 6 ] Reader feedback Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or may have disliked. Reader feedback is important for us to develop titles that you really get the most out of. To send us general feedback, simply send an e-mail to feedback@packtpub.com, and mention the book title via the subject of your message. If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide on www.packtpub.com/authors. Customer support Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase. Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you. Errata Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you would report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub. com/submit-errata, selecting your book, clicking on the errata submission form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded on our website, or added to any list of existing errata, under the Errata section of that title. Any existing errata can be viewed by selecting your title from http://www.packtpub.com/support. Preface [ 7 ] Piracy Piracy of copyright material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works, in any form, on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy. Please contact us at copyright@packtpub.com with a link to the suspected pirated material. We appreciate your help in protecting our authors, and our ability to bring you valuable content. Questions You can contact us at questions@packtpub.com if you are having a problem with any aspect of the book, and we will do our best to address it. Developing for the Mobile Web If you are at all interested in developing web apps in the future, it is important you understand the increasing role played by mobile devices, and how to develop apps fitting their capabilities. I'm saying this not to scare you into buying my book (though I hope that you are currently reading your purchased copy), but to underscore the fact that mobile computing will play an increased role in the lives of every connected person. To appreciate the growth in mobile usage, one should consider the iPhone. The iPhone, typically heralded as the smartphone that began the current mobile computing revolution, wasn't introduced until 2007. At the end of 2008, more than a year after its release, mobile traffic accounted for less than 1 percent of the global Internet traffic, which was not much of a revolution. However, by the end of 2010, mobile traffic accounted for nearly 5 percent of all the Internet traffic, and at the end of 2012 it was nearly 13 percent. Halfway through 2013, mobile traffic has passed 15 percent of all the Internet traffic. This trend is roughly a multiplier of 1.5, year-over-year, and is likely to accelerate. In the 4th quarter of 2012, iPad sales reached approximately 140,000,000 total units shipped, approximately 3 times the total number of iPhones shipped. The iPad was introduced 3 years after the iPhone, and just 3 years after the tablet revolution was launched by the iPad, total tablet shipments in the 4th quarter of 2012 surpassed both desktop and notebook shipments. As developers, it is important we understand and embrace this mobile revolution or else we will be run over by it. Developing for the Mobile Web [ 10 ] Throughout this book, we will be building a fully functional web app using ASP. NET MVC 4, HTML5, and CSS3 to support both desktop and mobile computing platforms. We will begin with building the desktop version of the web app but will be keeping mobile considerations in mind. Once our desktop app is complete, we will modify it to support the mobile web using concepts such as responsive design and media queries. During this modification, we will examine the new features of ASP.NET MVC 4 we can use to better target mobile web devices. In the last chapters of this book, we will modify the app to support a truly mobile experience using jQuery Mobile. It is my goal that, by the end of the last chapter in this book, you will have a complete understanding of what it takes to develop for the mobile web, and the tools to take your mobile web apps to the next level. In this chapter, we will begin by examining a history of the mobile web. This understanding is essential in appreciating the unprecedented growth in the past few years. This chapter will also highlight some of the constraints that existed, and still exist, when trying to target the mobile devices of yesterday, today, and tomorrow. We will end with a preview of the new platform support in Microsoft ASP.NET MVC 4. Our journey into the mobile web begins now. History of the mobile web Without knowing how the mobile web started, it's impossible to appreciate the ease with which we can develop for mobile devices. If the mobile web works at all, it is a feat in itself, and it took the convergence of several technologies to make it all possible. The Nokia 9000 The Nokia 9000 is, arguably, the first mobile web device. Developed by Nokia in 1996, this phone weighed in at a whopping 14 ounces (397 g), and was powered by an Intel i386. It was equipped with a 640 x 200 pixel gray-scale LCD. This phone allowed owners to send faxes, send and receive email, and surf the web. It also came equipped with terminal and Telnet applications for accessing mainframe systems. Chapter 1 [ 11 ] Market fragmentation During this time, Nokia was in competition with Ericsson and others for control of the mobile data space. The Nokia 9000 was designed to use Narrow Band Sockets, a communication protocol developed and championed by Nokia. Information that was to be displayed on the Nokia 9000 was returned to the phone using Tagged Text Markup Language (TTML), a markup language that content providers could use to optimize web pages for mobile devices by removing extraneous information from the display and transmission. At about the same time, Ericsson had developed Intelligent Terminal Transfer Protocol (ITTP). ITTP was Ericsson's proprietary markup for the mobile web. It became evident to the major phone manufacturers that market fragmentation was going to be inevitable unless they could develop a common standard to enable the mobile web on their devices. WAP 1.0 and WML On June 26, 1997, Nokia, Ericsson, Motorola, and Unwired Planet publicly announced that they would be cooperating on a Wireless Application Protocol (WAP). WAP 1.0 was to be an open protocol that any vendor could implement, and this new protocol would enable mobile device manufacturers to connect to the IP-based world of the Internet from mobile devices that had an inherently high rate of data loss during communication. Wireless Markup Language (WML) became the standard for designing applications that ran on WAP 1.0, and was a second-generation derivative of HTML and XML. However, WAP and WML had some shortcomings. The protocol and companion markup languages were designed for very slow data networks and very limited display capabilities. If your device had limited data input capabilities and a low-resolution display, then WML served you well, but with the advent of smart phones and mobile web browsers, derivatives of their desktop counterparts, WAP 1.0 and WML became less relevant. Developing for the Mobile Web [ 12 ] WAP 2.0 and XHTML MP As the convergence of mobile phones and PDAs gained momentum, new standards were needed to support the growing use of web-enabled mobile devices. To support the new browsers that began to ship with mobile devices, a new markup language was required. In 2001, eXtensible HyperText Markup Language Mobile Profile (XHTML MP) was adapted from XHTML Basic by the WAP Forum (now part of the Open Mobile Alliance) to replace WML as the default protocol for WAP. While WAP became the standard in the United States, United Kingdom, and Europe, the standard in Japan, i-mode, was developed by NTT DoCoMo. The new standards were short-lived. Today, most mobile devices ship with browsers supporting the latest HTML standards including HTML5 and CSS3, but it is still a good practice to deliver content to target the broadest market possible. Continued development constraints Having modern browsers on our phones, tablets, and other mobile devices doesn't mean we should make no accommodation for users of the mobile web. There are still many real-time constraints placed upon mobile devices which we, as developers, should take into consideration when writing mobile web apps. We can't simply shrink down the desktop version of our web app and provide a satisfying experience to the user. One must keep in mind when developing mobile apps that the mobile devices on which our app is being executed have different processing, network, and presentation constraints than their desktop counterparts. Processing constraints Today's mobile devices have several times the processing power of the Apollo Guidance Computer that put humans on the moon. They do not, however, have infinite processing power and have much less processing power than the common PC has at its disposal. To accommodate the lack of processing power, mobile web apps should refrain from running highly intensive JavaScript functions, image manipulation, or any other processor-intensive operations in your app unless it is absolutely necessary to the functionality of the app. Chapter 1 [ 13 ] One way to reduce the load on the client is to make certain determinations on the server before returning content back to the mobile device. This practice, referred to as server-side browser sniffing, allows the application to return web pages and content targeted for a specific device, and limits the need to do browser capability checks on the client. It is during this time that you can also preprocess data that would be returned to the client for processing otherwise. This is a shift from current web development trends where data is typically submitted to the client for processing. By reducing the amount of content that is returned to the client by the server, you also mitigate some of the network constraints inherent to mobile devices. Network constraints While today's mobile networks rival, and in some cases surpass, speeds available to home-based broadband networks, your users may be constrained by data limits, speed governance, corporate policy, or some other constraint on the limit or speed at which they can retrieve data on their mobile device. Mobile networks also inherently lose more network data in transmission than land- based communication. This data loss has two effects on the application and the user experience. Firstly, packet loss requires the TCP/IP stack implementation to request resends for lost packets and increases the amount of data that must be sent across the network. Secondly, your app needs to be written such that it can survive failed requests because it's guaranteed to happen. How do we, as developers, ensure that our mobile web apps provide a great user experience on such a network? Content compression We can start reducing the amount of data representing content we're sending to the client by compressing it on the server side. Server to client compression Content compression can occur as part of the communication between client apps and web servers that support it. Content compression works by serving static, and occasionally dynamic content, and compressing it using gzip or deflate before returning it to the requesting app. Developing for the Mobile Web [ 14 ] For a client to indicate that it can accept and process content, it must send an Accept-Encoding HTTP header with the request with the types of encoding it will accept. Accept-Encoding: gzip, deflate Enabling compression on the server is vendor and version-specific. It should be noted that while enabling compression on the server for communication does reduce the amount of data the server must send, it increases server processor utilization. In addition to compression, we can also reduce the amount of data that needs to be sent to the client through a process called minification. Minification Minification is the act of removing extraneous white space from our HTML, CSS, and JavaScript files. Minification is not compression in the typical sense. The benefit of minification is that while you have reduced the amount of data you are sending to the client, it is immediately usable because nothing functional from that data has been removed. Some minification techniques can also serve as a way to obfuscate JavaScript making it harder for people with ill intent to decipher what your code is doing. This is accomplished by parsing the content that is being minified and renaming long variables to between 1 and 3 characters. Think Security Never perform any action on the client that requires you to expose keys, usernames, passwords, or other sensitive information. Transmitting this information to the client is inviting mischief. Image optimizations Images make up a large percentage of the content your app will be serving to the client. Outside of minification, image optimizations may be one of the fastest ways to reduce the size of your app. Chapter 1 [ 15 ] Lower color depth Perhaps the easiest way to optimize images on your site is to reduce their color depth. Most images on the web are icons that can easily be represented with images of 8-bit or 16-bit color depth. With that said, it is an art more than a science. As today's mobile device displays increase their pixel depth, images of poor quality can detract from the functionality of your site and may discourage some users from using it. CSS image sprites An image sprite is a single image (that contains multiple images) that might be used on a site. The image sprite is then referenced by the stylesheet with different image offsets to only show a portion of that image. The following image from the Packt Publishing website (www.packtpub.com) is an example of an image sprite: This image is actually a single image that contains two images for the site to use. Both images are 31 x 31 pixels. From this image we can create the following two styles: .white-go { width:31px; background:url('img-sprite.png') 0 0; } .orange-go { width: 31px; background:url('img-sprite.png') -32px 0; } Firstly, note that the styles both have a width that is limited to the width of the actual image we want to display, that is, 31 pixels. The white-go class sets the background image of the element which is applied to the sprite and sets the offset of the image to be the top-left corner, that is, 0,0. Since the image is restricted to 31 pixels wide, the viewer of the image will only be presented with the portion of the image containing the white go button. The orange-go class has a negative offset to the image display telling the browser to show 31 pixels of the image starting at pixel 32. This displays only the orange image. Developing for the Mobile Web [ 16 ] Both images may be reused by the app by applying the defined styles to the elements within the HTML markup, but the true benefit is that the app only made one request to the server to retrieve both images. Data URIs Data URIs (Universal Resource Identifiers) allow you to put content data directly into a URI link. The URI is formatted using the data:[][;base64], format. From RFC 2397, the data URI scheme is defined as follows: The is an Internet media type specification (with optional parameters). The appearance of ";base64" means that the data is encoded as base64. Without ";base64", the data (as a sequence of octets) is represented using ASCII encoding for octets inside the range of safe URL characters and using the standard %xx hex encoding of URLs for octets outside that range. If is omitted, it defaults to text/plain;charset=US-ASCII. Assume we want to embed the following simple image in a page using a data URI: If you were to embed the image above as a base-64 encoded PNG data URI into a page on your site, you would construct a data URI in your HTML source. Chapter 1 [ 17 ] This provides the browser the benefit of not having to make a separate request to retrieve the image. With some clever JavaScript and CSS you could reuse the content of the URI without submitting another request to retrieve the image or embedding the image twice into the page. As part of the page content, there is a second added benefit: the image data is compressed when sent from the server to the client as part of the web server's gzip compression. Data URIs are not supported in all browsers. If you elect to use data URIs in your site, make sure that your target market's primary browser supports them. Content Delivery Networks A Content Delivery Network (CDN) is a distributed network of servers that exist solely for returning static content. CDNs can reduce network load by hosting static content that is commonly cached and reducing the amount of data an application sends and receives for any given request. Cached data If you are using common third-party libraries such as jQuery, the mobile device executing your app may have already loaded that library from a third-party CDN. If the device has already retrieved the data you want to load, there is no need for the client to retrieve it again from the server. It can simply load it from the cache. There are several free CDN networks available for common content. As of this writing, Microsoft hosts a large amount of common third-party content on its CDN, of which a listing may be found at http://www.asp.net/ajaxlibrary/cdn.ashx. As a routine point of maintenance, you will want to make sure the CDN you are using for shared content continues to provide the content. If they remove the content, your app will eventually degrade or fail. Less traffic A CDN is also useful for your proprietary static content. If you are using cookies within your site, every HTTP request to the domain specified in the cookie will retransmit the cookie data. Static content has no need for this data and it is consuming bandwidth that could be used elsewhere. If you move the static content of your site onto a different domain than the domain(s) on which your cookies reside, you reduce the amount of data sent to and from your app. Developing for the Mobile Web [ 18 ] Don't make them wait While it is critical to limit the amount of time any user has to wait to load your app's content, this is especially true of mobile web apps. Presentation constraints Processing constraints and network constraints help define how you implement your background services, but it is what the user sees that typically defines their experience. When presenting the content of your app to the user you need to keep in mind there are very real constraints placed on how information is presented to the user. Single window For starters, you only have a single window in which you can work. This means you should not be creating content that requires pop-up windows. Pop-up windows will open up in new tabs on most mobile browsers and those browsers may have limits as to the number of tabs open at any given time. It is far better to stick with a simple navigation paradigm, and reduce the amount of data you present to the user at any given time. The user may have a few more screen touches to navigate through your application, but if you make the behavior consistent then it is unlikely your users will notice. Lower resolution With the exception of the newest mobile devices on the market, most devices do not have the resolution of their desktop counterparts. Comparing standard phone form factors, the iPhone 5 has a screen resolution of 1136 x 640 pixels and the Samsung Galaxy S3 has a resolution of 1280 x 720. Of the popular 7-inch tablets, both the Kindle Fire HD and Google Nexus 7 have a screen resolution of 1280 x 800. Only the largest tablets such as the 10-inch third generation iPad (2048 x 1536) and the 8.9-inch Kindle Fire HD (1920 x 1200) come close to matching a desktop's display capability. By way of comparison, the iPhone 4 and iPhone 4S have a resolution of 960 x 640. Chapter 1 [ 19 ] While these resolutions seem respectable for mobile devices you must keep in mind that these resolutions are presented on screens that are substantially smaller than a desktop monitor, meaning not only is the number of available pixels for your app reduced on these smaller displays, but your app needs to present content, text, and buttons larger than it would to a desktop browser. This is partly because of the increased pixel density of the mobile devices, and partly because the input mechanism to these devices is your user's finger. Content spacing Designing a system to support touch instead of traditional input methods of mouse and keyboard mean that your buttons need to be larger, and a larger area of padding must surround any area of the screen that is designed for interaction with the user. This means your user interface and user experience must account for a large percentage of spacing. Viewing the mobile web While most of us own one, two, or perhaps three or more mobile devices with which we can browse the web, we need to develop our mobile web applications to support the broadest number of devices possible. Market percentage It is important for us to look at what technology is being used to browse the mobile web, so that we can target our mobile app appropriately. Currently, Android and iOS dominate the mobile OS market, but the newest version of Windows Mobile is gaining market share. Supporting the common browsers on these operating systems should be sufficient for most application needs. Browser variants and compatibility How does one target these specific browsers? All of these systems allow third-party browsers to be installed on them, so we cannot look at OS percentages as the sole determining factor when looking at compatibility. Fortunately, while there are multiple browsers available for these platforms, there are only a handful of layout engines with which we must concern ourselves. Developing for the Mobile Web [ 20 ] WebKit WebKit is the layout engine for the majority of the web. Safari, Chrome, the Android Web Browser, Dolphin HD (a popular third-party Android web browser), Blackberry Browser 6.0+, and even a version of the PS3 software all use WebKit. If you target WebKit without any vendor-specific extensions, you will be supporting a huge segment of the web. Trident Internet Explorer uses the Trident engine to lay out HTML content. If you have done any Windows desktop development you might know this engine by the name MSHTML. Trident has received a new version with every release of Internet Explorer since Internet Explorer 7. Both Windows and Windows Mobile share the same version of the engine. Internet Explorer 10 and Internet Explorer Mobile 10 use Version 6.0 of the Trident engine. Gecko Gecko has been around since Netscape 6, and is the current layout engine in Firefox, and several other Mozilla Foundation projects. Presto The Opera browser and the Nintendo DS/DSi use the Presto engine. This engine is only available as part of Opera but cannot be overlooked. Opera was the dominant browser on the mobile web and, depending on whose statistics you believe, continues to be the number two or number three used mobile browser today with over 20 percent of the market (no single browser currently eclipses 25 percent). Emulating the mobile web Since we will be implementing our mobile app on a desktop or laptop, we will want to emulate the mobile devices we are targeting. We can do this by installing emulators for each platform on our development machine, or by faking the mobile browser experience within our computer's browser. Mobile device and browser emulators Mobile device simulators provide us the best means of testing the functionality of our app within a mobile browser without having access to a physical mobile device. Chapter 1 [ 21 ] Opera The Opera Mobile Emulator has the smallest footprint of any emulator available. This is in large part due to the fact that there is no emulation of a mobile operating system. The installation comes with support for various device and browser version variants allowing you to test your app's look and feel on any device on which Opera Mobile is offered. There is also an optional install for Opera Dragonfly. Dragonfly allows you to debug your CSS and JavaScript as well as tune the performance of your app inside the emulator. The Opera Mobile Emulator may be downloaded at http://www.opera.com/ developer/tools/mobile/. Android The Android SDK, available at http://developer.android.com/sdk, comes with a mobile device emulator you can use to test your applications on the Android platform. The SDK requires you to install several third-party tools, JDK 6 most notably, to be fully functional. iOS If you do not have access to a machine running OS X, you cannot emulate the iOS environment with the official Apple SDK tools. Third-party emulators do exist, and you can find them by consulting your local search engine. Mac users may download the iOS emulator as part of Xcode (Apple's IDE) at https://developer.apple.com/ xcode/index.php. Windows Mobile Microsoft provides a rather comprehensive set of tools with its Windows Mobile SDK. You can download and install the Windows Mobile SDK at http://dev. windowsphone.com/. The user agent Outside of an emulator, the easiest way for us to view the mobile web for multiple browser and device variants is by manipulating our desktop browser's user agent. The user agent is contained in an HTTP header the browser sends with any standard request for content to identify itself to the web server. The following line is a representation of the User-Agent HTTP header that Internet Explorer 10 submits to a web server with each request: User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0) Developing for the Mobile Web [ 22 ] It cannot be stressed enough that altering the user agent is only marginally beneficial for testing the application. Even though mobile browsers are often built on top of the layout engines of their desktop brethren, you cannot assume that these engines will behave the same. The mobile engines are often ports of the desktop engines, and may have been altered or tweaked due to mobile device constraints. They may even not be written in the same language. Due to these issues, it must not be assumed that WebKit == WebKit. It does not. Because of this you will want to test your application using actual mobile devices, and all browser variants for which your mobile web app is targeted before pushing a product out to a production system. With that said, let's examine how to set the User-Agent string of Internet Explorer, Safari, and Chrome so that they identify themselves to a web server as their mobile version. Emulating Internet Explorer Mobile To emulate Internet Explorer Mobile from the desktop, you will need to access the developer tools. To do this, you can either press F12 in Internet Explorer or click on the settings wheel in the top-left corner of the window, and select F12 developer tools from the menu options. Chapter 1 [ 23 ] Internet Explorer will then present a dockable window containing the Internet Explorer developer tools. In the tools window, click on Tools from the menu, and then select the Change user agent string menu option. You will be presented with a list of preconfigured User-Agent strings within Internet Explorer. You may also enter a custom User-Agent string by selecting the Custom… menu option. Internet Explorer will revert to the default User-Agent string after you close all browser windows and exit the process. This is important to remember when you are debugging your mobile app using Internet Explorer. Developing for the Mobile Web [ 24 ] Emulating Mobile Safari To set the User-Agent string in Mobile Safari we first have to enable the mobile tools. To do this, open the preferences pane for Safari by pressing Ctrl + , or by clicking on the settings icon in the top-left corner of the window, and then clicking Preferences…. On the Preferences window, click on the icon labeled Advanced to display the Advanced Preferences pane, and ensure that the checkbox captioned Show Desktop menu in menu bar is checked. Chapter 1 [ 25 ] After you close the window, you will have a new Develop menu available. Clicking on the menu and hovering over User Agent will open up the known User-Agent strings for which Safari has built-in support. If you do not see the User-Agent string you wish to target, you may provide a custom User-Agent string by clicking on the menu item labeled Other…. It is important to note that Safari, like Internet Explorer, will restore the value of the User-Agent string to the default value after you close the browser window. Emulating Chrome for Mobile Like Safari, Chrome has built-in developer tools that are immediately accessible by pressing Ctrl + Shift + I or by clicking the customize icon in the top-right, selecting Tools and then clicking on the Developer tools menu item. Developing for the Mobile Web [ 26 ] Clicking on the Developer tools menu item will display a docked window at the bottom of the browser. In the bottom-left corner of this window is a small gear icon. Clicking on the icon will display the settings for the developer tools in an overlaid window. The window has three tabs: General, Overrides, and Shortcuts. Click on the Overrides tab, check the checkbox labeled User Agent, and then select the User-Agent string you wish to use from the drop-down menu. Like Safari and Internet Explorer, you can create custom User-Agent strings to be used by the browser. Unlike those browsers, Google Chrome will remember the User-Agent string to be used if you close all the windows. Emulation in this book When using user agent emulation, all samples in this book will emulate the mobile Safari browser used by iOS from within Chrome. This is in small part due to Chrome using the same layout engine as Safari, but is primarily due to the developer tools that are built into the browser itself and the fact that it is more widely installed on computers running Windows than is Safari. Chapter 1 [ 27 ] When using a mobile emulator, we will use Opera Mobile emulating a Samsung Galaxy S II—a device that has a screen resolution of 480 x 800, and has 216 pixels per inch. We will also show screens from a few physical devices such as iPhone 4, iPhone 5, and the Asus Nexus 7 Android tablet. You should feel free to run the samples in the book against any browser or emulator mentioned above. Support for the mobile web in ASP.NET MVC 4 Microsoft has unprecedented development support for the mobile web with Visual Studio 2012 and ASP.NET MVC 4.0. Out-of-the-box, the latest environment supports: • HTML5 and CSS3 (standards crucial to developing responsive mobile web apps) • The ability to merge, compress, and transform JavaScript and CSS files to minimize browser requests and bandwidth requirements • New convention support to target specific mobile platforms • As part of the new mobile application project template, jQuery Mobile integration into your mobile app projects All of these improvements to Microsoft's development environment directly address the constraints with which we, as developers, engineers, architects, and content designers, must concern ourselves. If you couple these improvements with the improvements in .NET 4.5, .NET users such as us can now target the mobile web better than ever before. Developing for the Mobile Web [ 28 ] Summary In this chapter, we learned why it is important as developers to embrace the mobile web and ensure that our apps support it. We began with a brief history of the mobile web and the constraints still placed upon developers like us to ensure an optimal user experience when viewing our sites through a mobile browser. We also learned how to emulate the common mobile browsers from our desktop and received a glimpse of what Microsoft has provided in support of the mobile web with the new ASP.NET MVC 4 tooling, Visual Studio 2012, and .NET 4.5. In the next chapter, we will create the shell for our app—a homebrew recipe sharing app called BrewHow—and configure our environment to run the app within an emulator. Homebrew and You In this chapter, we will discuss everything you need to know to build our sample app, a recipe-sharing site for homebrewers. We will begin with a discussion on homebrewing in order to understand the domain of our sample app. From our understanding of the domain, we will determine requirements. We will then create the solution for our app using one of the new MVC 4 (Model-View-Controller) project templates and examine the output of the template to discuss the notable changes between MVC 3 and MVC 4. Finally, we will configure Visual Studio to launch an emulator and a desktop browser simultaneously when starting our app. Understanding the homebrew domain The brewing and fermentation of malt that creates the delicious beverage commonly referred to as beer has been around since ancient Egypt. Beer is comprised of four ingredients: water, malt, hops, and yeast. This simple combination of four ingredients can produce a wide variety of beverages and it is this quest for variety that has sparked the homebrew and craft brew movement so active today. Knowing your ingredients Any good recipe starts with a list of ingredients. A beer recipe will start with the list of grains to be used, any adjuncts (special ingredients such as coffee, chocolate, fruit, or spices that will give the beer a new flavor or enhance an existing characteristic of the brew), the strain of yeast to be used, and hops used for bittering and aroma. Homebrew and You [ 30 ] Malt Malt is any grain that has been allowed to begin the germination process. It is the germination of the grain that allows the grain to produce enzymes that can convert starches contained in the grain to sugar and break down protein to feed the yeast. It is the converted sugar of the malt that gives beer its sweetness and it is the same sugar that is converted to alcohol during the fermentation process. Yeast Yeast handles the conversion of sugars into alcohol. When brewing beer one must always consider that the yeast is alive. Proper handling of yeast, in addition to the sanitization of brewing equipment, is essential to brewing a successful batch of ale or lager. Ale versus lager Beer is either classified as ale or lager. The classification is based upon the type of yeast used to ferment the beer. Lager yeast ferments beer from the bottom of the chamber and is active at cooler temperatures than yeast used to create ales. Ale yeast ferments from the top and is most active at around 70 degrees Fahrenheit. The warmer fermentation temperatures of ale yeast require less special equipment than lagering yeast and, as such, most homebrew recipes are designed to create ales. Hops Hops are a type of flower used in recipes and lend to the distinct aroma and bitterness that most people associate with beer. As with grains and yeast, hops come in several varieties and each variety is measured by the aroma and bitterness that their inclusion in the recipe brings to the beer. Hops also aid in the prevention of spoilage of beer as they create an environment within the brew that is favorable to the yeast used to ferment beer. Brewing The brewing process takes our raw ingredients and transforms them into unfermented beer. There are three steps in the brewing process, namely, mashing, sparging, and the boil. Chapter 2 [ 31 ] Mashing Mashing is the process of soaking cracked malt in water in a temperature-controlled environment. Temperature control is important as different proteins, enzymes, and by-products are produced and released from the malt depending on the temperature at which the malt is maintained. These by-products of the malting process affect the body, head retention, clarity, and alcohol content of the beer being produced. The mashing process may be a single infusion or step infusion. Single infusion mashing holds the ingredients at a single temperature throughout the process. Step infusion, however, requires the brewer to alter the temperature of the ingredients throughout the mashing process to better control the release of proteins, enzymes, and by-products released from the malt. Sparging Sparging is the process of separating the spent grains, termed grist, from the mash and is essentially straining the mash into another container. Additional water is poured over the grist to free up any remaining starches, proteins, or sugars. The resulting liquid is called wort. The boil Once you've obtained your wort, the wort must be boiled. The boil typically lasts 60 minutes and is meant to sanitize the liquid to create an optimal environment for the yeast. It is during the boil that hops are added to the beer. Early addition of hops to the boil increases the bitterness of the beer. Later additions contribute to the aroma of the beer. Fermentation After the boil, the wort must be cooled quickly, typically to 70 degrees Farenheit, before we can add the yeast. After cooling, the wort is moved into a fermenter and yeast is added. The wort is then kept in a quite corner at a temperature beneficial for the strain of yeast used to ferment, typically for two weeks. Bottling and kegging We now have beer; it's flat beer, but beer nonetheless. To liven the beer up, we need to feed the yeast before we put the beer into bottles or kegs. To do this, we put a little priming sugar into the beer or into the bottles or kegs. Feeding the yeast with sugar will allow for the production of CO2 and its production will carbonate our beer. Homebrew and You [ 32 ] That's all there is to making beer. After two weeks, in the bottle or keg, the beer should be sufficiently carbonated to open up and share with your friends. Now that we have a deeper understanding, appreciation, and love for beer, let's go build an app to allow us to share recipes to the world's mobile devices. About our mobile app We just arrived at the homebrew supply store and, low and behold, we left our recipe at home. That's the last time this is going to happen. We're going to build an app that allows us to retrieve recipes on our phone. The recipes created and stored in our app will also provide a means for us to teach others about the brewing process and what makes good beer. To that end, we will name this app BrewHow. App requirements For us to be successful in our mission to create a great beer recipe site for the mobile web, we need to know the requirements that, when met, will determine success. Adding, editing, and deleting recipes How good is a recipe-sharing app without the ability to add and edit recipes? Our site will allow us to create recipes that can be shared with other people. It will also allow us to edit recipes that we have contributed to the site. Adding recipes to a library As we find good recipes, we will want to be able to locate them again. We need to support adding them to a library. We may also grow tired of them so we need the ability to remove them as well. Rating recipes Much as we rate music to better identify our tastes, we should do this with beer too. Our app will provide users the ability to rate recipes on a scale of one to five. Chapter 2 [ 33 ] Commenting on recipes We not only want to share recipes, but to solicit feedback on what makes good beer and how to make our beer better. To allow this type of feedback, we want to allow constructive comments about the recipes on our site. Anonymous browsing, authenticated contributing We want our recipes hosted within our mobile web app to be available to the world, but if a user wants to contribute to the site we want to know who the user is. Likewise, we don't want users editing the recipes contributed by other users. Seems like we need to add some authentication and authorization to our mobile app. Now that we know what our app should do, let's get started by creating our ASP.NET MVC 4 solution. The BrewHow solution To build the BrewHow mobile app, we are going to use Visual Studio Express 2012 for Web. If you don't have a version of Visual Studio capable of building ASP.NET MVC 4 projects, Visual Studio Express 2012 for Web is freely available at http://www.microsoft.com/visualstudio/eng/downloads. We will constantly refer to Visual Studio or Visual Studio 2012. These are references to any version of Visual Studio 2012 or Visual Studio 2010 SP1 that is capable of building ASP.NET MVC 4 apps. Creating the project We will start with creating a new solution in Visual Studio 2012. Start by launching Visual Studio. Click on the FILE menu and then click on New Project…. You may also press Ctrl + Shift +N. Homebrew and You [ 34 ] Visual Studio will then prompt you with a dialog box asking you for the type of solution you want to create. We will be creating a new ASP.NET MVC 4 Web application. Select the ASP.NET MVC 4 Web Application icon and provide a name and location for the new project in the Name and Location text boxes respectively. In this book, we will be referencing the BrewHow project in the Packt directory located on the C:, but you may name it anything you like and put it wherever you want to. When you have decided on a name and location, click on OK. Visual Studio will now prompt you to choose your project template. Choosing our template Visual Studio 2012 ships with six ASP.NET MVC 4 project templates. Chapter 2 [ 35 ] The Empty template The Empty template isn't as empty as you might think. The project template is not empty, instead it contains the minimal content required to make it an MVC project. There are no scripts or content and the Models, Controllers, and App_Data folders are empty. The Basic template The Basic template is essentially the new version of the MVC 3 Empty template. This template adds the Content and Scripts folder to the Empty template and includes additional assembly references that are required for some of the new features of MVC 4. The Internet Application template This template will be the template from which most sites will be created. This template includes everything present in the Basic template but adds an Account and Home controller to the structure to enable authentication against the traditional ASP.NET SQL Server Membership structure and, new to MVC 4, third-party authentication providers such as Microsoft, Google, and Facebook through the DotNetOpenAuth library. The Intranet Application template The Intranet Application template is a variation of the Internet Application template. It has been altered to support Windows authentication as the authentication mechanism. The Mobile Application template If you are sure that almost all of your traffic will be from mobile devices, you will want to create your application from the Mobile Application template. This template adds support for jQuery Mobile to the Internet Application but removes the DotNetOpenAuth library support in favor of traditional forms authentication. The Web API template New to ASP.NET MVC 4 is the Web API. The Web API provides an easy way to develop RESTful HTTP services and APIs that understand XML and JSON content types. This project template provides the base for constructing new services utilizing the Web API. Homebrew and You [ 36 ] We will create our sample application from the Internet template. We do this for a couple of reasons. First, most of the applications that we implement and support on a day-to-day basis require us to target both desktop browsers as well as mobile browsers. Second, by developing from the Internet template, we can learn more about what is necessary to support the mobile web from the perspective of ASP.NET MVC 4 as well as a general application development perspective. Select Internet Application from the template options and click on the button labeled OK. Congratulations! You have just created your first ASP.NET MVC 4 project. Chapter 2 [ 37 ] Project changes in MVC 4 In addition to new framework features, ASP.NET MVC 4 projects have also undergone some important changes that you should note if you have worked with ASP.NET MVC in the past. NuGet If you are unfamiliar with NuGet, NuGet is a .NET platform package management system. Its goal is to simplify the management of third-party libraries, tools, and scripts within .NET projects. It is now a first-class member of Visual Studio 2012 and the MVC project templates. If you examine the project we just created, you will notice there is a packages.config file at the bottom of the solution. This file is a NuGet package list and contains a list of all the external dependencies to the project. For the Internet Application template, the file includes references to DotNetOpenAuth, Entity Framework, jQuery, knockoutjs, non-core Microsoft libraries, Modernizr, Netwonsoft's JSON library, and WebGrease. Homebrew and You [ 38 ] Global.asax In prior versions of MVC, all of the application bootstrap code was located in the Global.asax code-behind. New in MVC 4, you will notice that the class within the Global.asax file contains only a single method named Application_Start. Have a look at the following piece of code: protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } This method invokes several other classes with which you may be unfamiliar. While it is true that some new functionality regarding bundling and the Web API are reflected in the class names, these names also identify the functionality that has been present in prior versions such as area registration and routing. These new classes encapsulate the traditional configuration information you might expect to see here and the classes exist in the project's App_Start folder. This new organization of code provides for better separation of functionality and makes the Global.asax code-behind a lot easier to read and digest. Now that we've seen some of the structural changes that have taken place inside the new MVC 4 project templates, let's examine how the output of the new project templates looks by launching the project from within Visual Studio 2012. Chapter 2 [ 39 ] Launching the BrewHow app To launch the application, simply press Ctrl + F5 to start the app without running the debugger. You will notice that the default theme for MVC applications has been retooled. Not only does the initial application look better, but also it is structured in such a way that it supports responsive design. Homebrew and You [ 40 ] Responsive design Responsive design means an app has been designed to attempt to present itself properly within any browser window and to continually respond to changes in the size of the browser window or in the content that the page, itself, is displaying. Notice how the content of the browser window has reorganized itself to work within a smaller browser window. All of the content is still logically grouped and is available to the user and there is no horizontal scroll bar present indicating that while the content may have collapsed it still will display within the window. This compressed view does allow you to get an idea of how the site will appear on a mobile device, but if you really want to know how it will look, then you should view the app in an emulator. Configuring and launching an emulator It would be pretty useful for us to launch our app from within Visual Studio 2012 and have an emulator, or multiple emulators, open up the landing page. Fortunately for us, Visual Studio 2012 supports the simultaneous launching of multiple browsers when attempting to run or debug an app. Chapter 2 [ 41 ] Choose and use an emulator Hopefully you have installed one of the emulators listed in the first chapter. If not, let me emphasize again that unless you are testing the app on physical hardware (preferred) or on an emulator. It is disservice to users because it's buggy and also to you as it tarnishes your reputation. To configure Visual Studio to launch multiple browsers simultaneously, we first need to add an empty HTML page to our solution. The empty HTML page will add no functionality and exists only to gain us access to the context menu that will allow us to set the default browser/browsers for our app. To add a new HTML page file to the project, right-click on the BrewHow project to bring up the project context menu. From the menu, select Add and then select HTML Page. You will be presented with a dialog box asking you to specify a name for the item. Name the file anything you'd like (the sample project filename is browser.html) and then click on the button labeled OK. Homebrew and You [ 42 ] Right-click on the HTML page you just added to the project and select Browse With… from the context menu. This will bring up the Visual Studio 2012 Browse With dialog box. This dialog box allows us to set the default browser with which we will view our app when launching it from within Visual Studio. Chapter 2 [ 43 ] We are going to use Google Chrome and the Opera Mobile emulator as our default browsers for the BrewHow project. Though we're configuring Opera Mobile to launch, these instructions can be used with any emulator or desktop browser. Since Opera Mobile isn't a browser that's typically registered with Visual Studio, we first need to tell Visual Studio where it can be found. Click on the Add… button on the Browse With dialog box to begin registering the browser. Assuming you have installed the Opera Mobile emulator in the default location, enter the following values into the dialog box to register an emulator for Opera Mobile running on a Samsung Galaxy S II and then click on OK. Field Description Program C:\Program Files (x86)\Opera Mobile Emulator\ OperaMobileEmu.exe Arguments -windowsize 480x800 -ppi 216 -profile-name "Samsung Galaxy S II" Friendly name Opera Mobile You should now see Opera Mobile displayed in the Browse With dialog box. Homebrew and You [ 44 ] Hold down the Ctrl key, click on both Google Chrome and Opera Mobile, click on the button labeled Set as Default and then close the dialog box. If you were successful, you should notice that the text beside the Start Debugging button in Visual Studio now says Multiple Browsers. Chapter 2 [ 45 ] Press Ctrl + F5 to launch the app without debugging and Visual Studio will open the BrewHow app in both Chrome and the Opera Mobile emulator. Homebrew and You [ 46 ] Summary You should now have a good enough understanding of the homebrewing domain to apply it to the sample application. We also learned about the changes that have occurred in Visual Studio 2012's MVC 4 project templates and project structure and have now properly configured your environment to begin developing BrewHow, our mobile homebrew recipe-sharing app. In the next chapter, we will do a detailed examination of the code generated by the template and how that code relates to the MVC design pattern. We will also create our first controller using this knowledge. Introducing ASP.NET MVC 4 ASP.NET MVC 4 is the latest version of Microsoft's Model-View-Controller (MVC) framework for the web. The MVC pattern is not specific to this framework. It was first introduced as a feature of the Smalltalk language in the 1970s and has seen much success in client/server, desktop, mobile, and web development. It is a software design pattern that helps to enforce a separation of concerns between data and the interaction with data. In this chapter, we are going to examine the MVC pattern and how it is implemented within the ASP.NET MVC framework. We will then begin by applying that knowledge to the BrewHow app. At the end of this chapter, our application will be returning sample recipes to any user making a request. The Model-View-Controller pattern Each component of the MVC pattern fills a very specific purpose in separating data within an application from user interaction with the data. The following is a very brief introduction to the components of the MVC design pattern. The controller In the MVC pattern, the controller acts as a delegator. It submits modifications to the model on behalf of some external interaction (typically a user), and retrieves data for a view as the result of a notification or direct request via user interaction. Introducing ASP.NET MVC 4 [ 48 ] The view Views handle the presentation of the data to some external entity. If a view contains logic, that logic is limited to the presentation of the data it received from the controller as the result of an interaction with the model. The model The model is the encapsulation of application-specific data, and the means by which to store, retrieve, and maintain the integrity of that data. The model may or may not mimic the structure in which the actual data is stored or presented. The MVC pattern and ASP.NET MVC 4 The implementation of the MVC pattern in ASP.NET MVC 4 largely follows a convention-over-configuration paradigm. Simply stated, if you put something in the right place and/or name it the right way, it simply works. That is not to say that we cannot configure the framework to ignore or alter these conventions. It is the flexibility and adaptability of ASP.NET MVC 4 along with its adherence to web standards that has driven its rapid adoption. If you have no exposure to ASP.NET or ASP.NET MVC, please note that each of the components of the MVC pattern, as they relate to ASP.NET MVC 4, is often presented in a separate chapter of its own. The following is a very condensed high-level overview of the MVC pattern in ASP.NET MVC 4. Controllers in ASP.NET MVC In ASP.NET MVC 4, controllers respond to HTTP requests and determine the action to take based upon the content of the incoming request. Controllers in ASP.NET MVC 4 are located in a project folder named, appropriately, Controllers. The Internet Application project we selected for BrewHow contains two controllers in the Controllers folder: AccountController and HomeController. Chapter 3 [ 49 ] If you examine the code in the HomeController.cs file, you will notice that the HomeController class extends the Controller class. public class HomeController : Controller { /* Class methods... */ } Downloading the example code You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub. com/support and register to have the files e-mailed directly to you. The Controller class and the ControllerBase class, from which the Controller class derives, contain methods and properties used to process and respond to HTTP requests. Almost all interaction that occurs while retrieving data from a request or returning data in response to a request will be through the methods and properties exposed by the Controller inheritance chain. Introducing ASP.NET MVC 4 [ 50 ] If you have no prior experience with ASP.NET MVC, you might assume that controllers in the project are identified by either placement in the Controllers folder or by extending the Controller class. In actuality, the runtime uses class name to identify controllers in the default MVC framework configuration; controllers must have a Controller suffix. For example, there might be a controller for recipes, and the class representing this controller would be named RecipeController. As we discussed briefly, every part of the ASP.NET MVC framework is extensible and configurable. You are free to provide some other convention to the framework that it can use to identify controllers. Creating the Recipe controller Let's create a new controller to return recipes to our users. In the Solution Explorer, right-click on the Controllers folder in the BrewHow project, select Add, and then select the Controller menu item. You may also press Ctrl + M, Ctrl + C. In the Add Controller dialog, name the controller RecipeController, select the Empty MVC controller template from the Template drop-down menu, and then click on the Add button. Chapter 3 [ 51 ] Congratulations! You have created your first controller in the BrewHow application. The code should look similar to the following: public class RecipeController : Controller { public ActionResult Index() { return View(); } } Notice that this code is very similar to the code in HomeController. The RecipeController inherits the Controller class and, like HomeController, contains an Index method that returns ActionResult. The class is also properly named with a Controller suffix, so the runtime will be able to identify it as a controller. I'm sure you're ready to examine the output of this controller, but before we can do that we need to understand a little about how the controller is invoked in the first place. Introducing ASP.NET MVC 4 [ 52 ] Introduction to routing At application startup, a series of formatted strings (similar to formatted strings you would use in String.Format) along with name, default values, constraints, and/or types are registered with the runtime. This combination of name, formatted string, values, constraints, and types is termed a route. The runtime uses routes to determine which controller and action should be invoked to handle a request. In our BrewHow project, routes are defined and registered with the runtime in the RouteConfig.cs file in the App_Start folder. The default route for our app is registered with the runtime as shown below. routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }); The formatted string for our default route looks very similar to a URL you might type within the browser. The only notable difference is that each segment of the URL—the portion of the URL between the slashes (/)—is surrounded with curly braces ({}). Our default route contains segments to identify a controller, an action (method), and an optional ID. When our app receives a request, the runtime looks at the URL requested and attempts to map it to any formatted string that has been registered via the MapRoute method. If the incoming URL contains segments that can be mapped into the segments of the formatted string URL, the runtime determines that a match has been found. Two segments, controller and action, have special meaning, and determine the controller to be instantiated and method (action) to be invoked on the controller. The other segments may be mapped to parameters on the method itself. All segments are placed in a route dictionary using the name of the segment within the curly braces as the key, and the mapped portion of the URL as the value. Chapter 3 [ 53 ] To help clarify that with an example, assume a request is made to our app for the URL /do/something. The runtime would consult the route table, which is the collection of all routes registered by the application, and find a match on our Default route. It would then begin to map the segments of the URL request to the formatted string URL. The value do would be placed in the route dictionary under the key controller and the value of something would be under the key action. The runtime would then attempt to invoke the Something method of the DoController, appending the Controller suffix to the controller name. If you examine our Default route a little further, you will see the words within the curly braces correspond to the names of values passed via the defaults parameter of MapRoute. This is, in fact, what makes this a default route. If no controller has been identified by a route, then the runtime will use HomeController. If it can find no action, the Index method on the identified controller will be used. The welcome page we viewed in Chapter 2, Homebrew and You, was invoked because the requested URL of / (slash) mapped to our Default route, and hence, invoked the Index method of HomeController. Routing is a very complex topic. Incoming routes can be ignored, may contain specific values or constraints as part of their mapping, and may include optional parameters. And never forget, the order in which routes are registered is important, very important. Routing is so complex that entire tools have been built around debugging routing issues. This introduction covers only the information needed to understand the content of this book until we get to Chapter 7, Separating Functionality Using Routes and Areas. Action methods An action method (action for short) is a special method in an ASP.NET MVC controller that does the heavy lifting. The code within action methods handles business decisions based upon the data passed to it, interacts with the model on behalf of the request, and tells the runtime which view should be processed in the response to the client. In the initial request to our application, we identified that the HomeController class was being invoked and instructed to execute the Index action when we examined how routing worked. Introducing ASP.NET MVC 4 [ 54 ] For our Recipe controller, this method is pretty straightforward. public ActionResult Index() { return View(); } There is no model interaction and no business decision to be made within our action method. All that the action does is use the View method of the base Controller class to return the default view. The View method is one of several methods in the base Controller class that return an ActionResult. ActionResults An ActionResult is a special return type used by action methods. ActionResult allows you to render a view to the response, redirect the requestor to another resource (a controller, view, image, and others), translate data into JSON for AJAX method calls, and pretty much anything else you can imagine. The base Controller class provides methods that return most of the ActionResult derived classes you need, so you should rarely need to instantiate a class derived from ActionResult. The following table illustrates the helper methods within the base Controller class that return an ActionResult: Controller ActionResult Helper Returns Use Content ContentResult Returns content in response to a request on a controller File FileContentResult FileStreamResult FilePathResult Returns the contents of a file in response to a request on a controller JavaScript JavaScriptResult Returns JavaScript in response to a request on a controller Json JsonResult Returns the JSON representation of an object, typically a model or view model, in response to a request on a controller Chapter 3 [ 55 ] Controller ActionResult Helper Returns Use PartialView PartialViewResult Returns a rendered partial view result in response to a request on a controller Redirect RedirectResponse Instructs the requestor to retrieve the requested resource from another location RedirectPermanent RedirectResponse Instructs the requestor to retrieve the requested resource from another location, and that the resource has been permanently moved RedirectToAction RedirectToRouteResult Behaves the same as RedirectResponse but uses the route table to create the redirect location returned to the requestor RedirectToActionPermanent RedirectToRouteResult This is identical to RedirectToAction, but informs the requestor that the resource has been moved permanently RedirectToRoute RedirectToRouteResult Takes route parameters, values that map to URL segments in the route table, to construct a redirect URL to return to the requestor Introducing ASP.NET MVC 4 [ 56 ] Controller ActionResult Helper Returns Use RedirectToRoutePermanent RedirectToRouteResult Behaves the same as RedirectToRoute but informs the requestor that the resource has been moved permanently View ViewResult Returns a rendered view result in response to a request on a controller Invoking the Recipe controller Applying what we've learned about routing, accessing /Recipe should invoke the Index action method of our new RecipeController using the Default route. Launch the app in the browser, append /Recipe to the URL, and press Enter. This is probably not the result you were expecting. The error exists because there is no view available for the Index action of RecipeController. Chapter 3 [ 57 ] Views in ASP.NET MVC In ASP.NET MVC and the MVC pattern in general, the view handles the presentation of the data as the result of a request sent to a controller. By default, views are stored in the Views folder. Within the Views folder of the project there are folders corresponding to each controller. Note that in the Home folder there are views corresponding to each action method in the HomeController class. This is by design, and is one of the other ASP.NET MVC's convention-over-configuration features. Whenever the runtime is looking for the view to correlate back to an action, it will first look for a view whose name matches the action being invoked. It will try and locate that view in a folder whose name matches the controller being invoked. For our initial request of /Home/Index, the runtime will look for the view Views/Home/ Index.cshtml. There is a pretty substantial search order that the runtime goes through to determine the default view. You can see that search order if you examine the error screen presented when trying to invoke the RecipeController without first creating the view for the action. Razor Razor is the default View Engine, part of the runtime that parses, processes, and executes any code within a view, in ASP.NET MVC 4. The Razor View Engine has a very terse syntax designed to limit keystrokes and increase readability of your views. Introducing ASP.NET MVC 4 [ 58 ] Note that I said syntax and not language. Razor is intended to be easily incorporated into your existing skill set and allow you to focus on the current task. All you really need to know to use Razor successfully is the location of the @ character on your keyboard. The .cshtml is an extension that identifies a view as a Razor View Engine view written in C#. If the language in which the view is written is Visual Basic, the extension will be .vbhtml. If you elect to use the Web Form View Engine, your views will have a .aspx extension associated with them, but you will be unable to follow along with the samples in this book. All of the views used by the BrewHow app are parsed and processed by the Razor View Engine. The @ character The @ character is the key to understanding the Razor syntax. It is the symbol used to denote blocks of code, comments, expressions, and inline code. More precisely, the @ character instructs the View Engine to begin treating the content of a view as code that must be parsed, processed, and executed. Code blocks If you want to place a block of code within a Razor view, simply prefix the block of code using @. @{ string foo = "bar"; } Code blocks are the portions of code between the curly braces ({}). Expressions Expressions are portions of code whose evaluation results in a value being returned. Expressions can be a method invocation. @foo.Bar() They can also be used to retrieve the value of a property. @user.FirstName. Chapter 3 [ 59 ] Expressions can be embedded directly into the output HTML.

Hello, @user.FirstName

By default, the result of any Razor expression evaluation is HTML encoded. This means that any special characters having meaning to the client are escaped as part of the output processing. This functionality also serves as a security mechanism, preventing accidental (or malicious) additions of executable code being sent to a requestor. If you need to expose the raw value of a property or method, you may do so using the Raw HTML helper extension method. @Html.Raw(beVeryCarefulDoingThis) HTML encoding helps prevent Cross-Site Scripting (XSS) attacks by instructing the browser to render the output as data. It is critical that you encode any and all data you return to the client. There are several other attacks possible on websites, which are well beyond the scope of this book, and I urge you to develop defensive coding practices and become knowledgeable about the potential threats your application may face. Inline code As mentioned earlier, the Razor View Engine is smart enough to infer when an actionable piece of code has terminated and processing should stop. This is exceptionally handy when placing inline code in your views. @if (userIsAuthenticated) { Hello, @username } else { Please login } If the content you want to display to the user within inline code has no wrapping tag such as span or div, you can wrap the content in tags. @if (jobIsDone) { profit! } Introducing ASP.NET MVC 4 [ 60 ] Note that merely mentioning the placement of code directly within your view may result in discussions similar to those about the location of your opening curly brace. If you are a practicing member of the Church of Inline Code it may be best that you follow a "Don't Ask, Don't Tell" policy. Comments If you are wise and comment your code, Razor supports it. @* Your comment goes here. *@ Comments, like anything else, need to be maintained. If you modify your code, modify your comments. There are several other things that can be done with Razor such as creating delegates, but we will address them as we encounter them in our application. Shared views When we examined the views of HomeController, we learned that the views for a controller are placed in a folder that shares the same name. Views are only readily available to the controller owning that folder. If we want to make a view easily accessible to more than one controller, we need to mark that view as shared by placing the view in the Shared folder underneath the Views folder. Chapter 3 [ 61 ] If the runtime cannot find the appropriate view in the executing controller's view folder, the next place it will look is the Shared folder. Our current app has three views located in the Shared folder. _LoginPartial.cshtml is a partial view that contains our login control. This control is embedded in several of our views and displays the login form for users who are unauthenticated. Its consumption by several of the views merits it a position in the Shared folder. The view Error.cshtml is the global error page. It is returned by action methods when something unforeseen has happened. Since any action can return this view, it has been placed in the Shared folder. The third view, _Layout.cshtml, is a special type of shared view known as a layout. Layouts A layout is a template for the content of your view. Layouts typically contain scripts, navigation, headers, footers, or other elements you deem necessary on more than one page of your site. If you have worked with ASP.NET in the past, you are likely familiar with master pages. A layout is the master page of the ASP.NET MVC world. You can specify the layout for a page using the Layout property of the view. @{ Layout = "~/Views/Shared/_Layout.cshtml" } When a view is loaded, the layout is executed and the content of the view is placed where the call to @RenderBody() is. The _ViewStart file If you have several views using the same layout, specifying the layout in each and every view may get a little repetitive. To keep things DRY (Don't Repeat Yourself), you can specify the default layout for all views of the site in _ViewStart.cshtml. _ViewStart.cshtml is located at the root of the Views folder. It is used to store code common to all views within the app, not just to specify the layout. When each view is loaded, _ViewStart.cshtml is invoked. It acts like a base class for the views and any code within it becomes part of the constructor for every view in the site. Introducing ASP.NET MVC 4 [ 62 ] You will note that both _LoginPartial.cshtml and _Layout.cshtml start with an underscore. The underscore is another convention indicating that the views are not to be requested directly. Partial views Partial views allow you to design portions of your view as reusable components. These are very similar to controls in ASP.NET Web Forms development. Partial views may be returned directly from a controller using the PartialView method, or directly returning a PartialReviewResult return type. They may also be embedded directly into a view using the RenderPartial, Partial, RenderAction, or Action HTML helper methods. HTML helpers Much of the code you will see in our views has methods prefixed with Html. These methods are HtmlHelper extension methods (HTML helpers for short) intended to provide you a quick way to perform some action or embed some information into the output of your view. Typically, these methods have a return type of string. HTML helpers assist in standardizing the rendering of content presented in views such as forms or links. Html.RenderPartial and Html.Partial The RenderPartial HTML helper processes the partial view and writes the result directly to the response stream. The result is as if the code of the partial view were placed directly into the calling view. @Html.RenderPartial("_MyPartialView", someData) The Partial HTML helper does the same processing of the view as the RenderPartial helper, but the output of the processing is returned as a string. The _LoginPartial.cshtml in our project is rendered within the _Layout.cshtml layout using the Partial HTML helper. @Html.Partial("_LoginPartial") If you are returning a large amount of data in a partial view, RenderPartial will be slightly more efficient than Partial due to its direct interaction with the response stream. Chapter 3 [ 63 ] Html.RenderAction and Html.Action The RenderAction HTML helper differs from RenderPartial, in that it actually invokes a controller's action method and embeds that content within the view. This functionality is extremely useful as it provides a way to execute business logic or other code specific to a view in the controller responsible for returning the view to the requestor. Let's say we decided we wanted to show a tag cloud of the most viewed styles of beer on our BrewHow site on every page. You have two options: you could make every action of the site retrieve from the database or cache the current values to display in the tag, or you could have a controller action solely responsible for retrieving the values for the tag cloud and invoke that action in every view using the RenderAction or Action method. The differences between RenderAction and Action are the same as those between RenderPartial and Partial. RenderAction will write the output of the processing directly to the response stream. Action will return the output of the processing as a string. Display templates Display templates are type-specific partial views. They exist in a folder named DisplayTemplates. This folder may exist inside a controller's View folder if the display template is specific to a controller, or it may exist under the Shared folder if it is to be used by the entire application. Each of the display templates must be named for its type. A display template for a Beer class that could be used everywhere in the application would be named Beer.cshtml and placed in ~/Shared/Views/DisplayTemplates. Introducing ASP.NET MVC 4 [ 64 ] We can also create display templates for base types like strings or integers. Display templates may be added to a view using either Display, DisplayFor, or DisplayForModel HTML helper methods. Html.Display The Display HTML helper takes a single string parameter. The string represents the property name of the current model or a value in the ViewData dictionary to be rendered. Assume that the model passed to our view is defined as follows: public class Recipe { public string RecipeName { get; set; } /* Other properties here… */ } If we want to invoke a display template for the RecipeName property, we put the following code into our view: @Html.Display("RecipeName") The runtime will try and locate a display template for the string type and use any identified template to render the RecipeName property. Html.DisplayFor DisplayFor is the expression-based version of Display. It takes as its argument the current model for the view and processes the display template for the specified property on the model. @Html.DisplayFor(model => model.RecipeName) We will examine how the view knows the model type when we populate our views later in this chapter. Html.DisplayForModel If we want to invoke the display template chain for an entire model, we simply use the DisplayForModel helper method. @Html.DisplayForModel() Chapter 3 [ 65 ] Editor templates Editor templates are the read/write version of display templates. Their implementation and usage are identical to display templates. Editor templates are stored in a folder named EditorTemplates. This folder may exist in the same location as the DisplayTemplates folder. Editor templates, like display templates, are invoked using one of three HTML helper methods: Editor, EditorFor, or EditorForModel. We will utilize display and editor templates as we refine our BrewHow app. Creating our Recipe view Having taken the long way around, we can get back to the task at hand. We now know we need to create a view in the ~/Views/Recipe folder named Index.cshtml if we want the /Recipe URL to succeed. We could manually create the folder structure in the solution (the Recipe folder does not currently exist), and then create a new partial view, but why not allow Visual Studio to do the heavy lifting for us. Open the RecipeController.cs file in Solution Explorer and right-click anywhere within the Index action method. You will see a menu item labeled Add View…. Introducing ASP.NET MVC 4 [ 66 ] Clicking on Add View… or pressing Ctrl + M, Ctrl + V will display the Add View dialog. Accept the default values by simply clicking on the Add button. If you return to Solution Explorer, you will now see the view directory structure and the Index.cshtml view for RecipeController. Chapter 3 [ 67 ] Launch the app by pressing Ctrl + F5 and append /Recipe to the URL in the browser's address bar as before. You should now see a page very similar to the following screenshot: Making Recipe default We should set the /Recipe controller's Index action to be the default action for the app, given our app is all about sharing recipes. Open the RouteConfig.cs file in the App_Start folder and modify the values for the defaults parameter to default to the RecipeController. Remember that the runtime will append Controller to the controller name when looking for the class to handle a request. routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Recipe", action = "Index", id = UrlParameter.Optional }); Introducing ASP.NET MVC 4 [ 68 ] Press Ctrl + F5 to build and launch the app. Our RecipeController's Index action and view now handle presenting the default landing page to the user. The only thing left is to modify our layout so users are redirected to /Recipe/Index instead of /Home/Index when clicking on the Home navigation link or the logo text itself.

@Html.ActionLink("your logo here", "Index", "Recipe")

  • @Html.ActionLink("Home", "Index", "Recipe")
  • Chapter 3 [ 69 ] Returning a model to the view We have successfully processed the view and returned it to the client. Now we need to return some data from RecipeController's Index action. This data represents the model portion of the MVC pattern, and ASP.NET MVC supports several ways to return to the view any data gathered by the controller. Using ViewData The ViewData property of the ControllerBase class (the parent of the Controller class) is a "magic strings" mechanism for passing data from a controller to a view. It is more or less a dictionary. Almost all interaction with it occurs through a key/value syntax courtesy of its IDictionary interface implementation. ViewData["MyMagicProperty"] = "Magic String Win!" Any value put into the ViewData dictionary is retrievable in the view using the ViewData property of the WebViewPage base class. @ViewData["MyMagicProperty"] All other methods of sending a model to a view from within the Controller and ControllerBase classes are wrappers and abstractions of the ViewData dictionary. While you may (or may not) view magic strings as an appropriate mechanism for data exchange, all other methods of returning data to a view leverage ViewData internally. Using ViewBag ViewBag is a wrapper around the ViewData dictionary enabling support for dynamic properties and types on the ViewData dictionary. If we examine the HomeController class's Index action, we'll see it's using the ViewBag property to send a message back to the view. public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } Introducing ASP.NET MVC 4 [ 70 ] Message is not a declared member of the ViewBag property. The ViewBag property's support for dynamic typing, also referred to as duck typing, allows assignment of values to properties not declared on the object. The mere act of assigning values to these properties adds them to the object. The ViewBag data can be accessed from within the view using the ViewBag property of the WebViewPage base class. The Index view for HomeController has the following code:

    @ViewBag.Title.

    @ViewBag.Message

    This is displayed to the user as part of the content of the page. Any use of ViewBag should be well documented. Due to their dynamic nature, the compiler has no way to validate references to dynamic types. Attempts to access properties or methods that do not exist, or that are defined with different types or arguments will not be caught at compile time. Instead, these errors will be captured at runtime and will cause your app to crash. Chapter 3 [ 71 ] Using TempData If you need to persist data for the view between redirects or sequential requests, then you may want to consider using TempData. TempData is another wrapper around the ViewData dictionary, but data placed in TempData is intentionally short-lived; anything stored in TempData will persist for exactly two requests: the current request and the next subsequent request for the same user. Placing data in the TempData dictionary should be done sparingly as the implementation can result in unexpected behavior. Assume that a user of our app has two tabs open to compare two recipes. A request originates from one of the tabs inserting data into TempData for consumption. A second request to the app is then triggered from the another open tab. The second request will force the values put in TempData by the first request to expire whether or not the intended recipient has retrieved and operated on the values. The TempData dictionary is accessible through the TempData properties of ControllerBase and WebViewPage. TempData["UserNotification"] = "Hope you get this message." @TempData["UserNotification"] The three methods presented thus far provide means to submit loosely coupled data to a view from a controller. While you certainly could send a full model to the view through these mechanisms, the framework provides a strongly typed method for moving data between the controller and view. Strongly typed models If you want to pass a strongly typed model from a controller to a view, you can do this in one of two ways. You can do this directly by setting the value of the Model property on the ViewData dictionary (OK, so it's a little more than a dictionary), or you can pass the model to the view through one of the ActionResult methods on the Controller class. Setting the property directly can be done as follows: ViewData.Model = myModel; You will likely not set the value directly very often, but will instead use one of the ActionResult methods. return View(myModel); Introducing ASP.NET MVC 4 [ 72 ] This is much more concise and if you examine the code in the Controller class you will see it's actually setting ViewData.Model on your behalf. protected internal virtual ViewResult View (string viewName, string masterName, object model) { if (model != null) { ViewData.Model = model; } /* Other code removed */ } Take the initiative The code above is taken directly from the RTM version of ASP.NET MVC 4. Microsoft's entire web stack is available under an open source license at aspnetwebstack.microsoft.com. You are urged to take the time and explore the code to learn what is actually being done by the framework. For the view to operate on this model in a strongly typed fashion, it must be informed of the type of model to expect. In Razor views, this is done with the @model keyword. @model BrewHow.Web.Model.MyModel Returning a Recipe list Let's put into practice everything we've learned. When a user of our app lands on the recipe page, we will present them with a list of recipes. Chapter 3 [ 73 ] Creating the model We need to define a model to represent a recipe within our app. For now, that model will contain four properties: name, style, original gravity, and final gravity. The gravity of a liquid is a measurement of its density compared to water, with water having a gravity of 1.0. Measuring the gravity of beer is done to determine how much sugar exists as a percentage of the liquid. Two measurements are taken when brewing beer. The original gravity is taken to measure the amount of sugar in the wort before yeast is added. The final gravity is taken to measure the gravity of the liquid at the end of fermentation. The difference between the two measurements can be used to determine how much of the sugar within the unfermented wort was converted into alcohol during fermentation. The formula for determining the amount of alcohol by volume is 132.715*(original gravity - final gravity). In Solution Explorer, right-click on the Models folder, select Add, and then click on Class…. Introducing ASP.NET MVC 4 [ 74 ] Select Class as the type of item to add in the Add New Item dialog if it is not already selected. Name the class Recipe, and click on Add to create the class. Open the new Recipe.cs file, and replace the Recipe class definition with the following: public class Recipe { public string Name { get; set; } public string Style { get; set; } public float OriginalGravity { get; set; } public float FinalGravity { get; set; } } Save and close the file. Chapter 3 [ 75 ] Returning the model Open the RecipeController class, and replace the Index action with the following code: public ActionResult Index() { var recipeListModel = new List { new Recipe { Name = "Sweaty Brown Ale", Style = "Brown Ale", OriginalGravity = 1.05f, FinalGravity = 1.01f }, new Recipe { Name = "Festive Milk Stout", Style="Sweet/Milk Stout", OriginalGravity = 1.058f, FinalGravity = 1.015f }, new Recipe { Name = "Andy's Heffy", Style = "Heffeweisen", OriginalGravity = 1.045f, FinalGravity = 1.012f } } return View(recipeListModel); } The new Index action is pretty straightforward. The new code creates a populated list and assigns it to the recipeListModel variable. The populated list is sent to the Index view as a strongly typed model through the View method (remember, the view has the same name as the action unless otherwise specified). return View(recipeListModel); For the code to compile, you will need to add a using statement to the top of the file to reference the new Recipe model defined in BrewHow.Models. using BrewHow.Models; Introducing ASP.NET MVC 4 [ 76 ] Displaying the model The final step is to inform the view of the incoming model and provide the view the means to display the model. Open up the Index.cshtml view in the ~/Views/Recipe folder and add the following line at the top of the view. @model IEnumerable This declares the model we are passing to the view is an enumeration of recipes. It is now strongly typed. Place your cursor at the bottom of the Index.cshtml view and paste the following code. You won't be judged for flinching at the use of tables even though they are being used appropriately to display tabular data. We are just trying to get the model to display right now. @foreach (var item in Model) { Chapter 3 [ 77 ] }
    @Html.DisplayNameFor(model => model.Name) @Html.DisplayNameFor(model => model.Style) @Html.DisplayNameFor(model => model.OriginalGravity) @Html.DisplayNameFor(model => model.FinalGravity)
    @Html.DisplayFor(modelItem => item.Name) @Html.DisplayFor(modelItem => item.Style) @Html.DisplayFor(modelItem => item.OriginalGravity) @Html.DisplayFor(modelItem => item.FinalGravity)
    The markup you pasted into the view lays out a table to list each entry in the model collection passed to the view. Do take note of how little the Razor syntax interferes with the markup of the view. The first row of the table contains the headers for the recipe list. During the processing of the view within the foreach loop, the view engine iterates over each item in the collection passed to it and outputs a row for the table using the display template for the type. Since we have not defined display templates, the values of the properties will simply be output as strings. You have successfully created a model, populated the model in the controller, passed the populated model from the controller to the view, and displayed the populated model to the user. Press Ctrl + F5 on the keyboard to start the app and admire your work. Introducing ASP.NET MVC 4 [ 78 ] Summary Congratulations! This chapter was a whirlwind of information, but we now have a basic understanding of the MVC pattern and how it relates to ASP.NET MVC 4. We learned about controllers and action methods and how to create them. We created a model, passed the model from the controller to the view, and wrote code that displayed that model. With the basics known, it's time for us to look at bigger and better things. In the next chapter, we leverage the functionality of Entity Framework 5.0 to create a persistence layer for our application and return the information stored in the database. This persistence layer will be used as the basis for our models moving forward. Modeling BrewHow in EF5 If you're developing a new application, Microsoft would very much like you to use Entity Framework 5.0 (EF5). Entity Framework is Microsoft's officially supported Object-Relational Mapping (ORM) tool, finally coming on its own after a much maligned introduction with .NET 3.5 SP1. As with any ORM, Entity Framework is designed to separate the domain model of an application from the actual storage mechanism. This allows the developer to focus on the actual problem they're trying to solve and spend less time worrying about the tables and columns underneath the model. Having a framework provide the underlying storage mechanism does have its own set of issues. As almost any DBA will tell you, ORMs will often generate substandard storage models and Entity Framework is not excluded from this issue. However, Entity Framework allows you to customize the translation between the domain and database to match almost any conceivable underlying data store, allowing you and your DBA to work in relative harmony. In this chapter, we will create the persistence layer for the BrewHow app using Entity Framework 5. We will explore migrations and how we can use them to apply and remove changes to the database. Additionally, we will look at some of the conventions and configurations used by Entity Framework 5.0 to tailor our model to a database mapping we or our DBA prefer. Modeling BrewHow in EF5 [ 80 ] What's new in Entity Framework 5.0? Version 5.0 of the Entity Framework is a fairly major update to Microsoft's ORM. While there are several improvements and additions, we will only briefly examine the improvements as they relate to the use of EF5 in the development of our BrewHow app. Performance enhancements Under the hood, Microsoft has squeezed every ounce of performance it can out of the framework. One of the key performance enhancements is the automatic use of compiled queries—a query in which the LINQ to Entities expression tree has been translated into pure SQL. To accomplish this, upon first invocation the EF5, the framework configures all of the components the query needs, caches certain components of the query, and stores them locally in the memory so that any subsequent invocations do not need to be translated or have resources loaded. This greatly increases performance of a warmed-up application. LocalDB support LocalDB is now supported within the EF5 Code First development model. In fact, it is the default server used within Visual Studio 2012. If you are unfamiliar with LocalDB, it is a new version of SQL Server targeted at developers. It is intended to fit between SQL Server Express and SQL Server Compact. You may be asking yourself, "Isn't that what SQL Server Express is for?" Although Microsoft's original intention was to have SQL Server Express as the database standard for developers, as the SQL Server line improved it became harder to maintain the low-overhead, small-footprint requirements of developers because of the requirements forced on SQL Server Express by its fully licensed siblings. To rectify this, Microsoft created LocalDB, a repackage of the same SQL Server executable as Express and other versions of SQL Server but without the large footprint and configuration of the SQL Server line. The repackage allows us as developers to maintain SQL Server compatibility in our development without having to install and configure SQL Server Express or one of the enterprise variants. LocalDB differs from SQL Server Compact, in that it is a separate process (SQL Server Compact is an in-proc DLL) and provides support for stored procedures and extended data-types where SQL Server Compact does not. Chapter 4 [ 81 ] Enumeration support EF5 has finally received support for enumerations, a feature that has been requested since the earliest versions of Entity Framework. Framework support for enumerations is provided by mapping enumeration values to and from an integer value in the database. If you require a lookup table, want to add or alter values without recompiling, or are the type of person that doesn't want magic integers in their database, you will still need to use classes mapped to a lookup table to represent enumerated values. There is one important caveat around enumeration support; it is only available if you are targeting version 4.5 of the .NET Framework. If you are targeting Version 4.0, you will receive an error message about the framework being unable to map the enumeration property. If, however, you are targeting Version 4.5 or higher of the .NET Framework, enumerations are one of those nice little "it just works" features we as developers love. The BrewHow model The Entity Framework supports three distinct ways to model our data: Database First, Model First, and Code First. • Database First is used when the database already exists and provides support to derive a model from the existing database schema • The Model First approach provides support to visually model our data and, from the model, generate the database • Code First allows us to generate our database schema from a model we define in code Since we are developing a new app, the Database First method of modeling our data doesn't really apply. The Model First approach, introduced in Visual Studio 2010, could be used for the BrewHow app, but we will instead opt for the more agile approach of Code First. The Code First approach will also allow us to update the schema in a (largely) non-destructive manner using migrations. This is important since we will adjust the model to better map our domain as we continually enhance our app. Additionally, it's just cool and we like new shiny toys, right? So let's get EF5 enabled and start using it in our app. Modeling BrewHow in EF5 [ 82 ] Modeling data Using the Code First feature of EF5, classes will dictate the database schema used to model our domain. We will start with three classes: Recipe, Review, and Style. Each of these classes will be added to the Models folder of our BrewHow app. Recipe The Recipe class contains all of the information about our recipe. This is a slightly modified version of the class presented in the previous chapter. public class Recipe { public int RecipeId { get; set; } public string Name { get; set; } public Style Style { get; set; } public float OriginalGravity { get; set; } public float FinalGravity { get; set; } public string GrainBill { get; set; } public string Instructions { get; set; } } Review The Review class contains information related to the review of a recipe. public class Review { public int ReviewId { get; set; } public int Rating { get; set; } public string Comment { get; set; } } Style The Style class will allow us to associate a style to a particular beer recipe. Examples of beer styles are India Pale Ale, Milk/Sweet Stout, Pilsner, and Porter. public class Style { public int StyleId { get; set; } public Category Category { get; set; } public string Name { get; set; } } Chapter 4 [ 83 ] Category The Category class is an enumeration that will be used to define a beer as ale or lager. We use an enumeration because these values are not going to change. public enum Category { Ale, Lager } The BrewHow context We now have the classes that represent our model. We need a way to map these classes to a persistent store. To do this, we will create a class named BrewHowContext that extends the DbContext class. DbContext is a combination of repository and unit-of-work patterns. It provides the glue to map the Code First model to the database. It also provides change tracking, allowing you to make several edits to an entity or several entities in a context, committing them to the database in bulk. DbContext isn't magic, however. It needs to have some idea of the entities that exist for a model, the entities for which it's responsible. DbContext uses a special collection class to map entities to tables within the database. This class is DbSet. The DbSet class is a special class within the Entity Framework used to represent a set of typed objects upon which you can perform CRUD (Create, Retrieve, Update, and Delete) operations. These operations may be performed using LINQ as DbSet implements the IQueryable interface. Create BrewHowContext in the Models folder of our app. You will need to add System.Data.EntityFramework to the using statements in BrewHowContext.cs. public class BrewHowContext : DbContext { public DbSet Recipes { get; set; } public DbSet Reviews { get; set; } public DbSet