ViewData ViewBag TempData

1,Mvc中比较常用的三个集合


1.ViewData, ViewBag, TempData
viewData是ViewDataDictionary字典类型 它实现了 IDictionary<string, object>, ICollection<KeyValuePair<string, object>>, IEnumerable<KeyValuePair<string, object>>, IEnumerable接口


ViewBag是动态类型,编译时不会检查,只有运行时才会检查,“运行时变量” 它本质和ViewData是一样的。


TempData 
1,是一个string object的字典
2,Action执行前后都会对temp进行操作
我们的TempData其实是用System.Web.Mvc.SessionStateTempDataProvider来实现的

TempData可以存储一次,只能读取一次,如果第二次读取,将不会有tempdata数据,这样就起到了临时变量的作用


重点:控制器在调用一个Action方法前,会先执行一个BeginExecuteCore方法 。这个方法中的执行了一个this.PossiblyLoadTempData()方法 ,这个方法最终执行的是System.Web.Mvc.SessionStateTempDataProvider类中的LoadTempData方法

//控制器的Action方法执行前会执行一个BeginExecuteCore方法
protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
	
	this.PossiblyLoadTempData(); //这个方法调用的是SessionStateTempDataProvider类中的LoadTempData方法
	..........
}
而控制在调用完Action方法并执行完视图后(即在OnResultExecuted  方法后)执行了SaveTempData方法。这个方法中执行了this.PossiblySaveTempData()方法,这个方法最终执行的是System.Web.Mvc.SessionStateTempDataProvider类中的SaveTempData方法

//控制器调用Action方法并在视图执行完毕后会执行一个EndExecuteCore方法(即这个方法会在Action过滤器的OnResultExecuted方法执行完后再执行)
protected virtual void EndExecuteCore(IAsyncResult asyncResult)
{
	try
	{
		AsyncResultWrapper.End(asyncResult, Controller._executeCoreTag);
	}
	finally
	{
		this.PossiblySaveTempData(); //这个方法调用的是SessionStateTempDataProvider类中的SaveTempData方法
	}
}
以下System.Web.Mvc.SessionStateTempDataProvider类中的LoadTempData方法和SaveTempData方法两个方法就是TempData的原理机制。

让我们来看看System.Web.Mvc.SessionStateTempDataProvider类中的LoadTempData方法和SaveTempData方法

namespace System.Web.Mvc
{
	/// <summary>Provides session-state data to the current <see cref="T:System.Web.Mvc.TempDataDictionary" /> object.</summary>
	public class SessionStateTempDataProvider : ITempDataProvider
	{
		internal const string TempDataSessionStateKey = "__ControllerTempData";

		/// <summary>Loads the temporary data by using the specified controller context.</summary>
		/// <returns>The temporary data.</returns>
		/// <param name="controllerContext">The controller context.</param>
		/// <exception cref="T:System.InvalidOperationException">An error occurred when the session context was being retrieved.</exception>
		public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
		{
			HttpSessionStateBase session = controllerContext.HttpContext.Session;
			if (session != null)
			{
				Dictionary<string, object> dictionary = session["__ControllerTempData"] as Dictionary<string, object>;
				if (dictionary != null)
				{
					//第一次进来,查询下session["__ControllerTempData"] 存不存在,如果存在,则把这个Session删除
					session.Remove("__ControllerTempData"); //注意:虽然删除了session,但是dictionary已经有值了哦
					return dictionary;//返回这个字典
				}
			}
			return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
		}

		/// <summary>Saves the specified values in the temporary data dictionary by using the specified controller context.</summary>
		/// <param name="controllerContext">The controller context.</param>
		/// <param name="values">The values.</param>
		/// <exception cref="T:System.InvalidOperationException">An error occurred the session context was being retrieved.</exception>
		public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
		{
			if (controllerContext == null)
			{
				throw new ArgumentNullException("controllerContext");
			}
			HttpSessionStateBase session = controllerContext.HttpContext.Session;
			bool flag = values != null && values.Count > 0;
			if (session == null)
			{
				if (flag)
				{
					throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
				}
			}
			else
			{
				if (flag)
				{
					session["__ControllerTempData"] = values;
					return;
				}
				if (session["__ControllerTempData"] != null)
				{
					session.Remove("__ControllerTempData");
				}
			}
		}
	}
}


根据原理让我们来自己实现TempData  (我们知道TempData是根据Session来实现的,既然是Session,那么模式是线程方式,,这样的Session是无法进行跨平台的

假设我们的项目采用的分布式部署,MVC在多台机器中部署..那么怎么做到Session在多台机器中共存呢,这就涉及到分布式的存储。比如存储在关系型数据库中 如Sql Server或者MySql  又比如存储在非关系行数据库中,如MongoDB,Redis中。)

为了演示,我们就用本地的Cache来替换Session吧。。重点在替换,不在实现。


第一:首先定义一个自己的类(MyCacheStateTempData),实现ITempDataProvider接口,这个接口中就定义了LoadTempData和SaveTempData两个方法

第二:然后我需要定义自己的控制工厂。并在Global文件中将自己定义的控制器工厂替换掉MVC默认的控制器工厂

第三:在自定义的控制器工厂中将控制器的TempDataProvider属性设置为我们的自定义的 MyCacheStateTempData类对象

第四:动手写代码

namespace MvcApp
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
    // 请访问 http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);



            //将默认的控制器工厂修改为我们自己的控制器工厂
            ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
        }

       
    }

    //我们只所以要自己定义一个我们自己的控制器工厂类,目的是就是要将控制器的TempDataProvider值设为我们自己定义的MyCacheStateTempData对象
    public class MyControllerFactory : DefaultControllerFactory
    {
        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            //调用父类的CreateController创建控制器。与默认的其实是一模一样的
            var iController = base.CreateController(requestContext, controllerName);
            var controller = iController as Controller; //类型转换

            //注:控制的的TempDataProvider的默认值是 new SessionStateTempDataProvider()
            //现在我们将它修改为我们自己定义的值
            controller.TempDataProvider = new MyCacheStateTempData();
            return iController;
        }
    }

    //这个类就是实现了Mvc的TempData的机制
    //【这个类中的两个方法我模仿了Mvc默认的实现机制,只是将controllerContext.HttpContext.Session改为了controllerContext.HttpContext.Cache】
    public class MyCacheStateTempData : ITempDataProvider
    {
        internal const string TempDataSessionStateKey = "__ControllerTempData";

        //控制器调用Action方法前会执行这个LoadTempData方法
        public IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
        {
            var cache = controllerContext.HttpContext.Cache;
            if (cache != null)
            {
                Dictionary<string, object> dictionary = cache["__ControllerTempData"] as Dictionary<string, object>;
                if (dictionary != null)
                {
                    //第一次进来,查询下session["__ControllerTempData"] 存不存在,如果存在,则把这个Session删除
                    cache.Remove("__ControllerTempData"); //注意:虽然删除了session,但是dictionary已经有值了哦
                    return dictionary;//返回这个字典
                }
            }
            return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        }

        //控制器调用Action方法后会执行这个SaveTempData方法。目的是将我们在Action方法中设置的TempData["username"] = "jack";保存起来
        public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            var cache = controllerContext.HttpContext.Cache;
            bool flag = values != null && values.Count > 0;
            if (cache == null)
            {
                if (flag)
                {
                    throw new Exception("这里抛了个异常");
                }
            }
            else
            {
                if (flag)
                {
                    cache["__ControllerTempData"] = values;
                    return;
                }
                if (cache["__ControllerTempData"] != null)
                {
                    cache.Remove("__ControllerTempData");
                }
            }
        }
    }
}
OK









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值