带你读开源—ASP.NET_MVC(十一)

rufengit 2016-09-12 09:20:39
加精
上篇说到HtmlHelper,今天继续这个话题。
我们在自己建立的MVC项目中,随便打开一个.cshtml文件,找到一个HtmlHelper调用,例如:@Html.TextBox("CustomerName"),把光标放在Html上,按F12进入其定义,即代码段1中的语句【public new HtmlHelper<TModel> Html { get; set; }】。可见,@Html是HtmlHelper<TModel>类的一个实例,并且它是泛型类WebViewPage<TModel>的一个属性,由于.cshtml文件中的类继承于泛型类WebViewPage<TModel>,所以我们在Razor中可以直接使用@Html。
#region 程序集 System.Web.Mvc.dll, v4.0.30319
// C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Web.Mvc.dll
#endregion

using System;

namespace System.Web.Mvc
{
// 摘要:
// 表示呈现使用 ASP.NET Razor 语法的视图所需的属性和方法。
//
// 类型参数:
// TModel:
// 视图数据模型的类型。
public abstract class WebViewPage<TModel> : WebViewPage
{
// 摘要:
// 初始化 System.Web.Mvc.WebViewPage<TModel> 类的新实例。
protected WebViewPage();

// 摘要:
// 获取或设置 System.Web.Mvc.AjaxHelper 对象,该对象用于使用 Ajax 呈现 HTML 标记。
//
// 返回结果:
// 用于使用 AJAX 呈现 HTML 标记的 System.Web.Mvc.AjaxHelper 对象。
public AjaxHelper<TModel> Ajax { get; set; }
//
// 摘要:
// 获取或设置 System.Web.Mvc.HtmlHelper 对象,该对象用于呈现 HTML 元素。
//
// 返回结果:
// 用于呈现 HTML 元素的 System.Web.Mvc.HtmlHelper 对象。
public HtmlHelper<TModel> Html { get; set; }
//
// 摘要:
// 获取关联的 System.Web.Mvc.ViewDataDictionary 对象的 Model 属性。
//
// 返回结果:
// 关联的 System.Web.Mvc.ViewDataDictionary 对象的 Model 属性。
public TModel Model { get; }
//
// 摘要:
// 获取或设置一个字典,其中包含在控制器和视图之间传递的数据。
//
// 返回结果:
// 一个字典,其中包含在控制器和视图之间传递的数据。
public ViewDataDictionary<TModel> ViewData { get; set; }

// 摘要:
// 初始化 System.Web.Mvc.AjaxHelper、System.Web.Mvc.HtmlHelper 和 System.Web.Mvc.UrlHelper
// 类。
public override void InitHelpers();
//
// 摘要:
// 设置视图数据。
//
// 参数:
// viewData:
// 视图数据。
protected override void SetViewData(ViewDataDictionary viewData);
}
}

代码段 1

好了,现在我们进入泛型类HtmlHelper<TModel>的定义(代码段2),在这里可以看到两个大家肯定会感兴趣的属性,即ViewData和ViewBag。没错,这就是我们用于保持不同Http请求之间状态的那两个东东。
    public class HtmlHelper<TModel> : HtmlHelper
{
private DynamicViewDataDictionary _dynamicViewDataDictionary;
private ViewDataDictionary<TModel> _viewData;

public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
: this(viewContext, viewDataContainer, RouteTable.Routes)
{
}

public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
: base(viewContext, viewDataContainer, routeCollection)
{
_viewData = new ViewDataDictionary<TModel>(viewDataContainer.ViewData);
}

public new dynamic ViewBag
{
get
{
if (_dynamicViewDataDictionary == null)
{
_dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData);
}

return _dynamicViewDataDictionary;
}
}

public new ViewDataDictionary<TModel> ViewData
{
get { return _viewData; }
}
}

代码段 2

