写这篇文章的初衷是群友经常听到这类话题,母版页动态数据?视图如何给母版页赋值?视图如何改变母版页数据?

而要较为系统去分析这些事,会发现其实一方面我们要跳出web form思维,其次要深度了解何为MVC。

1、MVC数据存储方式

分别为:数据模型Model、ViewBag、TempData——(当然还包括:Session、Application等等这里不做讨论。)而这三者的不同大概可以分生命周期和写法而已。

数据模型Model即是严格要求MVC的规则来,即每个视图对应一个Model;而ViewBag其实是一个IDictionary<string, object>类型的数据集合。二者的生命周期和View同归于尽。

TempData也是一个IDictionary<string, object>类型的数据集,只不过可以跨视图;其核心是Session存储,很恶心吧!当然HTTP本是无状态,除了Session就没别的办法了,按我说就不应该存在TempData,有点助纣为虐之意。

2、ASP.NET MVC的母版页

单独做为一点来讲,主要原因是MVC母版页的存在跟Web Form的思维完全不同。因为母版页只是一个View页面,所以天生无任何Collection可对应。抑或我们可以换个方式来说,母版页只是在模板引擎Razor(取决于当前模板引擎)预编译时使用罢了。有此认识,我们下面便好说了。

3、让母版页有处理能力几种方式

既然母版页无任何处理能力,那我们只能通过嵌套她的视图来帮助她,当然这有多种方式,这话有臆断之嫌。因为不同处理方式会倒置不同感觉;但其核心还是由视图去控制母版的处理能力。

1)、ViewBag和TempData方式

这不难理解,因为视图预编译时会把母版页解析一并形成一个View,所以根据MVC数据存储方式的介绍,便很容易理解。

当然你会遇到两个头疼的问题(后面会慢慢改善这些问题):

1.必须对每个Collection的ViewBag、TempData重新赋值。

2.HTML页面到处ViewBag,逻辑简单还好,复杂就麻烦,易出错。

2)、Model方式

MVC中的M,伟大VS面前变得Coding体验很好。随便对于一些简单的页面,我们总是很懒去声明一个空或只有一二个属性的类。当然这不是重点,重点是如何表现Model跟母版页数据传递。

我通常的做法是创建一个BaseModel的类,接下来不用我讲了吧,把母版页需要运用到的数据模型都加入当中。当然我们一样可以通过System.Web.HttpContext.Current来获取我们最原始的一些数据。

最后我们可以很优雅的在母版页中直接使用@Model.XXX。这也使得我们轻松解决提到的两个问题。而唯一的好处是强迫你在每个页面都需要加入一个Model,哪怕是一个空页面,但我倒认为这是一种良好的习惯,因为强类型比ViewBag速度更快。

3)、利于ActionFilterAttribute改善ViewBag代码体验

其存储方式还是ViewBag只不过换成Filter变得代码更优雅而已。

ActionFilterAttribute一共有四个方法由ASP.NET MVC框架调用,分别:

  • OnActionExecuted:Action执行后调用。
  • OnActionExecuting:Action执行之前调用。
  • OnResultExecuted:Action结果后调用。
  • OnResultExecuting:Action结果之前调用。

有点晕对吧,我们来看张图就很容易理解了。

ActionFilterAttribute执行顺序

这里我选择的是OnActionExecuted加入我的逻辑代码,其核心是我还可以通过Action的参数来改变我业务逻辑。

以下是一个简单示例:

    public class LanFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            string lan = ConfigHelper.Lan_Default;
            if (filterContext.RouteData.Values.ContainsKey("lan")) lan = filterContext.RouteData.Values["lan"].ToString();
            if (filterContext.Result is ViewResult)
            {
                ViewResult result = (ViewResult)filterContext.Result;
                result.ViewBag.lan_d = LanData.D[lan];
                result.ViewBag.lan = lan;
                result.ViewBag.year = System.DateTime.Now.Year;
                    }
            base.OnActionExecuted(filterContext);
        }
    }

使用时在需要的Collection加上[LanFilter]即可。

4)@Html.Partial,@Html.RenderPartial,@Html.Action,@Html.RenderAction分部视图

别看这么多个,实际只有两种调用方式。

其一:而里面认真看其他是带Render和不带的问题,带Render可以理解为立刻输出,因为他在内部是将值写入HtmlHelper.ViewContext.Writer。而不带Render是返回一个MvcHtmlString,因此我们可以将其放入变量中,待合适的时候输出。

其二:Partial和Action区别在于有没有对应的Action方法。

作用理解了,那我们来分析一下适用环境。

1.Html.Partial和Html.RenderPartial更适用于静态HTML的输出。
2.Html.Action和Html.RenderAction更适用时业务逻辑处理能力,因为他必须有一个Action以她对应。

而Html.Action必须在任何一个Collection里面都有一个对应的Active,解决办法也很简单,创建一个BaseCollection写上用户分部视图需要的Action,然后每个Collection继承BaseCollection。

好了,至此已经将我知道所有数据传递方法全面介绍一遍。每一种方式都可以达到目的,关键看怎么用!

哎,发现写文章越来越费事,不做示例又不行。虽然都是简单应用篇,然而这周已经连续三篇,我还真勤劳。