+ All Categories
Home > Documents > Getting Started With Mvc 5

Getting Started With Mvc 5

Date post: 07-Jul-2018
Category:
Upload: henry-garcia-ospina
View: 218 times
Download: 0 times
Share this document with a friend
115
Getting Started with ASP.NET MVC 5 By Rick Anderson|October 17, 2013 This tutorial will teach you the basics of building an ASP.NET MVC 5 Web application using Visual Studio 2013. A Visual Web Developer project with C# source code is availab le to accompany this topic. Downloadthe C# version. See Building the Chapter Downloads  for instructions on building the sample and populating the database. In the tutorial you run the application in Visual Studio. You can also make the application available over the Internet by deploying it to a hosting provider. Microsoft offers free web hosting for up to 10 w eb sites in afree Windows Azure trial account . This tutorial was written by Scott Guthrie (twitter @scottgu ), Scott Hanselman (twitter: @shanselman ), and Rick Anderson ( @RickAndMSFT ) Getting Started Start by installing and running Visual Studio Express 2013 for Web or Visual Studio 2013. Visual Studio is an IDE, or integrated development environment. Just like you use Microsoft Word to write documents, you'll use an IDE to create applications. In Visual Studio there's a toolbar along the top showing various options available to you. There's also a menu that provides another way to perform tasks in the IDE. (For example, instead of selecting New Project from the Start page, you can use the menu and select File > New Project.) 1
Transcript

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 1/115

Getting Started with ASP.NET MVC 5By Rick Anderson |October 17, 2013

This tutorial will teach you the basics of building an ASP.NET MVC 5 Web application using Visual Studio

2013 . A Visual Web Developer project with C# source code is available to accompany thistopic. Download the C# version. See Building the Chapter Downloads for instructions on building thesample and populating the database.In the tutorial you run the application in Visual Studio. You can also make the application available overthe Internet by deploying it to a hosting provider. Microsoft offers free web hosting for up to 10 web sitesin afree Windows Azure trial account . This tutorial was written by Scott Guthrie (twitter @scottgu ), ScottHanselman (twitter: @shanselman ), and Rick Anderson ( @RickAndMSFT )

Getting StartedStart by installing and running Visual Studio Express 2013 for Web or Visual Studio 2013 .

Visual Studio is an IDE, or integrated development environment. Just like you use Microsoft Word to writedocuments, you'll use an IDE to create applications. In Visual Studio there's a toolbar along the topshowing various options available to you. There's also a menu that provides another way to perform tasksin the IDE. (For example, instead of selecting New Project from the Start page, you can use the menu andselect File > New Project .)

1

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 2/115

Creating Your First ApplicationClick New Project , then select Visual C# on the left, then Web and then select ASP.NET WebApplication . Name your project "MvcMovie" and then click OK .

2

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 3/115

In the New ASP.NET Project dialog, click MVC and then click OK .

3

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 4/115

Visual Studio used a default template for the ASP.NET MVC project you just created, so you have aworking application right now without doing anything! This is a simple "Hello World!" project, and it's a

good place to start your application.

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 5/115

Click F5 to start debugging. F5 causes Visual Studio to start IIS Express and run your web app. VisualStudio then launches a browser and opens the application's home page. Notice that the address bar ofthe browser says localhost:port# and not something like example.com . That'sbecause localhost always points to your own local computer, which in this case is running theapplication you just built. When Visual Studio runs a web project, a random port is used for the webserver. In the image below, the port number is 1234. When you run the application, you'll see a differentport number.

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 6/115

Right out of the box this default template gives you Home, Contact and About pages. The image abovedoesn't show the Home , About and Contact links. Depending on the size of your browser window, youmight need to click the navigation icon to see these links.

6

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 7/115

The application also provides support to register and log in. The next step is to change how thisapplication works and learn a little bit about ASP.NET MVC. Close the ASP.NET MVC application and let'schange some code.

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 8/115

Adding a ControllerBy Rick Anderson |October 17, 2013

MVC stands for model-view-controller . MVC is a pattern for developing applications that are well

architected, testable and easy to maintain. MVC-based applications contain: Models: Classes that represent the data of the application and that use validation logic to enforcebusiness rules for that data.

Views: Template files that your application uses to dynamically generate HTML responses. Controllers: Classes that handle incoming browser requests, retrieve model data, and then specify

view templates that return a response to the browser.We'll be covering all these concepts in this tutorial series and show you how to use them to build anapplication.

Let's begin by creating a controller class. In Solution Explorer , right-click the Controllers folder and thenclick Add , then Controller .

8

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 9/115

In the Add Scaffold dialog box, click MVC 5 Controller - Empty , and then click Add .

9

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 10/115

Name your new controller "HelloWorldController" and click Add .

Notice in Solution Explorer that a new file has been created named HelloWorldController.cs and a newfolder Views\HelloWorld . The controller is open in the IDE.

10

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 11/115

Replace the contents of the file with the following code.

using System . Web;using System . Web. Mvc;

11

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 12/115

namespace MvcMovie. Controllers {

public class HelloWorldController : Controller {

//// GET: /HelloWorld/

public string Index (){

return "This is my <b>default</b> action..." ;}

//// GET: /HelloWorld/Welcome/

public string Welcome(){return "This is the Welcome action method..." ;

}}

}

