asp.net mvc源碼分析-BeginForm方法 和ClientValidationEnabled 屬性

來源:互聯網
上載者:User

在上篇文章asp.net mvc源碼分析-RenderAction和RenderPartial我們提到了一個常用的RenderAction方法,除了它我們還會經常遇到表單提交,這時我們通常會用到BeginForm。讓我們來看看你BeginForm是如何使用的

運行結果就是產生form表單

一般我們的表單提交都涉及到強型別,所以一般需要@model MvcApp.Controllers.UserInfo指令,那我們來看看你用@using (Html.BeginForm()) 和Html.BeginForm();、Html.EndForm();這兩種用法有什麼區別。

我們找到BeginForm返回的是一個MvcForm,而MvcForm的一定如下: public class MvcForm : IDisposable

可見使用using最後調用的是MvcForm的Dispose方法:

 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;
                }
            }
        }

這裡的_disposed預設是false,_writer是viewContext.Writer或則httpResponse.Output都表示當前的輸出資料流。那麼我們再來看看EndForm吧:

 public static void EndForm(this HtmlHelper htmlHelper) {
            htmlHelper.ViewContext.Writer.Write("</form>");
            htmlHelper.ViewContext.OutputClientValidation();
        }

可見EndForm和MvcForm的Dispose方法完全等價。

我們來看看你BeginForm是如何?的,

 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, FormMethod.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 /* includeImplicitMvcValues */);
            return FormHelper(htmlHelper, formAction, method, htmlAttributes);
        }

這裡的FormHelper方法比較簡單,裡面有一句需要注意一下  bool traditionalJavascriptEnabled = htmlHelper.ViewContext.ClientValidationEnabled && !htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled;這裡ClientValidationEnabled 和UnobtrusiveJavaScriptEnabled預設都是true,所以traditionalJavascriptEnabled 為false。

上面有個GenerateUrl方法,這個方法也很簡單,關鍵代碼就3句。

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);

看看這裡我們就用到了VirtualPathData的VirtualPath屬性了。

在FormExtensions中有一個BeginRouteForm方法,該方法的使用方式和BeginForm方法差不多,就跳過了。現在我們來看看ClientValidationEnabled 和UnobtrusiveJavaScriptEnabled預設為什麼是true?這2個屬性都是調用ScopeCache執行個體的對應屬性,而擷取ScopeCache時通過ScopeCache的Get方法來完成的。該Get方法代碼很簡單:

  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;            }        }

而ScopeStorage的CurrentScope屬性是又是怎麼來的了?

        public static IScopeStorageProvider CurrentProvider {
            get {  return _stateStorageProvider ?? _defaultStorageProvider; }
            set {   _stateStorageProvider = value; }
        }
        public static IDictionary<object, object> CurrentScope {
            get {
                return CurrentProvider.CurrentScope;
            }
        }
預設來自於StaticScopeStorageProvider的CurrentScope,該屬性預設返回的是一個沒有成員的IDictionary<object, object>執行個體。那麼這裡的CurrentProvider 預設是個說明東西了,在System.Web.WebPages項目中的PreApplicationStartCode有這麼一句  ScopeStorage.CurrentProvider = new AspNetRequestScopeStorageProvider(); 在AspNetRequestScopeStorageProvider的夠著函數有這麼一句ApplicationScope = new ApplicationScopeStorageDictionary(); 在ApplicationScopeStorageDictionary的建構函式中有    public ApplicationScopeStorageDictionary()  : this(new WebConfigScopeDictionary()) {   },WebConfigScopeDictionary的夠著函數又有    public WebConfigScopeDictionary()  :this(WebConfigurationManager.AppSettings) {  }這麼一句.

不知道大家是否還記得在ControllerBase的Execute方法中有這麼一句 using (ScopeStorage.CreateTransientScope()) { ExecuteCore(); }

public static IDisposable CreateTransientScope() { 
return CreateTransientScope(new ScopeStorageDictionary(baseScope: 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

        }

現在我們知道了IScopeStorageProvider 的CurrentProvider是什麼東西了,是一個AspNetRequestScopeStorageProvider,裡面的資料有一部分從WebConfigurationManager.AppSettings這裡取出來的。

我想大家現在該明白為什麼這個ClientValidationEnabled 預設是true了吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.