大家看ViewData和ViewBag属性的定义中用了new关键字,这是为什么?我们知道,关键字new除了常用来创建对象,还有一个作用是覆写父类的同名成员。由此可知,在泛型类HtmlHelper<TModel>的父类中,肯定也存在一个叫ViewData的成员。(注:本篇文章第二自然段中的语句【public new HtmlHelper<TModel> Html { get; set; }】也是这个意思。)我们进入泛型类HtmlHelper<TModel>的父类HtmlHelper,果然不出所料,确实有ViewData属性和ViewBag属性,见代码段3,其中ViewData是一个字典,ViewBag是一个动态类型(dynamic)。怎么样?这就是ViewData和ViewBag的庐山真面目。
  public ViewDataDictionary ViewData
{
get { return ViewDataContainer.ViewData; }
}
public dynamic ViewBag
{
get
{
if (_dynamicViewDataDictionary == null)
{
_dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewDataDictionary;
}
}

代码段 3

我们在HtmlHelper类中并没有找到常用的ActionLink、TextBox等Helper,回想一下上篇文章中关于ActionLink的分析,可以知道MVC框架内置的HtmlHelper是以扩展方法的形式进行定义的,这些扩展方法存在于MVC源码中的“System.Web.MVC/Html”路径下,名称包含Extention的类中,例如InputExtensions、LabelExtensions、ChildActionExtensions、FormExtensions、NameExtensions、PartialExtensions、SelectExtensions、TextAreaExtensions等等。
下面我们着重说一下FormExtensions类。在这个类中,我们可以找到常用的@Html.BeginForm的定义,没错,这就是Razor中用来定义Web表单的Helper。用过这个Helper的人都会注意到一个细节,就是BeginForm的用法是【@using (Html.BeginForm()){}】,和普通的Helper不同。这种用法可以让我们不用调用EndForm方法,但这是为什么呢?
见到using关键字,我们都知道在这里它的作用是在代码块结束之前,自动调用Dispose方法,当然,using代码块中的对象必须实现了IDisposable接口。找到BeginForm的定义(代码段4),发现这个方法的返回值是一个MvcForm对象。
  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());
}

代码段 4

跟踪进入MvcForm类的定义,可以看到这个类果然实现了IDisposable接口,狂喜!在MvcForm类的定义中,找到Dispose方法的实现(代码段5),豁然开朗吧?原来在Dispose方法中调用了FormExtensions.EndForm方法。
     public void Dispose()
{
Dispose(true /* disposing */);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
FormExtensions.EndForm(_viewContext);
}
}

代码段 5

继续进入FormExtensions.EndForm方法的定义(代码段6),更加豁然开朗吧?继续狂喜!EndForm方法的作用正是向浏览器发送Web表单的结束标记</form>。
        internal static void EndForm(ViewContext viewContext)
{
viewContext.Writer.Write("</form>");
viewContext.OutputClientValidation();
viewContext.FormContext = null;
}

代码段 6
...全文
1892 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
tssunnan 2016-09-22
  • 打赏
  • 举报
回复
学习了,感谢分享
慢步前行 2016-09-20
  • 打赏
  • 举报
回复
学习了
qq_31916113 2016-09-20
  • 打赏
  • 举报
回复
6666666666666
kuangshikeji 2016-09-18
  • 打赏
  • 举报
回复
关注,研究与学习中......
qq_34573441 2016-09-18
  • 打赏
  • 举报
回复
谢谢
qq_36155672 2016-09-17
  • 打赏
  • 举报
回复
6666666
maoni599 2016-09-17
  • 打赏
  • 举报
回复
6666666666666666666666666666666666666666666
qq_33858074 2016-09-16
  • 打赏
  • 举报
回复
我过来看看!!
爱睡觉的阿狸 2016-09-16
  • 打赏
  • 举报
回复
insus 2016-09-12
  • 打赏
  • 举报
回复
关注,研究与学习中......

62,046

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