@using (Html.BeginForm())和@{Html.BeginForm();}@{Html.EndForm();}對比


image

這樣寫報錯

<body>
    @using (Html.BeginForm())
    {
        form主體1
    }
    @{Html.BeginForm();}
        form主體2
    @{Html.EndForm();}
</body>

這樣寫正確

<body>
    @using (Html.BeginForm())
    {
        <div>form主體1</div>
    }
    @{Html.BeginForm();}
        form主體2
    @{Html.EndForm();}
</body>

原因后續補上.

 

使用@:text標簽

在代碼塊中,要么是C#代碼,要么是HTML標簽,不能直接寫純文字,純文字須包裹在HTML標簽內。但如果需要在代碼塊中直接輸出純文字而不帶HTML標簽,則可以使用@:標簽,在代碼塊中輸出純文本文字非常有用。如下代碼所示:

 

@if (Model.Price > 5M)

{

@Model.Name@:太貴了 。

<br />

@: @@:后面可以是一行除@字符以外的任意文本,包括<、>和空格,怎么寫的就怎么輸出。

<br />

@: 如果要輸出@符號,當@符號前后都有非敏感字符(如<、{、和空格等)時,可以直接使用@符號,否則需要使用兩個@符號。

}

注意@符號的使用。上面代碼運行效果如下:
clip_image002

使用@:標簽在代碼塊中輸出一行不帶html標簽的文本非常方便,但如果需要在代碼塊中輸出續或不連續的多行純文本,則使用text標簽較為方便,如下代碼所示:

@if (Model.Price > 5M)

{

<text>

名稱:<b>@Model.Name</b><br />

分類:<b>@Model.Description</b><br />

價錢:<b>@Model.Price</b><br />

<pre>

測試行一: <a>aaaa</a>

測試行二: @@ fda@aaa

</pre>

</text>

}

運行結果:
clip_image003

 

 

參考內容:

\
運行結果就是生成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方法代碼很簡單:

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

而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了吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM