It is hard to understand that when WebForm appears, the program will be excited in the world. In fact, I switched to MVC only after Razor appeared.
WebForm
With the rise of ASP. net mvc, WebForm has become yellow yesterday, but I still want to say a few words for WebForm.
It is hard to understand that when WebForm appears, the program will be excited in the world. In fact, I switched to MVC only after Razor appeared, because I was afraid of seeing <%>. I have participated in a project to upgrade ASP to ASP. NET. the messy code in ASP makes my eyes sour and swollen, so I can remember it all my life!
The final html generated by WebForm may be bloated and ugly, but its code page (. aspx) is quite refreshing and beautiful.
Since we have all decided to adopt MVC, we don't need to talk about the shortcomings of WebForm. However, we should study hard and learn from its excellent advantages. these are also used in MVC development:
• The rendering and page logic are separated. In WebForm, because its framework originally explicitly distinguishes aspx and aspx. cs, we will not worry about this most of the time. But in MVC, we can easily use ViewModel data in the view to perform operations and blur the logical boundaries between the Controller and the View. We will explain this problem in detail during CurrentUser.
• Good page encapsulation and reuse. When we find that the pages are repeated and similar "parts", we will surely think of reuse. This is the time to test our skill. I would like to mention one thing I think of first: sometimes we would rather repeat them than reuse them! This is my tears. It should be in the comments page of the home project of entrepreneurship. I tried to reuse all comments in PartialView. The results were terrible, and I finally gave up reuse, but it was a sea of sky. In fact, a better example is the GridView and Repeater in WebForm. In practice, the Repeater in simple encapsulation is more popular, while the "big and complete" GridView is rarely used. Therefore, encapsulation and reuse have a problem.
RouteTest
The Route function is a major breakthrough of MVC and an important defect. Because there is no good automatic check mechanism, it is very error-prone in the actual development process! I believe that all those who have experience in development have some experiences. sometimes, when I get an error for a long time: no View can be found, no Action can be found, and a spelling error can be found. sometimes a RouteConfig is added, after a while, other colleagues shouted, "test! It turns out that your settings overwrite my settings. I checked it all afternoon !"
It is a pity to waste time in these places, so our solution to this problem is to use unit testing and introduce RouteTest in the PCTest project. Each time you add RouteConfig and run the unit test: if you can pass the test without affecting others, you will be OK.
This is the most successful example of unit testing at the UI layer of our project. The biggest benefit of MVC is that it can be tested. unit tests should be widely introduced elsewhere, but I am lazy, in addition, the sealed limitation of HttpContext also limits the implementation of unit testing (MVC 5 should solve this problem). Therefore, the unit testing at the UI layer has not yet been expanded. However, it is estimated that this work will have to be done sooner or later. now there are some problems that are complicated and easy to miss in manual testing.
URL/View level
Another problem with MVC is that it is difficult for a View to be organized by multiple layers. For example, the View I may need is organized as follows:
Note that the Controller also has hierarchical relationship settings. I always think this will be clearer and more clean, but if the MVC framework cannot be "hierarchical ". If the View must be organized in layers like this, all the paths of the View must be written in the Action, for example:
C # code
- Public class LogController: Controller
- {
- //
- // GET:/Account/Log/On
- Public ActionResult On ()
- {
- Return View ("~ /Views/Account/Log/On. cshtml ");
- }
- }
It is too troublesome to configure RouteConfig. Therefore, we should try our best to follow the MVC framework. starting from the URL design, we should try to adopt the/{Controller}/{action}/{route-parameter} style, view is also placed in the corresponding folder of Contoller.
Partial/ChildAction/EditorTemplate
When we need to reuse some "page fragments", we are faced with the above options. There are a lot of cutting-in points. we only use our projects to extract the most distinctive and easily identifiable features and directly describe their use scenarios:
The first is EditorTemplate. It has the most obvious characteristics and is related to Post. That is, when the data of a "page segment" needs to be Post back to the server, we must use EditorTemplate. if EditorTemplate is not used, ViewModel data cannot be returned. Why? It is related to the ViewModel binding mechanism of MVC. when the html control in EditorTemplate is rendered, the prefix of the parent Model is added to its name, so that MVC can automatically parse post data and bind it to the ViewModel.
If "page fragment" does not require POST, it is only responsible for rendering. what should I do? Our principle is:
• If the "page fragment" does not need to interact with the server, all required data can be obtained from the parent Model and Partial is used;
• Otherwise, if the "page fragment" says the required data still needs to be obtained from the server, ChildAction is the only option.
HtmlHelper
In addition to the reuse of the preceding page fragments, you can also customize a "page fragment" rendering method by creating HtmlHelper extension methods. This method is generally an alternative to PartialView. we usually take "very small" (such as a link or a drop-down list) for "a lot of use" (or even cross-project) html snippets can be encapsulated with HtmlHelper.
AJAX
By observing our actions, we can find that the Action we provide for Ajax is always the returned ActionResult, rather than the "more advanced" WebApi mechanism (directly returning simple types such as int ). This is mainly because we use the SessionPerRequest mechanism (mainly to improve performance). we make a Request use only one session (which can be simply understood as a database connection), that is:
1. when MVC obtains a Request and requires a session, the Service generates a session;
2. then, the generated session will be used throughout the Request process (similar to the "Singleton mode ");
3. when the Request ends, release the session and synchronize all changes to the database.
Okay. The key point here is when the Request is "ended "? We further define it as when the View is rendered, so we use the Filter mechanism to synchronize the database during OnResultExecuted (). The code is as follows: So even if Ajax calls, you must also go through a "View rendering completed" process to complete data synchronization.
UIDevService switchover
For foreground development, you do not need to connect to the background database. you only need to enter UIDEV when compiling the MVC project (if you want to actually connect to the database, use PROD), as shown below:
So how is this actually implemented?
In general, we borrowed the autofac class library to implement the so-called "Dependency Inversion"
Therefore, in the MVC Controller, we only use ServiceInterface, regardless of its specific implementation, as shown below:
C # code
- Private IAuthroizationService _ authService;
- Public AuthController (IAuthroizationService authService)
- {
- _ AuthService = authService;
- }
Finally, in Global. asax. cs, we use the condition compiler if... else to determine which Service implementation is used: ProdServiceModule or UIDevServicemodule.
C # code
- Void ResolveDependency ()
- {
- Var builder = new ContainerBuilder ();
- Builder. RegisterControllers (Assembly. GetExecutingAssembly ());
- Builder. RegisterFilterProvider ();
- # If PROD
- Builder. RegisterModule (new ProdServiceModule ());
- # Endif
- # If UIDEV
- Builder. RegisterModule (new UIDevServicemodule ());
- # Endif
- Container = builder. Build ();
- DependencyResolver. SetResolver (new AutofacDependencyResolver (container ));
- }
Finally, do not forget to add the following to ProdServiceModule. cs or UIDevServicemodule. cs when a new Service is introduced:
C # code
- Builder. RegisterType (). ();
This chapter is almost the same. In the next chapter, we will talk about CurrentUser and introduce our principle: how to divide logic (or responsibility) between View, Controller, Service, and ViewModel ).