If (ModelState. IsValid )? ActionFitlter is also a pitfall !, Modelstate. isvalid
This blog is really a dry job. It is estimated that there are still some "bumps", so videos and code are also provided. However, for those with a weak foundation, I am afraid I still have to add some basic knowledge on my own-I can't cover all of them in an article.
- Download video and code: Demo-Baidu cloud Disk
- Reference: Automatic ModelState validation in ASP. NET MVC ).
Origin
I forgot whether I mentioned it in the garden. I named it"Truncation Programming. The main purpose is to put simple, filtering conditions, and "non-trunk" logic at the beginning. For example, in ASP. net mvc Action, when processing POST, we usually need to perform server verification, so we can write like this:
[HttpPost] public ActionResult Send (MessageSendModel model) {# region Non-truncation writing // if (ModelState. isValid) // {// assume that a message is sent // Response. write ("message sent"); // return View (model); # endregion # region truncation programming // filter condition if (! ModelState. isValid) {return View (model);} // main program: Assume that a message Response is sent. write ("message sent"); return RedirectToAction ("Send"); # endregion}View Code
Using this method, we soon found a problem: if (! ModelState. IsValid) {return View (model);} is everywhere.
Is it a little bad? How do you get it?
ActionFilter
First of all, of course, it is ActionFilter: before the Action is executed, check with a Filter. Isn't it OK?
I think this is a good idea, but please note that you must ask why!Why can't others think of it?? -- How is this possible ?!
So, before you do it yourself, get into the habit of google/bing to see how others get it.
Sure enough, find a blog: Automatic ModelState validation in ASP. net mvc, which is exactly the same as what I think! \ (^ O ^ )/
Besides, he thinks better than me! I'm so excited ......
So here we get the first experience:Search for the wheel first..
I would like to open up another question,
English+Google= Great programmers.
For developers, at least for the current and foreseeable future,English is very importantIt is very important, and the importance cannot be emphasized too much. If you have any blog materials similar to Chinese, I didn't try it. However, according to my experience, Chinese documents are scarce compared to English documents.
UsageSearch EngineMany people think this is a "shameful behavior", but it is not. You must understand:Your goal is to solve the problemInstead of being brilliant, you have to keep everything in your mind and write everything on your own ...... Forget it. Many people may not accept it, and the length is limited. You can get started with what you know. It's useless to say what you don't know.
The simplest scenario
At first, the solution was relatively simple. I put the Code directly:
Public class ValidateModelStateAttribute: ActionFilterAttribute {public override void OnActionExecuting (ActionExecutingContext filterContext) {if (! ViewData. ModelState. IsValid) {filterContext. Result = new ViewResult ();}}}View Code
The difficulty is probably the reason: return View (); and filterContext. Result = new ViewResult (); are equivalent.
I think the root cause of this problem is still not understanding "Object-Oriented", which has always been lacking by programmers in the. NET camp.
Sometimes some people in the QQ group are confused. After chatting, I realized that he always put return View (); this is the meaning of "go to that View page", but cannot be understood as: This is a method, and an ActionResult object is returned. Do you understand what I mean? All actions are a method, a method that returns the ActionResult object. Then, the ASP. net mvc Framework finds the corresponding View based on this ActionResult object and renders it ). There is one more link in the middle, but this is not a "take off your pants and fart", it is very necessary, and a very "exquisite" architecture design.
In this way, you can assign values to filterContext. Result in the Filter to display the page. Of course, the biggest benefit of doing so is the "testability" of the UI Layer, which is a very complex topic, which is skipped here.
I would like to say one more thing: thanks to this student for asking questions and letting me know that as a beginner, those are difficult points. In other words, it is really difficult for me to receive some feedback when I have been playing live for so long!
However, there is a problem
If there is no bing (the tragedy of google cannot be said), I will definitely be here. However, Master is master, and Ben Foster thinks of another problem:
Suppose that the data on the page needs to be transmitted from the background for normal presentation, how do I assign values in the Filter and pass them to the View?
This is a bit dizzy, so I just made a Demo and used DropdownList as an example. The optional data of DropdownList is obtained from the background. Due to the "stateless protocol" feature of HTTP, POST cannot "inherit" the data obtained during GET. What should I do?
TempData
In many ways, Ben Foster's blog encapsulates a method that is called by GET and POST.
My previous project used TempData in MVC. For details about the two requests, see share data. In this way, if the data that can be selected is obtained from the database, you can reduce the number of queries and improve the performance slightly.
TempData is really a good thing. This is what I like. NET, It is very "considerate", it gives people the feeling that it is "always oriented to frontline developers", it knows what problems you may encounter when writing code, so that you can prepare a solution in advance.
Both ideas and implementations are simple: in GET, the data required by POST is stored in TempData; in POST, the data in TempData is retrieved (a forced conversion is required, because the data is stored as the Object type ).
The code will not be pasted, because this is not the final solution.
But in FilterAction, is it swollen?
You can do whatever you want in the Controller, but we need to "encapsulate" now. We need to solve this problem in the Filter!
Dumb. The key problem is that we need to verify the OnActionExecuting (before the Action is executed). At this time, the ViewModel of the Action is not generated. We can use ControllerBase. the value in ActionParameters, but the retrieved Object type, you do not know what type to convert it to (of course you can do it with reflection, but it is very complicated, you don't think it is necessary because of the complexity.) The same is true for TempData.
At this time, I will think of ViewState in ASP. NET WebForm. In those years, I think of it as a "performance killer" and write down it. The birth and prevalence of MVC is estimated to be very large (how big? I am talking about it.
But now MVC has no ViewState, so you have to handle it yourself. Haha, it's a bit "convenient" for WebForm development.
Expand, DateSet, Linq to SQL, Entity Framework ...... A series of technologies, once launched, are all loud and open. In fact, why? each has its own use, and each has its own application scenarios. What can it do without the specific business requirements?
Therefore, I have always stressed that software engineering and technology selection are based on solving problems. The problem varies widely, so the technology used cannot be uniform. In a single sentence, there is no silver bullet ".
PRG Mode
If it was me, I gave up now. However, Ben Foster provides a great solution:Use PRG Mode.
PRG is short for Post, Redirect, and Get, meaning that all POST requests are Redirect to GET actions, even if the returned result is actually the same page. The sample code is as follows:
[HttpPost] public ActionResult Send (MessageSendModel model) {// main program: Assume that a message Response is sent. write ("the message has been sent"); // Note: it is not return View () // 1, it is Redirect // 2. The Redirection Action has the same name as itself, both are Send return RedirectToAction ("Send ");}View Code
I am very pleased with our system architecture. At the beginning, it was built based on this principle. I was a little confused when I first came into contact with the PRG model, but I thought everyone would use it like this, and it seems that there is no harm, so I used it. Later I did, the convenience of this pattern is discovered again and again. This is another example of "logging ".
I remember what I said in the live broadcast: if there are many strange and insurmountable problems in the architecture, it is generally because you are not on the road.
The common practice model is the road that others have already taken. You follow the steps that others have taken. When encountering a problem, you can easily find a solution to the problem. You need to find your own solution. Generally, you may not want to find your own solution, well, most of them are just walking by themselves-it's really hard to find help in the desert mountains and mountains.
Ultimate Solution
The idea is:
- In the POST Filter of Action, if the verification fails, the ModelState is stored in TempData;
- Add a Filter to the GET of Aciton to retrieve the ModelState in TempData and Merge to your ModelState.
- Therefore, through Redirect, GET Action gets the error message
It is very clear. I can mix images and codes:
Core code:
/// <Summary> // Exports the current ModelState to TempData (available on the next request ). /// </summary> protected static void ExportModelStateToTempData (ControllerContext context) {context. controller. tempData [Key] = context. controller. viewData. modelState;} // <summary> // Populates the current ModelState with the values in TempData // </summary> protected static void ImportModelStateFromTempData (ControllerContext context) {var prevModelState = context. controller. tempData [Key] as ModelStateDictionary; context. controller. viewData. modelState. merge (prevModelState );}View Code
That's simple and perfect! Endless aftertaste.
In fact, return View (); In the POST Action is not a good practice.
In my project, I found this problem: when the return View () contains @ Html. action () is called. If you need to distinguish GET and POST, the ChildAction to which the POST belongs is entered. This is definitely not logical. (It's delicious! Watch the video while thinking about it ......)
Digress
After a day, I finally finished writing.
I am tired of writing this article. I feel tired of writing this article than the 90-minute video. No wonder there are no documents for many open-source projects now, so I am directly playing the video ......
Finally, let's talk about "Help together". Now it's a lot better than the original Qianyi version. Some people are angry when they ask questions, however, the popularity is far from enough. According to the voting results in the QQ group, the main focus should be on promotion.
I have been promoting it for several days, but it has some effect, but sorry, my mom! This promotion is more tiring than writing this blog. Why?
I won't talk about this in the garden. "Drinking wine to friends, poetry to people will sing", the blog will only talk about technology in the future, this is also welcome to the blog Park. If you want to talk about programming, you are welcome to join the QQ group:
179742319 (paid into the group to grab red packets), 312423951 (verified into the group)
And public accounts:Let's help together.
Thank you for your comments
@ Code-based food:
If you use the PRG solution, you cannot meet your requirements: "re-present the submitted data for modification ". To meet this requirement, you can only return View (model) in POST; the model carries the previous data.
@ Stoneniqiu:
The advantage of this solution is not to "reduce" The amount of code, but to solve the null exception caused by return View (); in POST at the architecture level.