一、要实现一个功能,在不同的页面放置一段如下的内容,用于采集用户行为信息:

<input type='hidden' id='page_id' value='xxxx' />
<script type="text/javascript">
//balabala...
</script>

[1] 需求中还藏着一点,有些页面加,有些页面不加。

二、方案

方案一:当然可以这样做:找到需要采集的页面,一个个打开将采集代码拷贝进去,然后把xxxxx修改为分配给各页面的值。但如此显然违背DRY原则。

方案二:不希望采集代码处处被粘贴的话,那么从View的角度,备选的机制有partial viewlayout pages。如果使用前者,仍然需要被采集页面,重复的引用包含采集代码的partial view。如果使用后者,假使网站已经使用了多个layout pages(这很常见),依然会需要重复的粘帖采集代码。

1. 那么我们将两者结合起来,并且做一点折衷,用paritial view包含采集代码,然后在各layout pages中引用partial view:

@Html.Partial("_TraceByPageIdScript")

让采集代码就可以安然存在于_TraceByPageIdScript这个partial view中。

2. 作为page_id值的xxxx怎么办?

开始的想法是,在被采集的页面中,对ViewBag.PageId赋值(set),保证在该变量被使用前有值(不为null)。然后以为在_TraceByPageIdScript中就可以使用ViewBag.Page了(get)。

实验可耻的失败鸟。

发现pages的ViewBag和layout pages的ViewBag是不同的对象,从属于不同的WebViewPage实例。
类似的,包括MVC3之前的ViewData,都不是用在"pages需要和layout pages共享数据"这种场景的。
[it] Gets or sets a dictionary that contains data to pass between the controller and the view.
http://msdn.microsoft.com/en-us/library/system.web.mvc.viewpage.viewdata.aspx

google到了PageData
[it] Provides array-like access to page data that is shared between pages, layout pages, and partial pages.
http://msdn.microsoft.com/en-us/library/system.web.webpages.webpagebase.pagedata(v=VS.99).aspx

所以采集代码中的xxxx,可以替换为PageData["xxxx"]了

3. 这个时候发现犯了一个错误,断点看了下,PageData["xxxx"]在partial pages中的值是null。(这个和俺对MSDN注释的理解不大一致啊)
换个方式吧:

@Html.Partial("_TraceByPageIdScript", (int?)PageData["PageId"], new ViewDataDictionary())

注意:如果这里省掉了第三个参数,那么当null被传递到partial view时,会导致实际传入的对象类型是@model指明的类型,进而导致异常。这是ASP.NET MVC 3的一个古怪的地方,尚不清楚后续版本是否有调整。
如下两篇资料给自给了一种解法:

  a. http://stackoverflow.com/questions/650393/renderpartial-with-null-model-gets-passed-the-wrong-type    @Html.Partial("_TraceByPageIdScript", new ViewDataDictionary(PageData["PageId"]))

  b. http://stackoverflow.com/questions/9292852/how-do-i-invoke-a-partial-view-with-null-for-its-model    @Html.Partial("_TraceByPageIdScript", (int?)PageData["PageId"], new ViewDataDictionary())

4. 还有前面的需求[1]被丢下了,在_TraceByPageIdScript.cshtml中,对采集代码包一下:

@model int?
@if(Model.HasValue)
{
<input type='hidden' id='page_id' value='@Model.Value' />
<script type="text/javascript">
//balabala...
</script>
}

三、结语

小经周折,至此完整的实现了该需求。

除了ASP.NET MVC相关的知识外,“值即开关”模式的使用,实现了随需加载采集代码的效果,这样今后如果其它页面需要加入采集,只需要在相应页面,通过赋值即可;不再需要采集的页面,赋值为null或者注视掉赋值语句即可。

更理想的方案,其实是被采集的页面,完全不用为了被采集而进行任何修改。

做法之一,以配置的形式维护一个字典,value是page_id,key则要求可以唯一标识某个特定页面。如果有了这个字典,程序可以在运行时根据请求,来找到key,进而就能找到page_id。以此作为基础,就可以利用一个能共享给layout pages的变量,来告诉layout pages是否打开"输出采集代码"的开关。

这里有两个比较复杂的点:

  1. 以何载体来作为这里说的共享变量?这也牵扯到根据请求找到page_id的时机。时机方面可以考虑Action Filter机制,这样自然就能利用上Controller和Pages间的桥梁:ViewBag/ViewDatalayout pages拿到它,心里一定很乐呵。
http://www.manasinc.com/setting-a-viewbag-property-in-the-onresultexecuting-action-filter-in-asp-net-mvc/

  2. 关键的难点在于,字典的key的选取。如果使用url,则当route发生变化时,相应页面的采集就会失效。如果使用route,还要考虑参数取值的变化。

