BIT 286: Web Applications Lecture 10: Thursday, February 5, 2015 ASP.Net Form Submission 2 Examining Edit Form submission http://www.asp.net/mvc/overview/gettingstarted/introduction/examining-the-edit-methods-and-edit-view Controller method for first time (non-POST) visit: 3 Examining Edit: First Visit: Controller Notice how similar this looks to the Details page // 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); } Edit.cshtml 4 Examining Edit: First Visit: the View The rendered HTML @model MVCBasics.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> <h2>Edit</h2> @using (Html.BeginForm()) <form action="/Movies/Edit/1" method="post"> { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Movie</h4> <hr /> <input name="__RequestVerificationToken " type="hidden" value="iYr5boxkobMxM9Ad4T9zZ_AcVmdy7Pv6k5Z_mhyIbS gN3P6uv3G8oheeQ2u_IrBLmdyYyX bMRs5ECU4wrE_g5s70fRyQP5pKg4T RC1p_mE1" /> <div class="form-horizontal"> <h4>Movie</h4> 5 XSRF/CSRF Cross-Site Request Forgery Good explanation at ASP.Net Essentially, you visit Web Site #1 and legitimately log in The browser keeps the authentication info until the web browser process exits The browser also automatically re-sends the authentication info whenever you visit that site. This is very convenient when you’re on Web Site #1 You go to Web Site #2, which attempts to access Web Site #1 E.g., Web Site #2 creates it’s own form, whose action is to submit to Web Site #1 Your browser conveniently re-sends the authentication info along with the form Web Site #2 can now act as you on Web Site #1 This is the ‘cross site’ part I’ve heard that this can be done even by ads served to you on pages you trust. I’d be surprised if Google, MS, etc, would let this happen, but you don’t control which adserving arrangements are used by the websites you visit. 6 XSRF/CSRF Cross-Site Request Forgery We can combat this with anti-forgery tokens Web Site #1 will generate a random number and put it into a hidden field in the form it sends to you (This is the anti-forgery token) Web Site #1 will check (when you post that form back) that the number in your form matches the one it sent you This prevents Web Site #2 from making up it’s own form Because it can’t generate the same random numbers as Web Site #1 7 Edit.cshtml <div class="form-horizontal"> <h4>Movie</h4> <hr /> Examining Edit: First Visit: the View @Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.ID) <div class="form-group"> @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" }) </div> </div> The rendered HTML <input data-val="true" data-valnumber="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="1" /> <div class="form-group"> <label class="control-label col-md-2" for="Title">Title</label> <div class="col-md-10"> <input class="form-control text-box single-line" id="Title" name="Title" type="text" value="Movie Title #1" /> <span class="fieldvalidation-valid text-danger" datavalmsg-for="Title" data-valmsgreplace="true"></span> </div> </div> Controller method for POST visit: 8 [HttpPost] // Only used for HTTP POST requests; HTTP Get is the default [ValidateAntiForgeryToken] // checks @Html.AntiForgeryToken() from View Examining Edit: POSTing the edits: Controller 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); } 9 Examining Edit: POSTing the edits Controller method for POST visit: [Bind(Include = "ID,Title,ReleaseDate,Genre,Price")] Movie movie) public ActionResult Edit( { /* Snip */ Include is the list of properties (data fields) to extract from the form Other fields are left blank in the movie object, even if they’re present in the form These data fields are filled in for you, automatically, on the movie object. 10 Security Risk: Overposting Normally you’d never put extra properties in your form…. …but hackers might download & save a copy and add stuff. For example, let’s say that the ‘Edit User’s Unimportant Account Info’ page normally just lets you update your firstname, last name, nickname, picture, etc, etc. But does NOT let you change the password You can go to that page, select ‘Save As’ in your browser, edit the form locally to also include a new password for the user, and then submit the form. If you blindly bound the movie object to ALL fields, and saved the whole object you’d update the password The ‘Include’ attribute allows you to only bind to some of the fields Also a good explanation at MSDN 11 Search http://www.asp.net/mvc/overview/gettingstarted/introduction/adding-search 12 Tutorial Outline Adding a search term ‘Search’ Param added to controller method LINQ query Important details about when this actually gets executed Goofy re-use of ‘id’ parameter for a nicer URL Adding a form Want to use GET, not POST (GET = retrieve, POST = change DB state) Decorate form so that it’ll get, not post Filtering by genre Querying for the list of genres Handling a GET’d search Updating the view to support the above public ActionResult Index(string searchString) 13 { var movies = from m in db.Movies Adding a parameter select m; This is LINQ This defines, but does NOT execute the query if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); This modifies the definition of the query } LINQ actually maps to SQL (as opposed to doing a SELECT * and then filtering the results in C# 14 My opinion: using ‘id’ as the parameter This seems goofy – it does produce a nice URL, but the controller code is kinda ugly (notice how they promptly renamed the parameter) 15 Adding a New Field http://www.asp.net/mvc/overview/gettingstarted/introduction/adding-a-new-field 16 Outline 17 Adding Validation http://www.asp.net/mvc/overview/gettingstarted/introduction/adding-validation 18 Examining the Details and Delete Methods http://www.asp.net/mvc/overview/gettingstarted/introduction/examining-the-details-and-delete-methods 19 Topics For Later Account Management: http://azure.microsoft.com/en-us/documentation/articles/web-sitesdotnet-deploy-aspnet-mvc-app-membership-oauth-sql-database/ Entity Framework: Foreign keys How does it handle objects with references to other objects? JavaScript/jQuery integration?