ASP.NET MVC 5 - Verify Edit Method and Edit View

original
2014/06/11 12:00
Reading number 248

In this section, you will verify the Edit action methods and views generated by the movie controller. But first, the point code will be modified to make the Release Date attribute look better. open Models \ Movie. cs File, and add the highlighted line as follows:

 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 ; } } }

In the next tutorial, we will discuss DataAnnotations Display Property indicates the name of the field to be displayed (in this example, "Release Date" replaces "ReleaseDate"). DataType Property is used to specify the type of data. In this example, it is a date, so the time details stored in this field will not be displayed. DisplayFormat Property has a bug in Chrome browser: the rendered date format is incorrect.

Add/Movies to the browser address bar and browse to the Movies page. And enter edit (Edit) Page.

 clip_image002

Edit (Edit) Links are created by Views\Movies\Index.cshtml view

In Html.ActionLink Method

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

 clip_image002[4]

Html The object is a helper, which is displayed in the System.Web.Mvc.WebViewPage Exposed on the base class. ActionLink It is a helper method to dynamically generate HTML hyperlink links to operation methods in the Controller. ActionLink The first parameter of the method is the link text you want to render (for example, <a>Edit Me</a> )。 The second parameter is the name of the operation method to be called (in this case, the Edit method). The last parameter is a Anonymous object anonymous object ), used to generate routing data (in this example, the ID is 4).

The link generated in the above figure is http://localhost:xxxxx/Movies/Edit/4 Default route (in App_Start\RouteConfig.cs ) uses the URL matching mode: {controller}/{action}/{id} Therefore, ASP.NET will http://localhost:xxxxx/Movies/Edit/4 Convert to Movies In controller Edit Operation method, parameter ID A request equal to 4. see App_Start\RouteConfig.cs The following code in the file.

MapRoute The method is to use HTTP request routing to find the correct controller and action method, and provide optional ID parameters. MapRoute Method is also used by HtmlHelpers as ActionLink The controller, operation method and any routing data of to generate URL.

 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 use QueryString to pass the parameters of the operation method. For example, URL: http://localhost:xxxxx/Movies/Edit?ID= three The parameter will also be ID The request for 3 is passed to Movies Controller's Edit Operation method.

 clip_image004

open Movies controller. Two as shown below Edit Operation method.

 // GET: /Movies/Edit/5 public ActionResult Edit( 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/Edit/5 // To protect from overposting attacks, please enable the specific properties you want 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); }

Note that the second Edit The operation method is as follows HttpPost Property. This property specifies Edit Method, which is only called by POST requests. You can set HttpGet Property is applied to the first edit method, but this is unnecessary because it is the default property. (The operation method will be implicitly specified as HttpGet Property as the HttpGet Method.) Binding( Bind )Attributes are another important security mechanism that can prevent hacker attacks (from over posting data to your model). You should only include the bind attribute attribute that you want to change. You can read about overposting security note We will use the simple model in this tutorial, and bind all data in the model. ValidateAntiForgeryToken Property is used to prevent forged requests and pair @ Html AntiForgeryToken () File( Views\Movies\Edit.cshtml ), as shown in the following figure, part of the view file is being edited:

 @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 > </ div >

@Html. AntiForgeryToken() generates a hidden form, and the anti-counterfeiting token must match the Edit method of the Movies controller. In my tutorial XSRF/CSRF Prevention in MVC , you can read more about cross site request forgery (also known as XSRF or CSRF).

HttpGet Edit Method will get the movie ID parameter and find the movie using Entity Framework Find Method and return to the editing view of the selected movie. If called without parameters Edit Method, the ID parameter is specified as Default Fatal Frame. If a movie cannot be found, return HttpNotFound When scaffolding automatically creates an edit view, it will view Movie Class and create a <label> and <input> Element of. The following example is an edit view automatically created by visual studio scaffolding:

 @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 > </ div > < div class ="form-group" > @Html. LabelFor(model => model. ReleaseDate, new { @class = "control-label col-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") }

Note that the view template has @model MvcMovie.Models.Movie Which specifies that the model type expected by the view is Movie

The code automatically generated by scaffolding uses Helper Methods. Html.LabelFor Displays the name of the field ("Title", "ReleaseDate", "Genre", or "Price"). Html.EditorFor Used to render HTML <input> Element. Html.ValidationMessageFor Used to display any validation messages associated with this property.

Run the application and browse the URL, /Movies single click Edit Links. View the page source code in the browser. The elements in the HTML Form are as follows:

 < 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"  /> < 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 ="The field Release Date must be a date." data-val-required ="The Release Date field is required." 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 ="The field 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 >