考虑到这个实现方案的复杂性,开发和维护都需要付出更多的精力,就没有进一步的探索下去了。

P.S. PageData["XXX"] 等效于 Page.XXX

ASP.NET MVC - PageData的应用的更多相关文章

  1. ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

    好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...

  2. 微冷的雨ASP.NET MVC之葵花宝典(MVC)

    微冷的雨ASP.NET MVC之葵花宝典 By:微冷的雨 第一章 ASP.NET MVC的请求和处理机制. 在MVC中: 01.所有的请求都要归结到控制器(Controller)上. 02.约定优于配 ...

  3. Asp.Net MVC<八>:View的呈现

    ActionResult 原则上任何类型的响应都可以利用当前的HttpResponse来完成.但是MVC中我们一般将针对请求的响应实现在一个ActionResult对象中. public abstra ...

  4. 返璞归真 asp.net mvc (9) - asp.net mvc 3.0 新特性之 View(Razor)

    原文:返璞归真 asp.net mvc (9) - asp.net mvc 3.0 新特性之 View(Razor) [索引页][源码下载] 返璞归真 asp.net mvc (9) - asp.ne ...

  5. ASP.Net MVC请求处理流程

    ASP.Net MVC请求处理流程 好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人& ...

  6. Asp.net mvc 中View 的呈现(二)

    [toc] 上一节介绍了 Asp.net mvc 中除 ViewResult 外的所有的 ActionResult,这一节介绍 ViewResult. ViewResultBase ViewResul ...

  7. asp.net mvc简单实现基于Razor的分页控件

    最近在写一些web应用了解了一下asp.net mvc发现的确好用,所以直接就干上了.不过在使用asp.net mvc的Razor模板的情况并不向传统webform那样可以使用控件.但从Razor的功 ...

  8. ASP.NET MVC+BUI实现表格的操作

    在Web中基于表格的操作,比如添加行.单元格内容编辑等等功能,是完全基于js实现的.但如果程序员完全使用js或者jquery去编写表格控件,则会导致样式不统一,代码量较大等问题,尤其对于不太熟悉js的 ...

  9. ASP.NET MVC布局

    一.Views文件夹 -> Shared文件夹下的 _Layout.cshtml 母版页 @RenderBody 当创建基于_Layout.cshtml布局页面的视图时,视图的内容会和布局页面合 ...

随机推荐

  1. 逆向分析-IDA动态调试WanaCrypt0r的wcry.exe程序

    0x00 前言 2017年5月12日全球爆发大规模蠕虫勒索软件WanaCrypt0r感染事件,各大厂商对该软件做了深入分析,但针对初学者的分析教程还比较少,复现过程需要解决的问题有很多,而且没有文章具 ...

  2. 以太坊系列之一: 以太坊RLP用法-以太坊源码学习

    RLP (递归长度前缀)提供了一种适用于任意二进制数据数组的编码,RLP已经成为以太坊中对对象进行序列化的主要编码方式.RLP的唯一目标就是解决结构体的编码问题:对原子数据类型(比如,字符串,整数型, ...

  3. debian安装及使用mysql

    在Debian中安装MySQL服务器是很方便的,使用apt-get命令即可完成. debian:~# apt-get install mysql-server mysql-client mysql-s ...

  4. hadoop学习;hdfs操作;执行抛出权限异常: Permission denied;api查看源代码方法;源代码不停的向里循环;抽象类通过debug查找源代码

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u010026901/article/details/26587251 eclipse快捷键alt+s ...

  5. Cocos2D-x-3.0 编译(Win7)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/logotostudent/article/details/25425969 第一次開始用手游引擎挺激 ...

  6. docker 部署 redmine 项目管理软件

    最近部署一套redmine项目管理程序, ruby部署各种问题,用docker 直接run, 简单方便. . docker run --name=mysql-redmine -d -p : -v /d ...

  7. transfer function

    线性变化后,往往希望进行非线性变化,常用的非线性变化函数有Sigmoid,Tanh,ReLU.会发现,经过这三个函数变化后,Tensor的维度并不发生变化. tanh(双曲正切函数):

  8. php后台+前端开发过程整理

    一.PHP后台从数据库中获取数据 1. 建立数据库连接: //在本项目中封装了数据库的各种操作 $dbConn = $this->_createMysqlConn(); 2. 执行sql语句 $ ...

  9. PAT乙级1033

    1033 旧键盘打字 (20 分)   旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 ...

  10. https协议的一些杂谈

    参考文献:百度运维博客&知乎车小胖的回答 这是拖了很久的一篇记录,项目完结了,也找个时间写完.(额,阅读者最好对http协议有一定了解,否则就没必要浪费时间看下去了)首先来一段百度的解释: H ...