zoukankan      html  css  js  c++  java
  • 深度解析Controller中的TempData及源码

    基础:
    首先说一下这个TempData在MVC架构体系中的结构和原理,我们一层层来说:

    一、首先是TempDataDictionary(也就是你在Controller中访问到的TempData属性)。
    TempDataDictionary是放在ControllerBase中的属性,继承于IDictionary<TKey,TValue>。它在ControllerBase中是非虚、不可重写的属性,意味着,如果你要实现自己的TempData,是必须实现自己
    Controller了,Controller都要重新实现。
    TempDataDictionary内部有个类型Dictionary<string,object>的_data字段,该_data就是保存TempData键值对的载体,TempDataDictionary使用它自己的Load和Save方法来加载和保存这个_data,也提供了方法如何读写该_data。
    每执行一个Action前会执行一次TempDataDictionary.Load,该Action执行完毕后会执行TempDataDictionary.Save。
    TempDataDictionary规定了它的核心数据字段_data的载体的类型必须是Dictionary<string,object>,但该数据载体实际是谁来管理、放在哪里,则是由ITempDataProvider提供者来提供的。


    二、然后是ITempDataProvider
    这个接口只有LoadTempData和SaveTempData两个方法,一个是返回实际数据载体,一个是保存数据。
    这个ITempDataProvider是由ControllerBase的CreateTempDataProvider虚方法创建的,默认创建的是new SessionStateTempDataProvider(),
    你可以在比如HomeController中override这个CreateTempDataProvider方法以定义你自己实现的ITempDataProvider类(后面再说)。


    三、然后是ITempDataProvider的默认实现类SessionStateTempDataProvider
    SessionStateTempDataProvider利用HttpContext.Session来保存一个Dictionary<string,object>,因为TempDataDictionary的_data字段只接受这种类型
    在LoadTempData时,载入返回上次请求(某个Action请求)之后完毕保存下来的Dictionary,然后从session中移除该Dictionary,如果Session中没有则返回一个空实例new Dictionary<string,object>()。
    在SaveTempData时,保存本次未移除的Key。继续下面

    四、关于TempData(TempDataDictionary)的读写
    TempDataDictionary内部除了_data,还有两个字段,一个是类型为HashSet<string>的初始Key集合,一个是类型为HashSet<string>的保留key集合,它们主要是在对TempData读写时起的作用,它们起什么作用看下面实验过程:
    注意:在TempDataDictionaryLoad时,初始key集合保存_data字段中所有的key,而保留key集合长度为0,什么都没有
    ======================================================================================================================================================================================================
    实验:
    一、现在我们开始请求一个Action:
    1.在Action请求前,Controller会在内部先初始化自己的TempData属性,给它new一个TempDataDictionary,然后Controller调用自己的CreateTempDataProvider创建一个SessionStateTempDataProvider
      随后调用TempData的Load方法,Load这个SessionStateTempDataProviderSessionStateTempDataProvider会初始化类型为Dictionary<string,object>的Session数据,并加载到TempData内部的_data,
      此时_data是个长度为0的Dictionary,至此TempData的初始化完成。
    2.我们在Action中写一个TempData["aaa"] = 1,在这种写操作的时候,TempDataDictionary会给_data来Add("aaa",1),然后再给初始Key集合 Add("aaa")
    3.然后我调用TempData.TryGetValue,或TempData["aaa"] 这种读操作的时候,TempDataDictionary会将初始Key集合中名为"aaa"的key移除掉。
    4.这时我们整个Action请求完毕。
    5.在Action请求完毕后(不论是否Action发生了异常),Controller会调用TempData字段的Save方法,Save方法会将保留key集合和另一个key集合(_data.Keys和初始Key集合的并集)选出来成一个非重复集合,
      这个集合是未移除的key,用_data.Keys.Except(这个集合)的结果就是已移除的key集合,然后从_data中移除这些已移除的key。
      然后调用SessionStateTempDataProvider的SaveTempData方法将这个_data保存到Session。


    二、然后我们再开始一个新的Action请求
    1.和前面一样,这次,SessionStateTempDataProvider会载入上次请求完后保存下来的Dictionary
    2.这时调用TempData["aaa"],因为aaa已经在上次访问后被移除掉了,所以会报异常提示找不到key,怎么办?看下面三。

    三、整个过程中,我们并没有读写保留key集合,那么这个保留key集合是什么用的呢?
    TempData有个方法Keep,在你调用TempData["aaa"]或TryGetValue("aaa")之前调用Keep("aaa"),它会把aaa添加到保留key集合,等到TempData["aaa"]或TempData.TryGetValue("aaa",out xxx)的时候,这个aaa虽然会在初始Key集合中被移除,但是待执行到第6步的时候,这个aaa的键值对数据会保存下来存活至下一次请求,下次请求Action仍又可以访问到它了。
    此外TempData有个Peek方法,和TryGetValue类似也是读取值,但是它不会将初始Key集合中名为"aaa"的key移除掉,下次请求Action也可以访问到它。也挺实用。

    ======================================================================================================================================================================================================

    后记:
    其实我认为mvc中有很多东西,学的人用的人都没有充分利用它。
    关于TempData,我猜mvc设计者之所以要这么做,是担心性能问题,也是怕开发者在session里面数据弄多了,容易搞混淆,每次请求后都及时清理掉。毕竟mvc的效率相对低。Items集合里面本来数据就多。如果能搞清楚mvc设计者为什么要这样设计,我想就可以更好的利用这个TempData了。
    如果有多线程,最好就别用这个了。自己写个ITempDataProvider实现类

    ======================================================================================================================================================================================================
    总结:
    由此可知,在单个Action请求过程中,TempData某个key的值始终可以访问到,但是如果又进行了一个新的请求,那么这个key就没了,你想保留,就使用keep
    注意:如果这个请求的Action是一个ChildAction,那么会载入调用这个ChildAction的父视图的 ControllerContext.ParentViewContext.TempData,而不会重复第1步和第5步的操作了
    总的来说,不是很复杂。

    如果没懂,去研究下源码,你就会清晰一点

  • 相关阅读:
    Python遇到的零碎小问题
    【bug】YYC松鼠短视频系统V2.7版本以上 增加阿里云上传后,“上传视频无法生成缩略图报错” 修改
    【补丁】YYC松鼠短视频系统补丁,增加视频点赞数据管理功能,可修改点赞数量,V2.8的功能
    【bug】修复YYC松鼠短视频系统V2.7版本bug 注册输入验证码提示邀请码,输入邀请码提示错误
    YYC松鼠短视频系统【bug】短信验证码功能bug,新注册短信用户任意填写验证码都能通过注册的严重bug修复
    修复YYC松鼠短视频系统我的收藏页面 没有返回按钮的bug
    学好C++必须要注意的十八个问题
    es节点失效,手动重置primary,迁移分区
    elasticsearch 大集群最基本,也是最重要的两个配置gc和指针压缩
    2020年一整年几乎没有更新,重新开张
  • 原文地址:https://www.cnblogs.com/yuuki/p/3307485.html
Copyright © 2011-2022 走看看