cover <form> Included in HTML elements <input> The element will be sent to the<form> action URL set by property: /Movies/Edit single click Save Button, the data from will be sent to the server. The second line is displayed or hidden XSRF Via @ Html The token generated by the AntiForgeryToken() call.

Process POST request

The following code shows Edit Operating method HttpPost handle:

 [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); }

ASP.NET MVC model binder

Receive the data posted by the form, and transform the received Movie request data to create a Movie Object. ModelState.IsValid Method is used to verify whether the submitted form data can be used to modify (edit or update) a Movie Object. If the data is valid movie data, it will be saved to the Movies aggregate (MovieDBContext Instance). By calling MovieDBContext Of SaveChanges Method, the new movie data will be saved to the database. After the data is saved, the code will redirect the user to MoviesController Class Index The page will display the movie list, including the update just made.

Once the client validation determines that the value of a field is invalid, an error message appears. If JavaScript is disabled, there will be no client verification, but the server will detect that the returned value is invalid, and the value and error message in the form will be displayed again. Later in this tutorial, we verify a more detailed review. Edit.cshtml In the view template Html.ValidationMessageFor Helper will be used to display the corresponding error message.

 clip_image006

All HttpGet methods follow a similar pattern. They get a movie object (or an object list, such as the Index in this case) and pass the model data to the view. The Create method passes an empty movie object to the Create view. All create, edit, delete methods, or other methods: use HttpPost overload methods to modify data. Modifying data in the HTTP GET method poses security risks, such as blog posts ASP.NET MVC Tip #46 � Don’t use Delete Links because they create Security Holes Modifying data in the HTTP GET method also violates HTTP best practices and REST Schema architecture, indicating that GET requests should not change the state of your application. In other words, executing the GET operation should be safe, without any side effects, and will not modify your persistent data.

If your computer is set in the US English language, you can skip this section and go directly to the next tutorial.

be careful In order for jQuery to support the validation of non English regions using commas, you need to set commas (",") to represent decimal points. You need to introduce globalize.js And you also need to specify cultures/globalize.cultures.js Document (address: https://github.com/jquery/globalize )You can use the Globalize.parseFloat You can install non English jQuery verification and plug-ins from NuGet. (If you are using an English locale, do not install Globalize.)

1. On Tools( Tools Menu, click Library Package Manager( Library Package Manager , Select Solution Package Manager Manage NuGet Packages for Solution .
 clip_image008

2. On the left panel, select Online Library Online See the figure below)

3. On Search Installed Libraries Search Installed packages ), Enter Globalize search
 clip_image010
Click Install( Install ) . JavaScript script \jquery.globalize\globalize.js The file will be added to your current project script \jquery.globalize\cultures\ The bottom of the folder will contain many JavaScript files of different cultures

Note: It is estimated to take 5 minutes to install this package (depending on your network speed)

The following code shows the Views Movies Edit.cshtml view under "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> $.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[ zero ] && val <= param[ one ]); } }); </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 script download, see my tutorial Bundling and Minification For more information, ASP.NET MVC 3 Internationalization and ASP.NET MVC 3 Internationalization - Part 2 (NerdDinner)

As a temporary solution, if you cannot verify the current regional settings, you can force your computer to use US English, or you can disable JavaScript in the browser. To force your computer to use American English, you can add the globalization settings in the project root directory Web.config file.

The following code demonstrates the global culture setting of American English.

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

In the next tutorial, we will implement the search function.

Add a Search Method and a Search View

In this section, you will add an Index operation method that allows you to search for movies by genre or name.

Upgrade Index Form

We start to update the Index method in the existing MoviesController class of the method. The codes are as follows:

 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 movies:

 var movies = from m in db.Movies select m;  If the searchString parameter contains a string, you can use the following code to modify the search string to be filtered by movie query: if (! String.IsNullOrEmpty(searchString)) { movies = movies. Where(s => s.Title.Contains(searchString)); }

above s => s.Title Code is a Lambda expression Lambda is method based LINQ Query, such as the above where query. The standard query parameter operator method is used in the above code. When defining a LINQ query or modifying query conditions, such as calling Where or OrderBy Method, no LINQ query is executed. On the contrary, query execution will be delayed, which means that expression calculation will be delayed until the actual value is obtained or the ToList method. In the Search example, Index.cshtml Execute the query in the view. For more information about deferred query execution, see Query Execution .

notes Contains The method is to run on the database instead of C # code. In the database, Contains Map to SQL LIKE , which is case insensitive.

Now you can implement the Index view and display it to the user.

Run this application and navigate to /Movies/Index Append a query string, such as URL? searchString=ghost。 The filtered movie will be displayed.

 clip_image012

If you change the ID of the Index method signature parameter, this ID parameter will match the placeholder of {id}. The default route set in the App_Start RouteConfig.cs file is defined as follows.

{controller}/{action}/{id}

The original Index method looks as follows:

 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 modified Index method looks 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); }