The controller methods will return a string of HTML as an example. The controller isnamed HelloWorldController and the first method is named Index . Let’s invoke it from a browser.Run the application (press F5 or Ctrl+F5). In the browser, append "HelloWorld" to the path in the addressbar. (For example, in the illustration below, it's http://localhost:1234/HelloWorld. ) The page in the browserwill look like the following screenshot. In the method above, the code returned a string directly. You told

the system to just return some HTML, and it did!

12

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 13/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 14/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 15/115

In the sample above, the URL segment ( Parameters ) is not used, the name and numTimes parameters

are passed as query strings . The ? (question mark) in the above URL is a separator, and the query stringsfollow. The & character separates query strings.Replace the Welcome method with the following code:

public string Welcome( string name, int ID = 1){

return HttpUtility . HtmlEncode ( "Hello " + name + ", ID: " + ID);}

Run the application and enter the following URL: http://localhost:xxx/HelloWorld/Welcome/3?name=Rick

This time the third URL segment matched the route parameter ID. The Welcome action method cpntainsa parameter ( ID) that matched the URL specification in the RegisterRoutes method.

public static void RegisterRoutes ( RouteCollection routes)

15

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 16/115

{routes. IgnoreRoute ( "{resource}.axd/{*pathInfo}" );

routes. MapRoute (name: "Default" ,

url: "{controller}/{action}/{id}" ,defaults: new { controller = "Home", action = "Index" , id =

UrlParameter . Optional });

}

In ASP.NET MVC applications, it's more typical to pass in parameters as route data (like we did with IDabove) than passing them as query strings. You could also add a route to pass boththe name and numtimes in parameters as route data in the URL. In the App_Start\RouteConfig.cs file, addthe "Hello" route:

public class RouteConfig {

public static void RegisterRoutes ( RouteCollection routes){

routes. IgnoreRoute ( "{resource}.axd/{*pathInfo}" );

routes. MapRoute(name: "Default" ,url: "{controller}/{action}/{id}" ,defaults: new { controller = "Home", action = "Index" , id =

UrlParameter . Optional });

routes. MapRoute(name: "Hello" ,url: "{controller}/{action}/{name}/{id}"

);}

}

Run the application and browse to /localhost:XXX/HelloWorld/Welcome/Scott/3 .

16

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 17/115

For many MVC applications, the default route works fine. You'll learn later in this tutorial to pass datausing the model binder, and you won't have to modify the default route for that.

In these examples the controller has been doing the "VC" portion of MVC — that is, the view andcontroller work. The controller is returning HTML directly. Ordinarily you don't want controllers returning

HTML directly, since that becomes very cumbersome to code. Instead we'll typically use a separate viewtemplate file to help generate the HTML response. Let's look next at how we can do this.

Adding a ViewBy Rick Anderson |October 17, 2013

In this section you're going to modify the HelloWorldController class to use view template files tocleanly encapsulate the process of generating HTML responses to a client.You'll create a view template file using the Razor view engine . Razor-based view templates havea .cshtml file extension, and provide an elegant way to create HTML output using C#. Razor minimizes thenumber of characters and keystrokes required when writing a view template, and enables a fast, fluidcoding workflow.Currently the Index method returns a string with a message that is hard-coded in the controller class.Change the Index method to return a View object, as shown in the following code:

public ActionResult Index (){

return View();}

The Index method above uses a view template to generate an HTML response to the browser. Controllermethods (also known as action methods ), such as the Index method above, generally returnan ActionResult (or a class derived from ActionResult ), not primitive types like string.

Right click the Views\HelloWorld folder and click Add , then click MVC 5 View Page with (Layout Razor) .

17

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 18/115

In the Specify Name for Item dialog box, enter Index , and then click OK .

18

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 19/115

In the Select a Layout Page dialog, accept the default _Layout.cshtml and click OK .

In the dialog above, the Views\Shared folder is selected in the left pane. If you had a custom layout file inanother folder, you could select it. We'll talk about the layout file later in the tutorial The MvcMovie\Views\HelloWorld\Index.cshtml file is created.

19

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 20/115

Add the following highlighed markup.

@{Layout = "~/Views/Shared/_Layout.cshtml";

}

@{ViewBag.Title = "Index";

}

<h2>Index </h2>

<p>Hello from our View Template! </p>

Right click the Index.cshtml file and select View in Browser .

0

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 21/115

1

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 22/115

You can also right click the Index.cshtml file and select View in Page Inspector. See the Page Inspectortutorial for more information.Alternatively, run the application and browse to the HelloWorld controller(http://localhost:xxxx/HelloWorld ). TheIndex method in your controller didn't do much work; it simply ranthe statement return View() , which specified that the method should use a view template file to render

a response to the browser. Because you didn't explicitly specify the name of the view template file to use,ASP.NET MVC defaulted to using the Index.cshtml view file in the \Views\HelloWorld folder. The imagebelow shows the string "Hello from our View Template!" hard-coded in the view.

Looks pretty good. However, notice that the browser's title bar shows "Index My ASP.NET Appli" and thebig link on the top of the page says "Application name." Depending on how small you make your browserwindow, you might need to click the three bars in the upper right to see the tothe Home , About , Contact , Register and Log in links.

Changing Views and Layout PagesFirst, you want to change the "Application name" link at the top of the page. That text is common to everypage. It's actually implemented in only one place in the project, even though it appears on every page inthe application. Go to the /Views/Shared folder in Solution Explorer and open the _Layout.cshtml file.This file is called a layout page and it's in the shared folder that all other pages use.

2

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 23/115

3

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 24/115

Layout templates allow you to specify the HTML container layout of your site in one place and then applyit across multiple pages in your site. Find the @RenderBody() line. RenderBody is a placeholder where allthe view-specific pages you create show up, "wrapped" in the layout page. For example, if you selectthe About link, the Views\Home\About.cshtml view is rendered inside the RenderBody method.Change the contents of the title element. Change the ActionLink in the layout template from "Application

name" to "MVC Movie" and the controller from Home to Movies . The complete layout file is shown below:<!DOCTYPE html> <html> <head>

<meta charset ="utf-8" /> <meta name="viewport" content ="width=device-width, initial-scale=1.0" > <title> @ViewBag.Title - Movie App </title> @Styles.Render("~/Content/css")@Scripts.Render("~/bundles/modernizr")

</head>

<body> <div class ="navbar navbar-inverse navbar-fixed-top" > <div class ="container" >

<div class ="navbar-header" > <button type ="button" class ="navbar-toggle" data-toggle ="collapse"

data-target =".navbar-collapse" > <span class ="icon-bar" ></span> <span class ="icon-bar" ></span> <span class ="icon-bar" ></span>

</button> @Html.ActionLink("MVC Movie", "Index", "Movies", null, new { @class =

"navbar-brand" })</div> <div class ="navbar-collapse collapse" >

<ul class ="nav navbar-nav" > <li> @Html.ActionLink("Home", "Index", "Home") </li> <li> @Html.ActionLink("About", "About", "Home") </li> <li> @Html.ActionLink("Contact", "Contact", "Home") </li>

</ul> @Html.Partial("_LoginPartial")

</div> </div>

</div> <div class ="container body-content" >

@RenderBody()<hr /> <footer>

<p>&copy; @DateTime.Now.Year - My ASP.NET Application </p> </footer>

</div>

4

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 25/115

@Scripts.Render("~/bundles/jquery")@Scripts.Render("~/bundles/bootstrap")@RenderSection("scripts", required: false)

</body> </html>

Run the application and notice that it now says "MVC Movie ". Click the About link, and you see how thatpage shows "MVC Movie", too. We were able to make the change once in the layout template and haveall pages on the site reflect the new title.

When we first created the Views\HelloWorld\Index.cshtml file, it contained the following code:

5

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 26/115

@{Layout = "~/Views/Shared/_Layout.cshtml";

}

The Razor code above is explicted setting the layout page. Examine the Views\_ViewStart.cshtml file, itcontains the exact same Razor markup. The Views\_ViewStart.cshtml file defines the common layout that allviews will use, therefore you can comment out or remove that code fromthe Views\HelloWorld\Index.cshtml file.

@*@{Layout = "~/Views/Shared/_Layout.cshtml";

}*@

@{ViewBag.Title = "Index";

}

<h2>Index </h2>

<p>Hello from our View Template! </p>

You can use the Layout property to set a different layout view, or set it to null so no layout file will beused.Now, let's change the title of the Index view.

Open MvcMovie\Views\HelloWorld\Index.cshtml . There are two places to make a change: first, the text thatappears in the title of the browser, and then in the secondary header (the <h2> element). You'll makethem slightly different so you can see which bit of code changes which part of the app.

@{

ViewBag.Title = "Movie List";}

<h2>My Movie List </h2>

<p>Hello from our View Template! </p>

To indicate the HTML title to display, the code above sets a Title property of the ViewBag object (whichis in the Index.cshtml view template). Notice that the layout template ( Views\Shared\_Layout.cshtml ) usesthis value in the <title> element as part of the <head> section of the HTML that we modified previously.

<!DOCTYPE html> <html> <head>

<meta charset ="utf-8" /> <meta name="viewport" content ="width=device-width, initial-scale=1.0" > <title> @ViewBag.Title - Movie App </title> @Styles.Render("~/Content/css")@Scripts.Render("~/bundles/modernizr")

</head>

6

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 27/115

Using this ViewBag approach, you can easily pass other parameters between your view template and yourlayout file.Run the application. Notice that the browser title, the primary heading, and the secondary headings havechanged. (If you don't see changes in the browser, you might be viewing cached content. Press Ctrl+F5 inyour browser to force the response from the server to be loaded.) The browser title is created with

the ViewBag.Title we set in the Index.cshtml view template and the additional "- Movie App" added inthe layout file.Also notice how the content in the Index.cshtml view template was merged with the _Layout.cshtml viewtemplate and a single HTML response was sent to the browser. Layout templates make it really easy tomake changes that apply across all of the pages in your application.

Our little bit of "data" (in this case the "Hello from our View Template!" message) is hard-coded, though.The MVC application has a "V" (view) and you've got a "C" (controller), but no "M" (model) yet. Shortly,we'll walk through how create a database and retrieve model data from it.

Passing Data from the Controller to the View

7

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 28/115

Before we go to a database and talk about models, though, let's first talk about passing information fromthe controller to a view. Controller classes are invoked in response to an incoming URL request. Acontroller class is where you write the code that handles the incoming browser requests, retrieves datafrom a database, and ultimately decides what type of response to send back to the browser. Viewtemplates can then be used from a controller to generate and format an HTML response to the browser.

Controllers are responsible for providing whatever data or objects are required in order for a viewtemplate to render a response to the browser. A best practice: A view template should never performbusiness logic or interact with a database directly . Instead, a view template should work only with thedata that's provided to it by the controller. Maintaining this "separation of concerns" helps keep yourcode clean, testable and more maintainable.Currently, the Welcome action method in the HelloWorldController class takes a name anda numTimes parameter and then outputs the values directly to the browser. Rather than have thecontroller render this response as a string, let’s change the controller to use a view template instead. Theview template will generate a dynamic response, which means that you need to pass appropriate bits ofdata from the controller to the view in order to generate the response. You can do this by having thecontroller put the dynamic data (parameters) that the view template needs in a ViewBag object that theview template can then access.Return to the HelloWorldController.cs file and change the Welcome method to adda Message and NumTimes value to the ViewBag object. ViewBag is a dynamic object, which means youcan put whatever you want in to it; the ViewBag object has no defined properties until you put somethinginside it. The ASP.NET MVC model binding system automatically maps the named parameters(name and numTimes ) from the query string in the address bar to parameters in your method. Thecomplete HelloWorldController.cs file looks like this:

using System . Web;using System . Web. Mvc;

namespace MvcMovie. Controllers {

public class HelloWorldController : Controller {

public ActionResult Index (){

return View();}

public ActionResult Welcome( string name, int numTimes = 1){

ViewBag. Message = "Hello " + name;ViewBag. NumTimes = numTimes;

return View();}

}}

8

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 29/115

Now the ViewBag object contains data that will be passed to the view automatically. Next, you need aWelcome view template! In the Build menu, select Build Solution (or Ctrl+Shift+B) to make sure theproject is compiled. Right click the Views\HelloWorld folder and click Add , then click MVC 5 View Pagewith (Layout Razor) .

In the Specify Name for Item dialog box, enter Welcome , and then click OK .

9

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 30/115

In the Select a Layout Page dialog, accept the default _Layout.cshtml and click OK .

The MvcMovie\Views\HelloWorld\Welcome.cshtml file is created.Replace the markup in the Welcome.cshtml file. You'll create a loop that says "Hello" as many times as theuser says it should. The complete Welcome.cshtml file is shown below.

@{ViewBag.Title = "Welcome";

}

<h2>Welcome</h2>

<ul> @for (int i = 0; i < ViewBag.NumTimes; i++)

{ <li> @ViewBag.Message </li> }

</ul>

Run the application and browse to the following URL:

http://localhost:xx/HelloWorld/Welcome?name=Scott&numtimes=4

30

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 31/115

Now data is taken from the URL and passed to the controller using the model binder . The controllerpackages the data into a ViewBag object and passes that object to the view. The view then displays thedata as HTML to the user.

In the sample above, we used a ViewBag object to pass data from the controller to a view. Latter in the

tutorial, we will use a view model to pass data from a controller to a view. The view model approach topassing data is generally much preferred over the view bag approach. See the blog entry Dynamic VStrongly Typed Views for more information.Well, that was a kind of an "M" for model, but not the database kind. Let's take what we've learned andcreate a database of movies.

Adding a ModelBy Rick Anderson |October 17, 2013

In this section you'll add some classes for managing movies in a database. These classes will be the

"model" part of the ASP.NET MVC app.

You’ll use a .NET Framework data -access technology known as the Entity Framework to define and workwith these model classes. The Entity Framework (often referred to as EF) supports a developmentparadigm called Code First . Code First allows you to create model objects by writing simple classes. (Theseare also known as POCO classes, from "plain-old CLR objects.") You can then have the database createdon the fly from your classes, which enables a very clean and rapid development workflow. If you arerequired to create the database first, you can still follow this tutorial to learn about MVC and EF app

31

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 32/115

development. You can then follow Tom Fizmakens ASP.NET Scaffolding tutorial, which covers the databasefirst approach.

Adding Model ClassesIn Solution Explorer , right click the Models folder, select Add , and then select Class .

Enter the class name "Movie".Add the following five properties to the Movie class:

using System ;

namespace MvcMovie. Models {

public class Movie

32

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 33/115

{public int ID { get ; set ; }public string Title { get ; set ; }public DateTime ReleaseDate { get ; set ; }public string Genre { get ; set ; }

public decimal Price { get ; set ; }}

}

We'll use the Movie class to represent movies in a database. Each instance of a Movie object willcorrespond to a row within a database table, and each property of the Movie class will map to a column inthe table.In the same file, add the following MovieDBContext class:

using System ;using System . Data . Entity ;

namespace MvcMovie. Models {

public class Movie {

public int ID { get ; set ; }public string Title { get ; set ; }public DateTime ReleaseDate { get ; set ; }public string Genre { get ; set ; }public decimal Price { get ; set ; }

}

public class MovieDBContext : DbContext {

public DbSet <Movie > Movies { get ; set ; }}

}

The MovieDBContext class represents the Entity Framework movie database context, which handlesfetching, storing, and updating Movie class instances in a database. The MovieDBContext derives fromthe DbContext base class provided by the Entity Framework.In order to be able to reference DbContext and DbSet , you need to add the following using statement atthe top of the file:

using System . Data . Entity ;

You can do this by manually adding the using statement, or you can right click on the red squiggly linesand click Resolve , and then click using System .Data .Entity .

33

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 34/115

Note: Several unused using statements have been removed. You can do this by right clicking in the file,clickOrganize Usings , and then click Remove Unused Usings.

34

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 35/115

We've finally added a model (the M in MVC). In the next section you'll work with the database connectionstring.

Creating a Connection String and Workingwith SQL Server LocalDBBy Rick Anderson |October 17, 2013

Creating a Connection String and Working with SQLServer LocalDBThe MovieDBContext class you created handles the task of connecting to the database andmapping Movieobjects to database records. One question you might ask, though, is how to specify whichdatabase it will connect to. You don't actually have to specify which database to use, Entity Framework

35

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 36/115

will default to using LocalDB. In this section we'll explicitly add a connection string inthe Web.config file of the application.

SQL Server Express LocalDBLocalDB is a lightweight version of the SQL Server Express Database Engine that starts on demand andruns in user mode. LocalDB runs in a special execution mode of SQL Server Express that enables youto work with databases as .mdf files. Typically, LocalDB database files are kept in the App_Data folderof a web project.SQL Server Express is not recommended for use in production web applications. LocalDB in particularshould not be used for production with a web application because it is not designed to work with IIS.However, a LocalDB database can be easily migrated to SQL Server or SQL Azure.

In Visual Studio 2013 (and in 2012), LocalDB is installed by default with Visual Studio.

By default, the Entity Framework looks for a connection string named the same as the object context class(MovieDBContext for this project). For more information see SQL Server Connection Strings for ASP.NET

Web Applications . Open the application root Web.config file shown below. (Not the Web.config file in the Views folder.)

Find the <connectionStrings> element:

36

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 37/115

Add the following connection string to the <connectionStrings> element in the Web.config file.

<add name="MovieDBContext" connectionString ="Data

Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;IntegratedSecurity=True"

providerName ="System.Data.SqlClient" />

The following example shows a portion of the Web.config file with the new connection string added:<connectionStrings>

<add name="DefaultConnection" connectionString ="DataSource=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MvcMovie-20130603030321.mdf;Initial Catalog=aspnet-MvcMovie-20130603030321;IntegratedSecurity=True" providerName ="System.Data.SqlClient" />

<add name="MovieDBContext" connectionString ="DataSource=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;IntegratedSecurity=True" providerName ="System.Data.SqlClient" />

The two connection strings are very similar. The first connection stringis named DefaultConnection and is used for the membership database to control who can access theapplication. The connection string you've added specifies a LocalDB database named Movie.mdf locatedin the App_Data folder. We won't use the membership database in this tutorial, for more informationon membership, authentication and security, see my tutorial Deploy a Secure ASP.NET MVC app withMembership, OAuth, and SQL Database to a Windows Azure Web Site. The name of the connection string must match the name of the DbContext class.

using System ;

37

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 38/115

using System . Data . Entity ;

namespace MvcMovie. Models {

public class Movie

{public int ID { get ; set ; }public string Title { get ; set ; }public DateTime ReleaseDate { get ; set ; }public string Genre { get ; set ; }public decimal Price { get ; set ; }

}

public class MovieDBContext : DbContext {

public DbSet <Movie > Movies { get ; set ; }

}}

You don't actually need to add the MovieDBContext connection string. If you don't specify a connectionstring, Entity Framework will create a LocalDB database in the users directory with the fully qualified nameof th eDbContext class (in this case MvcMovie.Models.MovieDBContext ). You can name the databaseanything you like, as long as it has the .MDF suffix. For example, we could name thedatabase MyFilms.mdf .Next, you'll build a new MoviesController class that you can use to display the movie data and allowusers to create new movie listings.

Accessing Your Model's Data from aControllerBy Rick Anderson |October 17, 2013

In this section, you'll create a new MoviesController class and write code that retrieves the movie dataand displays it in the browser using a view template.Build the application before going on to the next step. If you don't build the application, you'll get anerror adding a controller.In Solution Explorer, right-click the Controllers folder and then click Add , then Controller .

38

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 39/115

In the Add Scaffold dialog box, click MVC 5 Controller with views, using Entity Framework , and thenclick Add .

39

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 40/115

For the Controller name enter MoviesController . Select Movie (MvcMovie.Models) for the Model class. Select MovieDBContext (MvcMovie.Models) for the Data context class.

The image below shows the completed dialog.

0

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 41/115

Click Add . (If you get an error, you probably didn't build the application before starting adding thecontroller.) Visual Studio creates the following files and folders:

A MoviesController.cs file in the Controllers folder. A Views\Movies folder. Create.cshtml, Delete.cshtml, Details.cshtml, Edit.cshtml , and Index.cshtml in the

new Views\Movies folder.Visual Studio automatically created the CRUD (create, read, update, and delete) action methods andviews for you (the automatic creation of CRUD action methods and views is known as scaffolding). Younow have a fully functional web application that lets you create, list, edit, and delete movie entries.Run the application and click on the MVC Movie link (or browse to the Movies controllerby appending /Movies to the URL in the address bar of your browser). Because the application is relyingon the default routing (defined in the App_Start\RouteConfig.cs file), the browserrequest http://localhost:xxxxx/Movies is routed to the default Index action method ofthe Movies controller. In other words, the browser request http://localhost:xxxxx/Movies is effectively thesame as the browser request http://localhost:xxxxx/Movies/Index . The result is an empty list of movies,because you haven't added any yet.

1

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 42/115

Creating a MovieSelect the Create New link. Enter some details about a movie and then click the Create button.

2

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 43/115

Note: You may not be able to enter decimal points or commas in the Price field. To support jQueryvalidation for non-English locales that use a comma (",") for a decimal point, and non US-English dateformats, you must include globalize.js and yourspecific cultures/globalize.cultures.js file(from https://github.com/jquery/globalize ) and JavaScript touse Globalize.parseFloat . I'll show how to do this in the next tutorial. For now, just enter wholenumbers like 10.

3

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 44/115

Clicking the Create button causes the form to be posted to the server, where the movie information issaved in the database. You're then redirected to the /Movies URL, where you can see the newlycreated movie in the listing.

Create a couple more movie entries. Try the Edit , Details , and Delete links, which are all functional.

Examining the Generated CodeOpen the Controllers\MoviesController.cs file and examine the generated Index method. A portion of themovie controller with the Index method is shown below.

public class MoviesController : Controller {

private MovieDBContext db = new MovieDBContext ();

// GET: /Movies/ public ActionResult Index (){

return View(db. Movies . ToList ());}

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 45/115

A request to the Movies controller returns all the entries in the Movies table and then passes the resultsto the Index view. The following line from the MoviesController class instantiates a movie databasecontext, as described previously. You can use the movie database context to query, edit, and deletemovies.

private MovieDBContext db = new MovieDBContext ();

Strongly Typed Models and the @model KeywordEarlier in this tutorial, you saw how a controller can pass data or objects to a view template usingthe ViewBagobject. The ViewBag is a dynamic object that provides a convenient late-bound way topass information to a view.MVC also provides the ability to pass strongly typed objects to a view template. This strongly typedapproach enables better compile-time checking of your code and richer IntelliSense in the Visual Studioeditor. The scaffolding mechanism in Visual Studio used this approach (that is, passing a strongly typedmodel) with the MoviesController class and view templates when it created the methods and views.In the Controllers\MoviesController.cs file examine the generated Details method. The Details methodis shown below.

public ActionResult Details ( int ? id){

if (id == null ){

return new HttpStatusCodeResult ( HttpStatusCode . BadRequest );}Movie movie = db. Movies . Find (id);if (movie == null ){

return HttpNotFound ();

}return View(movie);}

The id parameter is generally passed as route data, forexample http://localhost:1234/movies/details/1 will set the controller to the movie controller, theaction to details and the id to 1. You could also pass in the id with a query string as follows:http://localhost:1234/movies/details?id=1 If a Movie is found, an instance of the Movie model is passed to the Details view:

return View(movie);

Examine the contents of the Views\Movies\Details.cshtml file:

@model MvcMovie.Models.Movie

@{ViewBag.Title = "Details";

}

<h2>Details </h2>

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 46/115

<div> <h4>Movie</h4>

<hr /> <dl class ="dl-horizontal" >

<dt>

@Html.DisplayNameFor(model => model.Title)</dt>

@*Markup omitted for clarity.*@</dl>

</div> <p>

@Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |@Html.ActionLink("Back to List", "Index")

</p>

By including a @model statement at the top of the view template file, you can specify the type of objectthat the view expects. When you created the movie controller, Visual Studio automatically included thefollowing @modelstatement at the top of the Details.cshtml file:@model MvcMovie.Models.Movie

This @model directive allows you to access the movie that the controller passed to the view by usinga Modelobject that's strongly typed. For example, in the Details.cshtml template, the code passes eachmovie field to th eDisplayNameFor and DisplayFor HTML Helpers with the stronglytyped Model object. The Create and Edit methods and view templates also pass a movie model object.Examine the Index.cshtml view template and the Index method in the MoviesController.cs file. Notice howthe code creates a List object when it calls the View helper method in the Index action method. Thecode then passes this Movies list from the Index action method to the view:

public ActionResult Index ()

{return View(db. Movies . ToList ());

}

When you created the movie controller, Visual Studio automatically included thefollowing @model statement at the top of the Index.cshtml file:

@model IEnumerable <MvcMovie.Models.Movie>

This @model directive allows you to access the list of movies that the controller passed to the view byusing a Model object that's strongly typed. For example, in the Index.cshtml template, the code loopsthrough the movies by doing a foreach statement over the strongly typed Model object:

@foreach (var item in Model) {<tr>

<td> @Html.DisplayFor(modelItem => item.Title)

</td> <td>

@Html.DisplayFor(modelItem => item.ReleaseDate)</td> <td>

6

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 47/115

@Html.DisplayFor(modelItem => item.Genre)</td> <td>

@Html.DisplayFor(modelItem => item.Price)</td>

<th> @Html.DisplayFor(modelItem => item.Rating)

</th> <td>

@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |@Html.ActionLink("Details", "Details", { id=item.ID }) |@Html.ActionLink("Delete", "Delete", { id=item.ID })

</td> </tr>

}

Because the Model object is strongly typed (as an IEnumerable<Movie> object), each item object in theloop is typed as Movie. Among other benefits, this means that you get compile-time checking of thecode and full IntelliSense support in the code editor:

Working with SQL Server LocalDBEntity Framework Code First detected that the database connection string that was provided pointed toa Movies database that didn’t exist yet, so Code First created the database automatically. You can verifythat it's been created by looking in the App_Data folder. If you don't see the Movies.mdf file, click

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 48/115

the Show All Files button in the Solution Explorer toolbar, click the Refresh button, and then expandthe App_Data folder.

Double-click Movies.mdf to open SERVER EXPLORER , then expand the Tables folder to see the Moviestable. Note the key icon next to ID. By default, EF will make a property named ID the primary key. Formore information on EF and MVC, see Tom Dykstra's excellent tutorial on MVC and EF.

8

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 49/115

Right-click the Movies table and select Show Table Data to see the data you created.

9

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 50/115

Right-click the Movies table and select Open Table Definition to see the table structure that EntityFramework Code First created for you.

50

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 51/115

51

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 52/115

Notice how the schema of the Movies table maps to the Movie class you created earlier. EntityFramework Code First automatically created this schema for you based on your Movie class.When you're finished, close the connection by right clicking MovieDBContext and selecting CloseConnection . (If you don't close the connection, you might get an error the next time you run the project).

52

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 53/115

You now have a database and pages to display, edit, update and delete data. In the next tutorial, we'llexamine the rest of the scaffolded code and add a SearchIndex method and a SearchIndex view thatlets you search for movies in this database. For more information on using Entity Framework with MVC,see Creating an Entity Framework Data Model for an ASP.NET MVC Application .

Examining the Edit Methods and Edit ViewBy Rick Anderson |October 17, 2013

In this section, you'll examine the generated Edit action methods and views for the movie controller. Butfirst will take a short diversion to make the release date look better. Open the Models\Movie.cs file andadd the highlighted lines shown below:

53

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 54/115

using System ;using System . ComponentModel . DataAnnotations ;using System . Data . Entity ;

namespace MvcMovie. Models

{public class Movie {

public int ID { get ; set ; }public string Title { get ; set ; }

[ Display ( Name = "Release Date" )][ DataType ( DataType . Date )][ DisplayFormat ( DataFormatString = "{0:yyyy-MM-dd}" , ApplyFormatInEditMode =

true )]public DateTime ReleaseDate { get ; set ; }

public string Genre { get ; set ; }public decimal Price { get ; set ; }}

public class MovieDBContext : DbContext {

public DbSet <Movie > Movies { get ; set ; }}

}

We'll cover DataAnnotations in the next tutorial. The Display attribute specifies what to display for thename of a field (in this case "Release Date" instead of "ReleaseDate"). The DataType attribute specifies the

type of the data, in this case it's a date, so the time information stored in the field is not displayed.The DisplayFormat attribute is needed for a bug in the Chrome browser that renders date formatsincorrectly.Run the application and browse to the Movies controller. Hold the mouse pointer over an Edit link to seethe URL that it links to.

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 56/115

link to action methods on controllers. The first argument to the ActionLink method is the link text torender (for example, <a>Edit Me</a> ). The second argument is the name of the action method to invoke(In this case, the Edit action). The final argument is an anonymous object that generates the route data(in this case, the ID of 4).The generated link shown in the previous image is http://localhost:1234/Movies/Edit/4 . The default

route (established in App_Start\RouteConfig.cs ) takes the URLpattern {controller}/{action}/{id} . Therefore, ASP.NETtranslates http://localhost:1234/Movies/Edit/4 into a request to the Edit action method ofthe Movies controller with the parameter ID equal to 4. Examine the following code fromthe App_Start\RouteConfig.cs file. TheMapRoute method is used to route HTTP requests to thecorrect controller and action method and supply the optional ID parameter. The MapRoute method isalso used by the HtmlHelpers such as ActionLink to generate URLs given the controller, action methodand any route data.

public static void RegisterRoutes ( RouteCollection routes){

routes. IgnoreRoute ( "{resource}.axd/{*pathInfo}" );

routes. MapRoute (name: "Default" ,url: "{controller}/{action}/{id}" ,defaults: new { controller = "Home", action = "Index" ,

id = UrlParameter . Optional });

}

You can also pass action method parameters using a query string. For example, theURLhttp://localhost:1234/Movies/Edit?ID=3 also passes the parameter ID of 3 to the Edit action

method of the Movies controller.

56

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 57/115

Open the Movies controller. The two Edit action methods are shown below.

// GET: /Movies/Edit/5 public ActionResult Edit ( int ? id){

if (id == null )

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 58/115

{return new HttpStatusCodeResult ( HttpStatusCode . BadRequest );

}Movie movie = db. Movies . Find (id);if (movie == null )

{return HttpNotFound ();

}return View(movie);

}

// POST: /Movies/Edit/5 // To protect from overposting attacks, please enable the specific properties youwant to bind to, for// more details see http://go.microsoft.com/fwlink/?LinkId=317598. [ HttpPost ]

[ ValidateAntiForgeryToken ]public ActionResult Edit ([ Bind ( Include ="ID,Title,ReleaseDate,Genre,Price" )] Movie movie){

if ( ModelState . IsValid ){

db. Entry (movie). State = EntityState . Modified ;db. SaveChanges ();return RedirectToAction ( "Index" );

}return View(movie);

} Notice the second Edit action method is preceded by the HttpPost attribute. This attribute specifies thatthat overload of the Edit method can be invoked only for POST requests. You could applythe HttpGet attribute to the first edit method, but that's not necessary because it's the default. (We'llrefer to action methods that are implicitly assigned the HttpGet attributeas HttpGet methods.) The Bind attribute is another important security mechanism that keeps hackersfrom over-posting data to your model. You should only include properties in the bind attribute that youwant to change. You can read about overposting and the bind attribute in my overposting security note . In the simple model used in this tutorial, we will be binding all the data in the model.The ValidateAntiForgeryToken attribute is used to prevent forgery of a request and is paired upwith @Html.AntiForgeryToken () in the edit view file ( Views\Movies\Edit.cshtml ), a portion is shown

below:@model MvcMovie.Models.Movie

@{ViewBag.Title = "Edit";

}<h2>Edit </h2> @using (Html.BeginForm())

58

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 59/115

{@Html.AntiForgeryToken()<div class ="form-horizontal" >

<h4>Movie</h4> <hr />

@Html.ValidationSummary(true)@Html.HiddenFor(model => model.ID)

<div class ="form-group" > @Html.LabelFor(model => model.Title, new { @class = "control-label col-

md-2" })<div class ="col-md-10" >

@Html.EditorFor(model => model.Title)@Html.ValidationMessageFor(model => model.Title)

</div> </div>

@Html.AntiForgeryToken() generates a hidden form anti-forgery token that must match inthe Edit method of the Movies controller. You can read more about Cross-site request forgery (alsoknown as XSRF or CSRF) in my tutorial XSRF/CSRF Prevention in MVC. The HttpGet Edit method takes the movie ID parameter, looks up the movie using the EntityFramework Find method, and returns the selected movie to the Edit view. If a movie cannot befound, HttpNotFound is returned. When the scaffolding system created the Edit view, it examinedthe Movie class and created code to render <label> and <input> elements for each property of the class.The following example shows the Edit view that was generated by the visual studio scaffolding system:

@model MvcMovie.Models.Movie

@{ViewBag.Title = "Edit";

}<h2>Edit </h2> @using (Html.BeginForm()){

@Html.AntiForgeryToken()<div class ="form-horizontal" >

<h4>Movie</h4> <hr /> @Html.ValidationSummary(true)@Html.HiddenFor(model => model.ID)

<div class ="form-group" > @Html.LabelFor(model => model.Title, new { @class = "control-label col-

md-2" })<div class ="col-md-10" >

@Html.EditorFor(model => model.Title)@Html.ValidationMessageFor(model => model.Title)

</div>

59

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 60/115

</div> <div class ="form-group" >

@Html.LabelFor(model => model.ReleaseDate, new { @class = "control-labelcol-md-2" })

<div class ="col-md-10" >

@Html.EditorFor(model => model.ReleaseDate)@Html.ValidationMessageFor(model => model.ReleaseDate)

</div> </div> @*Genre and Price removed for brevity.*@<div class ="form-group" >

<div class ="col-md-offset-2 col-md-10" > <input type ="submit" value ="Save" class ="btn btn-default" />

</div> </div>

</div>

}<div> @Html.ActionLink("Back to List", "Index")

</div> @section Scripts {

@Scripts.Render("~/bundles/jqueryval")}

Notice how the view template has a @model MvcMovie.Models.Movie statement at the top of the file — this specifies that the view expects the model for the view template to be of type Movie.The scaffolded code uses several helper methods to streamline the HTML markup.The Html.LabelFor helper displays the name of the field ("Title", "ReleaseDate", "Genre", or "Price").

The Html.EditorFor helper renders an HTML <input> element.The Html.ValidationMessageFor helper displays any validation messages associated with that property.Run the application and navigate to the /Movies URL. Click anEdit link. In the browser, view the sourcefor the page. The HTML for the form element is shown below.

<form action ="/movies/Edit/4" method ="post" > <input name="__RequestVerificationToken" type ="hidden" value ="UxY6bkQyJCXO3Kn5AXg-

6TXxOj6yVBi9tghHaQ5Lq_qwKvcojNXEEfcbn-FGh_0vuw4tS_BRk7QQQHlJp8AP4_X4orVNoQnp2cd8kXhykS01" /> <fieldset class ="form-horizontal" >

<legend> Movie</legend>

<input data-val ="true" data-val-number ="The field ID must be a number." data-val-required ="The ID field is required." id ="ID" name="ID" type ="hidden" value ="4" />

<div class ="control-group" > <label class ="control-label" for ="Title" >Title </label> <div class ="controls" >

<input class ="text-box single-line" id ="Title" name="Title" type ="text" value ="GhostBusters" />

60

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 61/115

<span class ="field-validation-valid help-inline" data-valmsg-for ="Title" data-valmsg-replace ="true" ></span>

</div> </div>

<div class ="control-group" > <label class ="control-label" for ="ReleaseDate" >Release Date </label> <div class ="controls" >

<input class ="text-box single-line" data-val ="true" data-val-date ="Thefield Release Date must be a date." data-val-required ="The Release Date field isrequired." id ="ReleaseDate" name="ReleaseDate" type ="date" value ="1/1/1984" />

<span class ="field-validation-valid help-inline" data-valmsg-for ="ReleaseDate" data-valmsg-replace ="true" ></span>

</div> </div>

<div class ="control-group" > <label class ="control-label" for ="Genre" >Genre </label> <div class ="controls" >

<input class ="text-box single-line" id ="Genre" name="Genre" type ="text" value ="Comedy" />

<span class ="field-validation-valid help-inline" data-valmsg-for ="Genre" data-valmsg-replace ="true" ></span>

</div> </div>

<div class ="control-group" > <label class ="control-label" for ="Price" >Price </label> <div class ="controls" >

<input class ="text-box single-line" data-val ="true" data-val-number ="Thefield Price must be a number." data-val-required ="The Price field is required." id ="Price" name="Price" type ="text" value ="7.99" />

<span class ="field-validation-valid help-inline" data-valmsg-for ="Price" data-valmsg-replace ="true" ></span>

</div> </div>

<div class ="form-actions no-color" > <input type ="submit" value ="Save" class ="btn" />

</div> </fieldset>

</form>

The <input> elements are in an HTML <form> element whose action attribute is set to post tothe /Movies/Edit URL. The form data will be posted to the server when the Save button is clicked. Thesecond line shows the hidden XSRF token generated by the @Html.AntiForgeryToken() call.

61

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 62/115

Processing the POST RequestThe following listing shows the HttpPost version of the Edit action method.

[ HttpPost ][ ValidateAntiForgeryToken ]public ActionResult Edit ([ Bind ( Include ="ID,Title,ReleaseDate,Genre,Price" )] Movie movie){

if ( ModelState . IsValid ){

db. Entry (movie). State = EntityState . Modified ;db. SaveChanges ();return RedirectToAction ( "Index" );

}return View(movie);

}

The ValidateAntiForgeryToken attribute validates the XSRF token generated bythe @Html.AntiForgeryToken() call in the view.The ASP.NET MVC model binder takes the posted form values and creates a Movie object that's passed asthe movie parameter. The ModelState.IsValid method verifies that the data submitted in the form canbe used to modify (edit or update) a Movie object. If the data is valid, the movie data is saved tothe Movies collection of the db(MovieDBContext instance). The new movie data is saved to the databaseby calling the SaveChanges method of MovieDBContext . After saving the data, the code redirects theuser to the Index action method of the MoviesController class, which displays the movie collection,including the changes just made.As soon as the client side validation determines the values of a field are not valid, an error message isdisplayed. If you disable JavaScript, you won't have client side validation but the server will detect theposted values are not valid, and the form values will be redisplayed with error messages. Later in thetutorial we examine validation in more detail.

The Html.ValidationMessageFor helpers in the Edit.cshtml view template take care of displayingappropriate error messages.

62

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 63/115

All the HttpGet methods follow a similar pattern. They get a movie object (or list of objects, in the caseof Index ), and pass the model to the view. The Create method passes an empty movie object to theCreate view. All the methods that create, edit, delete, or otherwise modify data do so in

63

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 64/115

the HttpPost overload of the method. Modifying data in an HTTP GET method is a security risk, asdescribed in the blog post entry ASP.NET MVC Tip #46 – Don’t use Delete Links because they createSecurity Holes . Modifying data in a GET method also violates HTTP best practices and thearchitectural REST pattern, which specifies that GET requests should not change the state of yourapplication. In other words, performing a GET operation should be a safe operation that has no side

effects and doesn't modify your persisted data.If you are using a US-English computer, you can skip this section and go to the next tutorial.

Note to support jQuery validation for non-English locales that use a comma (",") for a decimal point, andnon US-English date formats, you must include globalize.js and yourspecificcultures/globalize.cultures.js file(from https://github.com/jquery/globalize ) and JavaScript touse Globalize.parseFloat . You can get the jQuery non-English validation from NuGet. (Don't installGlobalize if you are using a English locale.)

1. From the Tools menu click Library Package Manager , and then click Manage NuGet Packages forSolution .

64

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 65/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 66/115

Click Install . The Scripts\jquery.globalize\globalize.js file will be added to your project.

TheScripts\jquery.globalize\cultures\ folder will contain many culture JavaScript files. Note, itcan take five minutes to install this package.

The following code shows the modifications to the Views\Movies\Edit.cshtml file to work with the "fr-FR"culture: @section Scripts {

@Scripts.Render("~/bundles/jqueryval")<script src ="~/Scripts/jquery.globalize/globalize.js" ></script> <script src ="~/Scripts/jquery.globalize/cultures/globalize.culture.fr-

FR.js" ></script> <script>

66

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 67/115

$.validator.methods.number = function (value, element) {return this .optional(element) ||

!isNaN( Globalize .parseFloat(value));}$(document).ready( function () {

Globalize .culture( 'fr-FR' );});

</script> <script>

jQuery.extend(jQuery.validator.methods, {range: function (value, element, param) {

//Use the Globalization plugin to parse the value var val = $.global.parseFloat(value);return this .optional(element) || (

val >= param[ 0] && val <= param[ 1]);}

});</script> <script>

$.validator.methods.date = function (value, element) {return this .optional(element) ||Globalize .parseDate(value);

}</script>

}

To avoid repeating this code in every Edit view, you can move it to the layout file. To optimize the scriptdownload, see my tutorial Bundling and Minification .

For more information see ASP.NET MVC 3 Internationalization and ASP.NET MVC 3 Internationalization -Part 2 (NerdDinner) . As a temporary fix, if you can't get validation working in your locale, you can force your computer to useUS English or you can disable JavaScript in your browser. To force your computer to use US English, youcan add the globalization element to the projects root web.config file. The following code shows theglobalization element with the culture set to United States English.

<system.web> <globalization culture = "en-US" /> <!--elements removed for clarity-->

</system.web>

In the next tutorial, we'll implement search functionality.

SearchBy Rick Anderson |October 17, 2013

Adding a Search Method and Search View

67

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 68/115

In this section you'll add search capability to the Index action method that lets you search movies bygenre or name.

Updating the Index FormStart by updating the Index action method to the existing MoviesController class. Here's the code:

public ActionResult Index ( string searchString){

var movies = from m in db. Movies select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

return View(movies);

}

The first line of the Index method creates the following LINQ query to select the movies:

var movies = from m in db. Movies select m;

The query is defined at this point, but hasn't yet been run against the database.

If the searchString parameter contains a string, the movies query is modified to filter on the value ofthe search string, using the following code:

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

The s => s.Title code above is a Lambda Expression . Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as the Where method usedin the above code. LINQ queries are not executed when they are defined or when they are modified bycalling a method such as Where or OrderBy . Instead, query execution is deferred, which means that theevaluation of an expression is delayed until its realized value is actually iterated over orthe ToList method is called. In the Search sample, the query is executed in the Index.cshtml view. Formore information about deferred query execution, see Query Execution . Note : TheContains method isrun on the database, not the c# code above. On the database, Contains maps to SQL LIKE, which is caseinsensitive.Now you can update the Index view that will display the form to the user.Run the application and navigate to /Movies/Index . Append a query string suchas ?searchString=ghost to the URL. The filtered movies are displayed.

68

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 69/115

If you change the signature of the Index method to have a parameter named id , the id parameter willmatch the {id} placeholder for the default routes set in the App_Start\RouteConfig.cs file.

{controller}/{action}/{id}

The original Index method looks like this::

public ActionResult Index ( string searchString){

var movies = from m in db. Movies

select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

return View(movies);

69

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 70/115

}

The modified Index method would look as follows:

public ActionResult Index ( string id){

string searchString = id;var movies = from m in db. Movies select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

return View(movies);}

You can now pass the search title as route data (a URL segment) instead of as a query string value.

70

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 71/115

However, you can't expect users to modify the URL every time they want to search for a movie. So nowyou you'll add UI to help them filter movies. If you changed the signature of the Index method to testhow to pass the route-bound ID parameter, change it back so that your Index method takes a stringparameter named searchString :

public ActionResult Index ( string searchString){

var movies = from m in db. Movies select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

return View(movies);}

71

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 72/115

Open the Views\Movies\Index.cshtml file, and just after @Html.ActionLink("Create New", "Create") ,add the form markup highlighted below:

@model IEnumerable <MvcMovie.Models.Movie>

@{

ViewBag.Title = "Index";}

<h2>Index </h2>

<p> @Html.ActionLink("Create New", "Create")

@using (Html.BeginForm()){<p> Title: @Html.TextBox("SearchString") <br /> <input type ="submit" value ="Filter" /></p>

}</p>

The Html. BeginForm helper creates an opening <form > tag. The Html.BeginForm helper causes theform to post to itself when the user submits the form by clicking the Filter button.Visual Studio 2013 has a nice improvement when displaying and editing View files. When you run theapplication with a view file open, Visual Studio 2013 invokes the correct controller action method todisplay the view.

72

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 73/115

With the Index view open in Visual Studio (as shown in the image above), tap Ctr F5 or F5 to run theapplication and then try searching for a movie.

73

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 74/115

There's no HttpPost overload of the Index method. You don't need it, because the method isn'tchanging the state of the application, just filtering data.You could add the following HttpPost Index method. In that case, the action invoker would matchthe HttpPost Index method, and the HttpPost Index method would run as shown in the imagebelow.

[ HttpPost ]public string Index ( FormCollection fc, string searchString){

return "<h3> From [HttpPost]Index: " + searchString + "</h3>" ;}

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 75/115

However, even if you add this HttpPost version of the Index method, there's a limitation in how thishas all been implemented. Imagine that you want to bookmark a particular search or you want to send alink to friends that they can click in order to see the same filtered list of movies. Notice that the URL forthe HTTP POST request is the same as the URL for the GET request (localhost:xxxxx/Movies/Index) --there's no search information in the URL itself. Right now, the search string information is sent to theserver as a form field value. This means you can't capture that search information to bookmark or send tofriends in a URL.The solution is to use an overload of BeginForm that specifies that the POST request should add thesearch information to the URL and that it should be routed to the HttpGet version ofthe Index method. Replace the existing parameterless BeginForm method with the following markup:

@using (Html.BeginForm("Index","Movies",FormMethod.Get))

Now when you submit a search, the URL contains a search query string. Searching will also go tothe HttpGet Index action method, even if you have a HttpPost Index method.

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 76/115

Adding Search by GenreIf you added the HttpPost version of the Index method, delete it now.Next, you'll add a feature to let users search for movies by genre. Replace the Index method with thefollowing code:

public ActionResult Index ( string movieGenre, string searchString){

var GenreLst = new List <string> ();

var GenreQry = from d in db. Movies orderby d. Genre select d. Genre ;

GenreLst . AddRange( GenreQry . Distinct ());ViewBag.movieGenre = new SelectList ( GenreLst );

76

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 77/115

var movies = from m in db. Movies select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));}

if (! string . IsNullOrEmpty (movieGenre)){

movies = movies. Where(x => x. Genre == movieGenre);}

return View(movies);}

This version of the Index method takes an additional parameter, namely movieGenre . The first few linesof code create a List object to hold movie genres from the database.The following code is a LINQ query that retrieves all the genres from the database.

var GenreQry = from d in db. Movies orderby d. Genre select d. Genre ;

The code uses the AddRange method of the generic List collection to add all the distinct genres to thelist. (Without the Distinct modifier, duplicate genres would be added — for example, comedy would beadded twice in our sample). The code then stores the list of genres in the ViewBag.movieGenre object.Storing category data (such a movie genre's) as a SelectList object in a ViewBag, then accessing the

category data in a dropdown list box is a typical approach for MVC applications.The following code shows how to check the movieGenre parameter. If it's not empty, the code furtherconstrains the movies query to limit the selected movies to the specified genre.

if (! string . IsNullOrEmpty (movieGenre)){

movies = movies. Where(x => x. Genre == movieGenre);}

As stated previously, the query is not run on the data base until the movie list is iterated over (whichhappens in the View, after the Index action method returns).

Adding Markup to the Index View to Support Search byGenreAdd an Html.DropDownList helper to the Views\Movies\Index.cshtml file, just beforethe TextBox helper. The completed markup is shown below:

@model IEnumerable <MvcMovie.Models.Movie> @{

ViewBag.Title = "Index";

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 78/115

}<h2>Index </h2> <p>

@Html.ActionLink("Create New", "Create")@using (Html.BeginForm("Index", "Movies", FormMethod.Get))

{<p>

Genre: @Html.DropDownList("movieGenre", "All")Title: @Html.TextBox("SearchString")<input type ="submit" value ="Filter" />

</p> }

</p> <table class ="table" >

In the following code:

@Html.DropDownList("movieGenre", "All")

The parameter "movieGenre" provides the key for the DropDownList helper to finda IEnumerable < SelectListItem > in the ViewBag. The ViewBag was populated in theaction method:

public ActionResult Index ( string movieGenre, string searchString){

var GenreLst = new List <string> ();

var GenreQry = from d in db. Movies orderby d. Genre

select d. Genre ;

GenreLst . AddRange( GenreQry . Distinct ());ViewBag.movieGenre = new SelectList ( GenreLst );

var movies = from m in db. Movies select m;

if (! String . IsNullOrEmpty (searchString)){

movies = movies. Where(s => s. Title . Contains (searchString));

}

if (! string . IsNullOrEmpty (movieGenre)){

movies = movies. Where(x => x. Genre == movieGenre);}

return View(movies);

78

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 79/115

}

The parameter "All" provides the item in the list to be preselected. Had we used the following code:

@Html.DropDownList("movieGenre", "Comedy")

And we had a movie with a "Comedy" genre in our database, "Comedy" would be preselected in thedropdown list. Because we don't have a movie genre "All", there is no "All" in the SelectList , so whenwe post back without making a slection, the movieGenre query string value is empty.Run the application and browse to /Movies/Index . Try a search by genre, by movie name, and by bothcriteria.

In this section you created a search action method and view that let users search by movie title andgenre. In the next section, you'll look at how to add a property to the Movie model and how to add aninitializer that will automatically create a test database.

Adding a New Field

79

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 80/115

By Rick Anderson |October 17, 2013

In this section you'll use Entity Framework Code First Migrations to migrate some changes to the modelclasses so the change is applied to the database.

By default, when you use Entity Framework Code First to automatically create a database, as you didearlier in this tutorial, Code First adds a table to the database to help track whether the schema of thedatabase is in sync with the model classes it was generated from. If they aren't in sync, the EntityFramework throws an error. This makes it easier to track down issues at development time that you mightotherwise only find (by obscure errors) at run time.

Setting up Code First Migrations for Model ChangesNavigate to Solution Explorer. Right click on the Movies.mdf file and select Delete to remove the moviesdatabase. If you don't see the Movies.mdf file, click on the Show All Files icon shown below in the redoutline.

Build the application to make sure there are no errors.

80

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 81/115

From the Tools menu, click Library Package Manager and then Package Manager Console .

In the Package Manager Console window at the PM> prompt enterEnable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

The Enable-Migrations command (shown above) creates a Configuration.cs file in anew Migrations folder.

81

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 82/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 83/115

Price = 8.99M },

new Movie {

Title = "Ghostbusters 2" ,ReleaseDate = DateTime . Parse ( "1986-2-23" ),Genre = "Comedy" ,Price = 9.99M

},

new Movie {

Title = "Rio Bravo" ,ReleaseDate = DateTime . Parse ( "1959-4-15" ),Genre = "Western" ,

Price = 3.99M });

}

Right click on the red squiggly line under Movie and select Resolve and thenclick using MvcMovie.Models;

83

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 84/115

Doing so adds the following using statement:

using MvcMovie. Models ;

Code First Migrations calls the Seed method after every migration (that is, calling update-database inthe Package Manager Console), and this method updates rows that have already been inserted, or insertsthem if they don't exist yet.

The AddOrUpdate method in the following code performs an "upsert" operation:context. Movies . AddOrUpdate (i => i. Title ,

new Movie {

Title = "When Harry Met Sally" ,ReleaseDate = DateTime . Parse ( "1989-1-11" ),Genre = "Romantic Comedy" ,Rating = "PG",

84

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 85/115

Price = 7.99M }

Because the Seed method runs with every migration, you can't just insert data, because the rows you aretrying to add will already be there after the first migration that creates the database. The "upsert " operation prevents errors that would happen if you try to insert a row that already exists, but it overridesany changes to data that you may have made while testing the application. With test data in some tablesyou might not want that to happen: in some cases when you change data while testing you want yourchanges to remain after database updates. In that case you want to do a conditional insert operation:insert a row only if it doesn't already exist.

The first parameter passed to the AddOrUpdate method specifies the property to use to check if a rowalready exists. For the test movie data that you are providing, the Title property can be used for thispurpose since each title in the list is unique:

context. Movies . AddOrUpdate (i => i. Title ,

This code assumes that titiles are unique. If you manually add a duplicate title, you'll get the following

exception the next time you perform a migration.

Sequence contains more than one element

For more information about the AddOrUpdate method, see Take care with EF 4.3 AddOrUpdate Method ..

Press CTRL-SHIFT-B to build the project. (The following steps will fail if you don't build at this point.)The next step is to create a DbMigration class for the initial migration. This migration creates a newdatabase, that's why you deleted the movie.mdf file in a previous step.In the Package Manager Console window, enter the command add-migration Initial to create theinitial migration. The name "Initial" is arbitrary and is used to name the migration file created.

Code First Migrations creates another class file in the Migrations folder (with thename {DateStamp}_Initial.cs ), and this class contains code that creates the database schema. Themigration filename is pre-fixed with a timestamp to help with ordering. Examinethe {DateStamp}_Initial.cs file, it contains the instructions to create the Movies table for the Movie DB.When you update the database in the instructions below, this {DateStamp}_Initial.cs file will run andcreate the the DB schema. Then the Seed method will run to populate the DB with test data.In the Package Manager Console , enter the command update-database to create the database and runthe Seed method.

85

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 86/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 87/115

Adding a Rating Property to the Movie ModelStart by adding a new Rating property to the existing Movie class. Open the Models\Movie.cs file and addthe Rating property like this one:

public string Rating { get ; set ; }

The complete Movie class now looks like the following code:

87

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 88/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 89/115

</th> <th>

@Html.DisplayNameFor(model => model.ReleaseDate)</th> <th>

@Html.DisplayNameFor(model => model.Genre)</th> <th>

@Html.DisplayNameFor(model => model.Price)</th> <th>

@Html.DisplayNameFor(model => model.Rating)</th>

<th></th> </tr>

@foreach (var item in Model) {<tr>

<td> @Html.DisplayFor(modelItem => item.Title)

</td> <td>

@Html.DisplayFor(modelItem => item.ReleaseDate)</td> <td>

@Html.DisplayFor(modelItem => item.Genre)</td> <td>

@Html.DisplayFor(modelItem => item.Price)</td> <td>

@Html.DisplayFor(modelItem => item.Rating)</td>

<td> @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |@Html.ActionLink("Details", "Details", new { id=item.ID }) |@Html.ActionLink("Delete", "Delete", new { id=item.ID })

</td> </tr>

}

</table>

Next, open the \Views\Movies\Create.cshtml file and add the Rating field with the following highlighedmarkup. This renders a text box so that you can specify a rating when a new movie is created.

89

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 90/115

<div class ="form-group" > @Html.LabelFor(model => model.Price, new { @class = "control-label col-

md-2" })<div class ="col-md-10" >

@Html.EditorFor(model => model.Price)

@Html.ValidationMessageFor(model => model.Price)</div>

</div>

<div class ="form-group" > @Html.LabelFor(model => model.Rating, new { @class = "control-label col-

md-2" })<div class ="col-md-10" >

@Html.EditorFor(model => model.Rating)@Html.ValidationMessageFor(model => model.Rating)

</div>

</div>

<div class ="form-group" > <div class ="col-md-offset-2 col-md-10" >

<input type ="submit" value ="Create" class ="btn btn-default" /> </div>

</div> </div>

}

<div> @Html.ActionLink("Back to List", "Index")

</div>

@section Scripts {@Scripts.Render("~/bundles/jqueryval")

}

You've now updated the application code to support the new Rating property.Run the application and navigate to the /Movies URL. When you do this, though, you'll see one of thefollowing errors:

90

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 91/115

The model backing the 'MovieDBContext' context has changed since the database was created. Considerusing Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).

91

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 92/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 93/115

2. Explicitly modify the schema of the existing database so that it matches the model classes. Theadvantage of this approach is that you keep your data. You can make this change either manually orby creating a database change script.

3. Use Code First Migrations to update the database schema.

For this tutorial, we'll use Code First Migrations.

Update the Seed method so that it provides a value for the new column. OpenMigrations\Configuration.cs file and add a Rating field to each Movie object.

new Movie {

Title = "When Harry Met Sally" ,ReleaseDate = DateTime . Parse ( "1989-1-11" ),Genre = "Romantic Comedy" ,Rating = "PG",Price = 7.99M

},

Build the solution, and then open the Package Manager Console window and enter the followingcommand:add-migration Rating The add-migration command tells the migration framework to examine the current movie model withthe current movie DB schema and create the necessary code to migrate the DB to the new model. Thename Rating is arbitrary and is used to name the migration file. It's helpful to use a meaningful name forthe migration step.When this command finishes, Visual Studio opens the class file that defines thenew DbMIgration derived class, and in the Up method you can see the code that creates the newcolumn.

public partial class AddRatingMig : DbMigration {

public override void Up(){

AddColumn( "dbo.Movies" , "Rating" , c => c. String ());}

public override void Down(){

DropColumn ( "dbo.Movies" , "Rating" );

}}

Build the solution, and then enter the update-database command in the Package ManagerConsole window.The following image shows the output in the Package Manager Console window (The date stampprepending Rating will be different.)

93

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 94/115

Re-run the application and navigate to the /Movies URL. You can see the new Rating field.

Click the Create New link to add a new movie. Note that you can add a rating.

94

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 95/115

Click Create . The new movie, including the rating, now shows up in the movies listing:

95

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 96/115

Now that the project is using migrations, you won't need to drop the database when you add a new fieldor otherwise update the schema. In the next section, we'll make more schema changes and use migrationsto update the database.

You should also add the Rating field to the Edit, Details, and Delete view templates.You could enter the "update-database" command in the Package Manager Console window again andno migration code would run, because the schema matches the model. However, running "update-database" will run the Seed method again, and if you changed any of the Seed data, the changes will belost because the Seed method upserts data. You can read more about the Seed method in Tom Dykstra'spopular ASP.NET MVC/Entity Framework tutorial . In this section you saw how you can modify model objects and keep the database in sync with thechanges. You also learned a way to populate a newly created database with sample data so you can tryout scenarios. This was just a quick introduction to Code First, see Creating an Entity Framework DataModel for an ASP.NET MVC Application for a more complete tutorial on the subject. Next, let's look athow you can add richer validation logic to the model classes and enable some business rules to beenforced.

96

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 97/115

Adding ValidationBy Rick Anderson |October 17, 2013

In this this section you'll add validation logic to the Movie model, and you'll ensure that the validation

rules are enforced any time a user attempts to create or edit a movie using the application.Keeping Things DRYOne of the core design tenets of ASP.NET MVC is DRY ("Don't Repeat Yourself"). ASP.NET MVCencourages you to specify functionality or behavior only once, and then have it be reflected everywherein an application. This reduces the amount of code you need to write and makes the code you do writeless error prone and easier to maintain.The validation support provided by ASP.NET MVC and Entity Framework Code First is a great example ofthe DRY principle in action. You can declaratively specify validation rules in one place (in the model class)and the rules are enforced everywhere in the application.

Let's look at how you can take advantage of this validation support in the movie application.

Adding Validation Rules to the Movie ModelYou'll begin by adding some validation logic to the Movie class.Open the Movie.cs file. Notice the System.ComponentModel.DataAnnotations namespace does notcontain System.Web . DataAnnotations provides a built-in set of validation attributes that you can applydeclaratively to any class or property. (It also contains formatting attributes like DataType that help withformatting and don't provide any validation.)Now update the Movie class to take advantage of the built-in Required , StringLength , RegularExpression , and Range validation attributes. Replace the Movie class

with the following:public class Movie {

public int ID { get ; set ; }

[ StringLength ( 60, MinimumLength = 3)]public string Title { get ; set ; }

[ Display ( Name = "Release Date" )][ DataType ( DataType . Date )][ DisplayFormat ( DataFormatString = "{0:yyyy-MM-dd}" , ApplyFormatInEditMode =

true )]public DateTime ReleaseDate { get ; set ; }

97

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 98/115

[ RegularExpression (@"^[A-Z]+[a-zA-Z''-'\s]*$" )]

[ Required ][ StringLength ( 30)]public string Genre { get ; set ; }

[ Range ( 1, 100 )][ DataType ( DataType . Currency )]public decimal Price { get ; set ; }

[ RegularExpression (@"^[A-Z]+[a-zA-Z''-'\s]*$" )][ StringLength ( 5)]public string Rating { get ; set ; }

}

The StringLength attribute sets the maximum length of the string, and it sets this limitation on thedatabase, therefore the database schema will change. Right click on the Movies tablein Server explorer and click Open Table Definition :

98

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 99/115

In the image above, you can see all the string fields are set to NVARCHAR (MAX). We will use migrationsto update the schema. Build the solution, and then open the Package Manager Console window andenter the following commands:add-migration DataAnnotationsupdate-database When this command finishes, Visual Studio opens the class file that defines thenew DbMIgration derived class with the name specified ( DataAnnotations ), and in the Up method youcan see the code that updates the schema constraints:

public override void Up(){

AlterColumn ( "dbo.Movies" , "Title" , c => c. String (maxLength: 60));AlterColumn ( "dbo.Movies" , "Genre" , c => c. String (nullable: false , maxLength:

30));AlterColumn ( "dbo.Movies" , "Rating" , c => c. String (maxLength: 5));

}

The Genre field is are no longer nullable (that is, you must enter a value). The Rating field has amaximum length of 5 and Title has a maximum length of 60. The minimum length of 3 on Title andthe range on Price did not create schema changes.

99

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 100/115

Examine the Movie schema:

The string fields show the new length limits and Genre is no longer checked as nullable.The validation attributes specify behavior that you want to enforce on the model properties they areapplied to. The Required and MinimumLength attributes indicates that a property must have a value;but nothing prevents a user from entering white space to satisfythis validation. The RegularExpression attribute is used to limit what characters can be input. In the codeabove, Genre and Rating must use only letters (white space, numbers and special characters are notallowed). The Range attribute constrains a value to within a specified range. The StringLength attributelets you set the maximum length of a string property, and optionally its minimum length. Value types(such as decimal, int, float, DateTime ) are inherently required and don't needthe Required attribute.

Code First ensures that the validation rules you specify on a model class are enforced before theapplication saves changes in the database. For example, the code below will throwa DbEntityValidationException exception when the SaveChanges method is called, because severalrequired Movie property values are missing:

MovieDBContext db = new MovieDBContext ();Movie movie = new Movie ();movie. Title = "Gone with the Wind" ;db. Movies . Add(movie);db. SaveChanges (); // <= Will throw server side validation exception

The code above throws the following exception:

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details. Having validation rules automatically enforced by the .NET Framework helps make your application morerobust. It also ensures that you can't forget to validate something and inadvertently let bad data into thedatabase.

Validation Error UI in ASP.NET MVC

100

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 101/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 102/115

102

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 103/115

Note to support jQuery validation for non-English locales that use a comma (",") for a decimal point, youmust include the NuGet globalize as described previously in this tutorial.

Notice how the form has automatically used a red border color to highlight the text boxes that containinvalid data and has emitted an appropriate validation error message next to each one. The errors areenforced both client-side (using JavaScript and jQuery) and server-side (in case a user has JavaScriptdisabled).

A real benefit is that you didn't need to change a single line of code in the MoviesController class or inthe Create.cshtml view in order to enable this validation UI. The controller and views you created earlier inthis tutorial automatically picked up the validation rules that you specified by using validation attributeson the properties of the Movie model class. Test validation using the Edit action method, and thesame validation is applied.The form data is not sent to the server until there are no client side validation errors. You can verify thisby putting a break point in the HTTP Post method, by using the fiddler tool , or the IE F12 developertools .

How Validation Occurs in the Create View and CreateAction MethodYou might wonder how the validation UI was generated without any updates to the code in the controlleror views. The next listing shows what the Create methods in the MovieController class looklike. They're unchanged from how you created them earlier in this tutorial.

public ActionResult Create (){

return View();}// POST: /Movies/Create // To protect from overposting attacks, please enable the specific properties youwant to bind to, for// more details see http://go.microsoft.com/fwlink/?LinkId=317598. [ HttpPost ][ ValidateAntiForgeryToken ]public ActionResult Create ([ Bind ( Include ="ID,Title,ReleaseDate,Genre,Price,Rating" )] Movie movie){

if ( ModelState . IsValid ){

db. Movies . Add(movie);db. SaveChanges ();return RedirectToAction ( "Index" );

}return View(movie);

}

103

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 104/115

The first (HTTP GET)Create action method displays the initial Create form. The second ( [HttpPost] )version handles the form post. The second Create method (The HttpPost version)calls ModelState.IsValid to check whether the movie has any validation errors. Calling this methodevaluates any validation attributes that have been applied to the object. If the object has validationerrors, the Create method re-displays the form. If there are no errors, the method saves the new movie

in the database. In our movie example, the form is not posted to the server when there are validationerrors detected on the client side; the second Create method is never called . If you disableJavaScript in your browser, client validation is disabled and the HTTP POST Create methodcalls ModelState.IsValid to check whether the movie has any validation errors.You can set a break point in the HttpPost Create method and verify the method is never called, clientside validation will not submit the form data when validation errors are detected. If you disable JavaScriptin your browser, then submit the form with errors, the break point will be hit. You still get full validationwithout JavaScript. The following image shows how to disable JavaScript in Internet Explorer.

104

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 105/115

105

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 106/115

The following image shows how to disable JavaScript in the FireFox browser.

The following image shows how to disable JavaScript in the Chrome browser.

106

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 107/115

Below is the Create.cshtml view template that you scaffolded earlier in the tutorial. It's used by the actionmethods shown above both to display the initial form and to redisplay it in the event of an error.

@model MvcMovie.Models.Movie@{

ViewBag.Title = "Create";}<h2>Create </h2> @using (Html.BeginForm()){

@Html.AntiForgeryToken()<div class ="form-horizontal" >

107

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 108/115

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 109/115

Open the Movie.cs file and examine the Movie class.The System.ComponentModel.DataAnnotations namespace provides formatting attributes in additionto the built-in set of validation attributes. We've already applied a DataType enumeration value to therelease date and to the price fields. The following code shows the ReleaseDate and Price propertieswith the appropriate DataType attribute.

[ DataType ( DataType . Date )]public DateTime ReleaseDate { get ; set ; }

[ DataType ( DataType . Currency )]public decimal Price { get ; set ; }

The DataType attributes only provide hints for the view engine to format the data (and supply attributessuch as <a> for URL's and <a href="mailto:EmailAddress.com"> for email. You can usethe RegularExpression attribute to validate the format of the data. The DataType attribute is used tospecify a data type that is more specific than the database intrinsic type, theyare not validation attributes. In this case we only want to keep track of the date, not the date and time.The DataType Enumeration provides for many data types, such as Date, Time, PhoneNumber, Currency,EmailAddress and more. The DataType attribute can also enable the application to automatically providetype-specific features. For example, a mailto: link can be created for DataType.EmailAddress , and adate selector can be provided for DataType.Date in browsers that support HTML5. The DataType attributes emits HTML 5 data- (pronounced data dash ) attributes that HTML 5 browserscan understand. The DataType attributes do not provide any validation.DataType.Date does not specify the format of the date that is displayed. By default, the data field isdisplayed according to the default formats based on the server's CultureInfo . The DisplayFormat attribute is used to explicitly specify the date format:

[ DisplayFormat ( DataFormatString = "{0:yyyy-MM-dd}" , ApplyFormatInEditMode = true )]public DateTime EnrollmentDate { get ; set ; }

The ApplyFormatInEditMode setting specifies that the specified formatting should also be applied whenthe value is displayed in a text box for editing. (You might not want that for some fields — for example,for currency values, you might not want the currency symbol in the text box for editing.)You can use the DisplayFormat attribute by itself, but it's generally a good idea to usethe DataType attribute also. The DataType attribute conveys the semantics of the data as opposed tohow to render it on a screen, and provides the following benefits that you don't get with DisplayFormat :

The browser can enable HTML5 features (for example to show a calendar control, the locale-appropriate currency symbol, email links, etc.).

By default, the browser will render data using the correct format based on your locale . The DataType attribute can enable MVC to choose the right field template to render the data

(theDisplayFormat if used by itself uses the string template). For more information, seeBrad Wilson's ASP.NET MVC 2 Templates . (Though written for MVC 2, this article still applies to thecurrent version of ASP.NET MVC.)

If you use the DataType attribute with a date field, you have to specify the DisplayFormat attribute alsoin order to ensure that the field renders correctly in Chrome browsers. For more information, see thisStackOverflow thread . Note: jQuery validation does not work with the Range attribute and DateTime . For example, the followingcode will always display a client side validation error, even when the date is in the specified range:

[ Range ( typeof ( DateTime ), "1/1/1966" , "1/1/2020" )]

109

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 110/115

You will need to disable jQuery date validation to use the Range attribute with DateTime . It's generallynot a good practice to compile hard dates in your models, so using the Range attribute and DateTime isdiscouraged.

The following code shows combining attributes on one line:

public class Movie {

public int ID { get ; set ; }[ Required , StringLength ( 60, MinimumLength = 3)]public string Title { get ; set ; }[ Display ( Name = "Release Date" ), DataType ( DataType . Date )]public DateTime ReleaseDate { get ; set ; }[ Required ]public string Genre { get ; set ; }[ Range ( 1, 100 ), DataType ( DataType . Currency )]public decimal Price { get ; set ; }[ Required , StringLength ( 5)]public string Rating { get ; set ; }

}

In the next part of the series, we'll review the application and make some improvements to theautomatically generated Details and Delete methods.

Examining the Details and Delete MethodsBy Rick Anderson |October 17, 2013

In this part of the tutorial, you'll examine the automatically generated Details and Delete methods.

Examining the Details and Delete MethodsOpen the Movie controller and examine the Details method.

110

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 111/115

public ActionResult Details ( int ? id){

if (id == null ){

return new HttpStatusCodeResult ( HttpStatusCode . BadRequest );}Movie movie = db. Movies . Find (id);if (movie == null ){

return HttpNotFound ();}return View(movie);

}

111

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 112/115

The MVC scaffolding engine that created this action method adds a comment showing a HTTP requestthat invokes the method. In this case it's a GET request with three URL segments, the Movies controller,the Details method and a ID value.Code First makes it easy to search for data using the Find method. An important security feature builtinto the method is that the code verifies that the Find method has found a movie before the code tries to

do anything with it. For example, a hacker could introduce errors into the site by changing the URLcreated by the links from http://localhost:xxxx/Movies/Details/1 to somethinglike http://localhost:xxxx/Movies/Details/12345 (or some other value that doesn't represent an actualmovie). If you did not check for a null movie, a null movie would result in a database error.Examine the Delete and DeleteConfirmed methods.

// GET: /Movies/Delete/5 public ActionResult Delete ( int ? id){

if (id == null ){

return new HttpStatusCodeResult ( HttpStatusCode . BadRequest );

}Movie movie = db. Movies . Find (id);if (movie == null ){

return HttpNotFound ();}return View(movie);

}

// POST: /Movies/Delete/5 [ HttpPost , ActionName ( "Delete" )][ ValidateAntiForgeryToken ]public ActionResult DeleteConfirmed ( int id){

Movie movie = db. Movies . Find (id);db. Movies . Remove(movie);db. SaveChanges ();return RedirectToAction ( "Index" );

}

Note that the HTTP Get Delete method doesn't delete the specified movie, it returns a view of themovie where you can submit ( HttpPost ) the deletion.. Performing a delete operation in response to aGET request (or for that matter, performing an edit operation, create operation, or any other operation

that changes data) opens up a security hole. For more information about this, see Stephen Walther's blogentry ASP.NET MVC Tip #46 — Don't use Delete Links because they create Security Holes . The HttpPost method that deletes the data is named DeleteConfirmed to give the HTTP POST methoda unique signature or name. The two method signatures are shown below:

// GET: /Movies/Delete/5 public ActionResult Delete ( int ? id)

//

112

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 113/115

// POST: /Movies/Delete/5 [ HttpPost , ActionName ( "Delete" )]public ActionResult DeleteConfirmed ( int id)

The common language runtime (CLR) requires overloaded methods to have a unique parameter signature(same method name but different list of parameters). However, here you need two Delete methods -- onefor GET and one for POST -- that both have the same parameter signature. (They both need to accept asingle integer as a parameter.)

To sort this out, you can do a couple of things. One is to give the methods different names. That's whatthe scaffolding mechanism did in the preceding example. However, this introduces a small problem:ASP.NET maps segments of a URL to action methods by name, and if you rename a method, routingnormally wouldn't be able to find that method. The solution is what you see in the example, which is toadd the ActionName("Delete") attribute to the DeleteConfirmed method. This effectively performsmapping for the routing system so that a URL that includes /Delete/ for a POST request will findthe DeleteConfirmed method.Another common way to avoid a problem with methods that have identical names and signatures is to

artificially change the signature of the POST method to include an unused parameter. For example, somedevelopers add a parameter type FormCollection that is passed to the POST method, and then simplydon't use the parameter:

public ActionResult Delete ( FormCollection fcNotUsed, int id = 0){

Movie movie = db. Movies . Find (id);if (movie == null ){

return HttpNotFound ();}db. Movies . Remove(movie);db. SaveChanges ();return RedirectToAction ( "Index" );

}

SummaryYou now have a complete ASP.NET MVC application that stores data in a local DB database. You cancreate, read, update, delete, and search for movies.

113

8/18/2019 Getting Started With Mvc 5

http://slidepdf.com/reader/full/getting-started-with-mvc-5 114/115

Next StepsAfter you have built and tested a web application, the next step is to make it available to other people touse over the Internet. To do that, you have to deploy it to a web hosting provider. Microsoft offers free

web hosting for up to 10 web sites in a free Windows Azure trial account . I suggest you next follow mytutorial Deploy a Secure ASP.NET MVC app with Membership, OAuth, and SQL Database to a WindowsAzure Web Site . An excellent tutorial is Tom Dykstra's intermediate-level Creating an Entity FrameworkData Model for an ASP.NET MVC Application .Stackoverflow and the ASP.NET MVC forums are a greatplaces to ask questions. Follow me on twitter so you can get updates on my latest tutorials.Feedback is welcome.

114


Recommended