The running result is to generate a form.
Generally, form submission involves a strong type, so we usually need @ model MvcApp. controllers. userInfo command. Let's see if you use @ using (Html. beginForm () and Html. beginForm ();, Html. endForm.
We can find that BeginForm returns an MvcForm, while MvcForm must be as follows: public class MvcForm: IDisposable
It can be seen that the Dispose method of MvcForm is called after using:
Protected virtual void Dispose (bool disposing ){
If (! _ Disposed ){
_ Disposed = true;
_ Writer. Write ("</form> ");
// Output client validation and restore the original form context
If (_ viewContext! = Null ){
_ ViewContext. OutputClientValidation ();
_ ViewContext. FormContext = _ originalFormContext;
}
}
}
Here, the default value of _ disposed is false, and the value of _ writer is viewContext. Writer or httpResponse. Output indicates the current Output stream. Let's take a look at the EndForm:
Public static void EndForm (this HtmlHelper htmlHelper ){
HtmlHelper. ViewContext. Writer. Write ("</form> ");
HtmlHelper. ViewContext. OutputClientValidation ();
}
It can be seen that the Dispose methods of EndForm and MvcForm are equivalent.
Let's see how BeginForm is implemented,
Public static MvcForm BeginForm (this HtmlHelper htmlHelper ){
// Generates <form action = "{current url}" method = "post">... </form>
String formAction = htmlHelper. ViewContext. HttpContext. Request. RawUrl;
Return FormHelper (htmlHelper, formAction, forw.hod. Post, new RouteValueDictionary ());
}
Public static MvcForm BeginForm (this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary <string, object> htmlAttributes ){
String formAction = UrlHelper. GenerateUrl (null/* routeName */, actionName, controllerName, routeValues, htmlHelper. RouteCollection, htmlHelper. ViewContext. RequestContext, true/* Other */);
Return FormHelper (htmlHelper, formAction, method, htmlAttributes );
}
The FormHelper method here is relatively simple. Note that bool traditionalpoliccriptenabled = htmlHelper. ViewContext. ClientValidationEnabled &&! HtmlHelper. ViewContext. UnobtrusiveJavaScriptEnabled; here, ClientValidationEnabled and UnobtrusiveJavaScriptEnabled are both true by default, so traditionalpoliccriptenabled is false.
There is a GenerateUrl Method on it. This method is also very simple, and there are three key codes.
RouteValueDictionary mergedRouteValues = RouteValuesHelpers. MergeRouteValues (actionName, controllerName, requestContext. RouteData. Values, routeValues, includeImplicitMvcValues );
VirtualPathData vpd = routeCollection. GetVirtualPathForArea (requestContext, routeName, mergedRouteValues );
String modifiedUrl = PathHelpers. GenerateClientUrl (requestContext. HttpContext, vpd. VirtualPath );
Here we use the VirtualPath attribute of VirtualPathData.
There is a BeginRouteForm method in FormExtensions. This method is similar to the BeginForm method and skipped. Now let's take a look at ClientValidationEnabled and UnobtrusiveJavaScriptEnabled. Why is it true by default? These two attributes call the corresponding attributes of the ScopeCache instance, and the Get method of ScopeCache is used for obtaining ScopeCache. The Get method code is simple:
[Csharp] view plaincopyprint? Public static ScopeCache Get (IDictionary <object, object> scope, HttpContextBase httpContext ){
If (httpContext = null & System. Web. HttpContext. Current! = Null ){
HttpContext = new HttpContextWrapper (System. Web. HttpContext. Current );
}
ScopeCache result = null;
Scope = scope ?? ScopeStorage. CurrentScope;
If (httpContext! = Null ){
Result = httpContext. Items [_ cacheKey] as ScopeCache;
}
If (result = null | result. _ scope! = Scope ){
Result = new ScopeCache (scope );
If (httpContext! = Null ){
HttpContext. Items [_ cacheKey] = result;
}
}
Return result;
}
}
Public static ScopeCache Get (IDictionary <object, object> scope, HttpContextBase httpContext ){
If (httpContext = null & System. Web. HttpContext. Current! = Null ){
HttpContext = new HttpContextWrapper (System. Web. HttpContext. Current );
}
ScopeCache result = null;
Scope = scope ?? ScopeStorage. CurrentScope;
If (httpContext! = Null ){
Result = httpContext. Items [_ cacheKey] as ScopeCache;
}
If (result = null | result. _ scope! = Scope ){
Result = new ScopeCache (scope );
If (httpContext! = Null ){
HttpContext. Items [_ cacheKey] = result;
}
}
Return result;
}
}
How does ScopeStorage's CurrentScope attribute come from?
Public static IScopeStorageProvider CurrentProvider {
Get {return _ stateStorageProvider ?? _ Defastorstorageprovider ;}
Set {_ stateStorageProvider = value ;}
}
Public static IDictionary <object, object> CurrentScope {
Get {
Return CurrentProvider. CurrentScope;
}
}
The default value is StaticScopeStorageProvider's CurrentScope. By default, this attribute returns an IDictionary <object, object> instance with no members. The CurrentProvider here is a description by default. web. in the WebPages project, PreApplicationStartCode has the following ScopeStorage statement. currentProvider = new feature (); The AspNetRequestScopeStorageProvider function has such an ApplicationScope = new ApplicationScopeStorageDictionary (); the constructor of ApplicationScopeStorageDictionary contains public ApplicationScopeStorageDictionary (): this (new WebConfigScopeDictionary () {}, WebConfigScopeDictionary is enough for functions and has public WebConfigScopeDictionary (): this (WebConfigurationManager. ettings,
I wonder if you still remember that there is such a using (ScopeStorage. CreateTransientScope () {ExecuteCore ();} in the Execute method of ControllerBase ();}
Public static IDisposable CreateTransientScope (){
Return CreateTransientScope (new ScopeStorageDictionary (baseline: CurrentScope ));
}
Public static IDisposable CreateTransientScope (IDictionary <object, object> context ){
Var currentContext = CurrentScope;
CurrentProvider. CurrentScope = context;
Return new DisposableAction () => CurrentProvider. CurrentScope = currentContext); // Return an IDisposable that pops the item back off
}
Now we know what the CurrentProvider of IScopeStorageProvider is. The data implementation in the AspNetRequestScopeStorageProvider is obtained from the WebConfigurationManager. deleetmanager.
I think you should understand why this ClientValidationEnabled is true by default.