Now, you can search the route data (URL segment) through the title instead of using it as the query string value. The screenshot is as follows:

 clip_image014

However, you can't expect users to modify the URL every time they want to search for a movie. So now you will add a user interface to help them filter movies. If you change the Index method to test how to bind the ID parameter signature through the route, the Index method requires a string parameter 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); }  Open the file Views  Movies  Index.cshtml. In this code @ Html After ActionLink ("Create New", "Create"), add the following highlighted: @ 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 >

Html.BeginForm auxiliary will create a<form>label. When a user submits a form by clicking the "Filter" button, the Html.BeginForm assistant will cause the form to post to itself.

There is a good improvement in Visual Studio 2013: when displaying and editing view files. When you run the application to open the view file, Visual Studio 2013 will call the correct controller operation method to display the view.

 clip_image016

Open the Index view in Visual Studio (as shown in the picture above), click Ctr F5 or F5 to run the application, and then try to search for a movie.

 clip_image018

The HttpPost of this Index method is not overloaded. You don't need it, because this method does not change the application state, but only filters data.

You can add the following httppost Index method. In this case, the function call will match the HttpPost Index method, and the HttpPost Index method runs as shown in the following figure.

 [HttpPost] public string Index(FormCollection fc, string searchString) { return " < h3 > From [HttpPost]Index: " + searchString + " </ h3 > "; }

 clip_image020

However, even if you add this HttpPost The implementation of the Index method is actually limited. Imagine that you want to add bookmarks to a specific search, or you want to send search links to friends, who can click to see the same movie search list. Please note that the URL of the HTTP POST request is the same as that of the GET request (localhost: xxxxx/movie/Index) -- there is no search information in the URL. Now, the search string information is sent to the server as a form field value. This means that you cannot capture this search information in the URL to bookmark or send to friends.

The solution is to use overloaded BeginForm , which specifies that the POST request should be added to the search information of the URL and should be routed to the HttpGet version of the Index method. Replace the existing parameter free BeginForm Method, modified as follows

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

 clip_image022

Now when you submit a search, the URL will contain the query string of the search. Search will also request HttpGet Index operation method, even if you have a HttpPost Index method.

 clip_image024

Add search by movie genre

If you added HttpPost , please delete it immediately.

Next, you will add a feature that allows users to search for movies by genre. Replace the Index method with the following 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); 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 will accept an additional movieGenre Parameters. The first few lines of code will create a List Object to save the movie genre in the database.

The following code is a LINQ query that retrieves all genres from the database.

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

This code uses generics List Collectively AddRange Method to add all different genres to the in the collection. (Using Distinct Modifier, does not add duplicate genres -- for example, we added comedy twice in our example).

The code then ViewBag Object stores the data list of the genre. The SelectList object in ViewBag is used to store class data (such as movie genre), and then the data access category in the drop-down list box is a typical MVC applications method.

The following code shows how to check movieGenre Parameters. If it is not empty, the code further specifies the queried movie genre.

 if (! string .IsNullOrEmpty(movieGenre)) { movies = movies. Where(x => x.Genre == movieGenre); }

As mentioned earlier, the query data will not run on the database until the movie list iteration ends (just after the View and Index methods return).

The Index view adds tags to support searching movies by genre

stay Views\Movies\Index.cshtml Add Html DropDownList auxiliary method, in front of TextBox. The completed code is shown in the following figure:

 @model IEnumerable < MvcMovie .Models.Movie > @{ ViewBag.Title = "Index"; } < 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" >

The following code:

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

In ViewBag, the "movieGenre" reference is used as a key to search for IEnumerable<SelectListItem>in the DropDownList Operation method of ViewBag filling:

 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); }

Pre selected in the item list provided by the parameter "All". If we use the following code:

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

In our database, we have movies of "comedy" genre, and "comedy" will be pre selected in the drop-down list. Because we don't have a movie genre "All" and a SelectList of "All", we don't make any choices after we post back. The movieGene query string value is empty.

Run the application and browse /Movies/Index Try to search for genre, movie name, and select both criteria.

 clip_image026

In this section, you have created a search method and view, with which users can search through movie titles and genres. In the next section, you will see how to add a property to the Movie model and how to add an initial value setting item value, which will automatically create a test database. The above examples of creating search methods and views are to help people better master MVC knowledge. When developing MVC, development tools can also greatly help improve tool efficiency. Using ComponentOne Studio ASP.NET MVC   This lightweight control can meet all users' needs while greatly improving efficiency.

Expand to read the full text
Loading
Click to lead the topic 📣 Post and join the discussion 🔥
Reward
zero comment
zero Collection
zero fabulous
 Back to top
Top