ASP. net MVC pattern by re-introducing the lost, or at least has not been used for many years, making itself a simpler and "real" HTTP experience (original article: The ASP. net MVC pattern tends to lead itself into a more simplified and "true" HTTP experience by re-introducing patterns that have been lost, or at least, not followed in policyears ). One of the modes is post, redirect, get (PRG, it can "avoid secondary submission and allow web applications to use browser bookmarks and reload buttons for more intuitive performance" (Wikipedia ).
A common ASP. NET web form has the following mode:
1. http get of "Create. aspx"
2. http post of "Create. aspx"
3. Validation fails, "Create. aspx" is re-rendered
4. http post of "Create. aspx"
5. item is created, "Create. aspx" is re-rendered with confirmation message
The main problem with this PostBack mode is that when you click the refresh button of the browser in step 2 or step 2, the submitted data will be re-posted. Another problem still exists in step 1 is that it may even re-submit the created data ). Of course, you can handle these problems in the above steps, but ASP. NET web form treats them like this by default.
Put the same situation in ASP. net mvc. You can achieve the same way by presenting a "CREATE" view from your post action. For example:
1. http get of "/products/create", "CREATE" view is rendered
2. http post to "/products/submit"
3. Validation fails, "CREATE" view is rendered
4. http post to "/products/submit"
5. item is created, "Confirm" view is rendered
As you have noticed, ASP. NET web form has the same problems in ASP. net mvc. The really beautiful choice is that ASP. net mvc gives us more "freedom" to deal with this process. If we strictly follow the PRG pattern in ASP. net mvc, it should look like:
1. http get of "/products/create", "CREATE" view is rendered
2. http post to "/products/submit"
3. Validation fails, redirect to "/products/create", "CREATE" view is rendered
4. http post to "/products/submit"
5. item is created, redirect to "/products/confirm", "Confirm" view is rendered
As you can see, we have encountered problems in steps 1 and 2, and there will be no more problems. If a user presses the refresh button in any of the above steps, they will not see the validation information shown in the cute "wocould you like to resubmit the form data", and the page is only reloaded.
To achieve this, you need one controller, three action methods, and two views. Follow the steps below to implement this mode:
using System.Web.Mvc;public class ProductsController : Controller{ public ActionResult Create() { ... } public ActionResult Submit() { ... } public ActionResult Confirm() { ... }}
When you implement your create action, remember that verification may fail and you may need to re-display the form. Tempdata is the most suitable method in this case. It is implemented as follows:
public ActionResult Create(){ if (TempData["ErrorMessage"] != null) { ViewData["ErrorMessage"] = TempData["ErrorMessage"]; ViewData["Name"] = TempData["Name"]; ViewData["Price"] = TempData["Price"]; ViewData["Quantity"] = TempData["Quantity"]; } return RenderView();}
Next, you need to implement your submit action. The verification of user input data will be processed here. If the verification succeeds, the data will be saved and redirected to the confirm action. If verification fails, the form data will be saved to tempdata and redirected to create action. The simulated method also maintains View data when verification fails.
public ActionResult Submit(){ string error = null; string name = Request.Form["Name"]; if (string.IsNullOrEmpty(name)) { error = "Name is empty. "; } decimal price; if (!decimal.TryParse(Request.Form["Price"], out price)) { error += "Price is invalid. "; } int quantity; if (!int.TryParse(Request.Form["Quantity"], out quantity)) { error += "Quantity is invalid."; } if (!string.IsNullOrEmpty(error)) { TempData["ErrorMessage"] = error; TempData["Name"] = Request.Form["Name"]; TempData["Price"] = Request.Form["Price"]; TempData["Quantity"] = Request.Form["Quantity"]; return RedirectToAction("Create"); } else { return RedirectToAction("Confirm"); } }
Note that one of the most important items in the above example is that although I put all the data in form into a local variable, any conversion of price or quantity may fail, and I will use the above local variable (the red part above) to assign a value to tempdata... I will lose user input data. Therefore, it is always a smart idea to retrieve data from the form and store it directly into tempdata. Finally, you need to implement the confrim action:
Public actionresult confirm () {return renderview (); // If the parameter is null, a view with the same name as the action is displayed}
Now it is time to create our view:
~ /Views/products/create. aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Create.aspx.cs" Inherits="Views_Products_Create" %>
~ /Views/products/confirm. aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Confirm.aspx.cs" Inherits="Views_Products_Confirm" %>
That's it. You can get the code of the sample program in this mode from here.