自定义TempData跨平台思路
一:TempData的自定义实现。。。
TempData是用Session实现的,既然是Session,那模式是线程方式。。。这样的Session是没法进行跨平台的。。。
那么这就涉及到如何在多台机器上部署、存储...
- 关系型数据库: sqlserver/mysql
- nosql: mongodb,redis。
问题1:重点在替换,不在实现。。。。。怎么替换,以及使用方式
TempData继承关系:Tempdata => TempDataDictionary=> SessionStateTempDataProvider=>ITempDataProvider
namespace System.Web.Mvc
{
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc.Properties; public class SessionStateTempDataProvider : ITempDataProvider
{
internal const string TempDataSessionStateKey = "__ControllerTempData"; 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.Remove("__ControllerTempData");
return dictionary;
}
}
return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
} 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 > );
if (session == null)
{
if (flag)
{
throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
}
}
else if (flag)
{
session["__ControllerTempData"] = values;
}
else if (session["__ControllerTempData"] != null)
{
session.Remove("__ControllerTempData");
}
}
}
}
SessionStateTempDataProvider类实现了ITempDataProvider接口,重写了Load和Save方法。
从源码可知,SessionStatesTempDataProvider暴露了LoadTempData和SaveTempData两个方法。
其中从SaveTempData中session["__ControllerTempData"] = (object) values;可以看出,TempData是存储在Session中的。
其中LoadTempData方法中session.Remove("__ControllerTempData");就说明了从session中获取tempdata后,对应的tempdata就从session中清空了
问题2:到底在mvc中哪个地方进行注入????mvc的管道中是怎么注入的???
MVC的管道和action方法执行前后发现:PossiblyLoadTempData和PossiblySaveTempData是在调用Controller中对应的action方法时执行的,并且Controller中有 TempDataProvider属性,代码如下:
public ITempDataProvider TempDataProvider
{
get
{
if (this._tempDataProvider == null)
{
this._tempDataProvider = this.CreateTempDataProvider();
}
return this._tempDataProvider;
}
set
{
this._tempDataProvider = value;
}
}
所以注入点就找到了,在创建Controller Factory中创建Controller实例的时候,把自定义的DataProvider类,赋值给TempDataProvider就可以了
下面来实现一把分布式的tempData
实现分布式流程
继承自DefaultControllerFactory的MyControllerFactory类即自定义的Controller Factory
public class MyControllerFactory:DefaultControllerFactory
{
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var iController= base.CreateController(requestContext, controllerName); var controller = iController as Controller;
controller.TempDataProvider = new CrossSessionTempData2(); return iController;
}
}
TempData的值存入到cache中之文件依赖
接着我们需要自定义一个实现了ITempDataProvider接口的DataProvider类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Web.Mvc; namespace CrossSessionTempData.Infrastructure
{
public class CrossSessionTempData2 : ITempDataProvider
{ internal const string TempDataSessionStateKey = "__ControllerTempData"; public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{
var cache = controllerContext.HttpContext.Cache; if (cache != null)
{
Dictionary<string, object> dictionary = cache[TempDataSessionStateKey] as Dictionary<string, object>;
if (dictionary != null)
{
//cache.Remove(TempDataSessionStateKey);
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");
}
var cache = controllerContext.HttpContext.Cache;
bool flag = values != null && values.Count > ;
if (cache == null)
{
if (flag)
{
throw new InvalidOperationException("");
}
}
else
{
CacheDependency dp = new CacheDependency(controllerContext.HttpContext.Server.MapPath("/Data/123.txt"));
if (flag)
{ //cache[TempDataSessionStateKey] = values;
cache.Insert(TempDataSessionStateKey, values, dp); return;
}
cache.Insert(TempDataSessionStateKey, values, dp);
//if (cache[TempDataSessionStateKey] != null)
//{
// cache.Remove(TempDataSessionStateKey);
//}
}
}
}
}
把TempData的值存入到NoSQL Memcached中实现真正的分布式
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Memcached.ClientLibrary; namespace WebDemo.Models
{
public static class MemcacheHelper
{
private static MemcachedClient mc; static MemcacheHelper()
{
//通过客户端来进行memcached的集群配置,在插入数据的时候,使用一致性哈希算法,将对应的value值存入Memcached
String[] serverlist = { "127.0.0.1:11211" }; // 初始化Memcached的服务池
SockIOPool pool = SockIOPool.GetInstance("test");
//设置服务器列表
pool.SetServers(serverlist);
//各服务器之间负载均衡的设置比例
pool.SetWeights(new int[] { });
pool.Initialize();
//创建一个Memcached的客户端对象
mc = new MemcachedClient();
mc.PoolName = "test";
//是否启用压缩数据:如果启用了压缩,数据压缩长于门槛的数据将被储存在压缩的形式
mc.EnableCompression = false; }
/// <summary>
/// 插入值
/// </summary>
/// <param name="key">建</param>
/// <param name="value">值</param>
/// <param name="expiry">过期时间</param>
/// <returns></returns>
public static bool Set(string key, object value,DateTime expiry){
return mc.Set(key, value, expiry);
}
/// <summary>
/// 获取值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static object Get(string key)
{
return mc.Get(key);
}
}
}
自定义的我们的DataProvider:
public class CrossSessionTempData2 : ITempDataProvider
{ internal const string TempDataSessionStateKey = "__ControllerTempData"; public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
{ Dictionary<string, object> dictionary = MemCaheHelper.Get(TempDataSessionStateKey) as Dictionary<string, object>;
if (dictionary != null)
{
MemCaheHelper.Set(TempDataSessionStateKey, dictionary, DateTime.MinValue);
return dictionary;
}
return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
} public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
} bool flag = values != null && values.Count > ;
if (flag)
{ MemCaheHelper.Set(TempDataSessionStateKey, values,DateTime.Now.AddMinutes());
return;
} if (MemCaheHelper.Get(TempDataSessionStateKey) != null)
{
MemCaheHelper.Set(TempDataSessionStateKey,values,DateTime.MinValue);
} }
}
最新文章
- ORA-00600 3020 ORA-10567案例
- PHP之session与cookie
- vijos P1780 【NOIP2012】 开车旅行
- vs2012安装Microsoft.AspNet.WebApi.WebHost
- mysql 异步执行 query //@todo
- css3 animation 动画属性简介
- [LeetCode 111] - 二叉树的最小深度 (Minimum Depth of Binary Tree)
- Aptana Studio 3 官方汉化包汉化
- c#中,委托Func的简单实践
- vue2.0 通过v-html指令渲染的富文本无法修改样式的解决方案
- shell编程-项目部署(二)
- 远程Gitlab新建的分支在IDEA里不显示
- Timus 1132 Square Root(二次剩余)
- Hibernate学习笔记:基础模型类
- SpringBoot入门 (十四) Security安全控制
- 写一个标准宏MIN,输入两个参数,返回较小的
- gitlab+jenkins环境搭建.md
- Javascript 面向对象编程(一):封装(转载)
- 【Python】自动化测试框架-共通方法汇总
- 为大家推荐一款很不错的MarkDown编辑器——stackEdit