自定义TempData跨平台思路

一:TempData的自定义实现。。。

TempData是用Session实现的,既然是Session,那模式是线程方式。。。这样的Session是没法进行跨平台的。。。

那么这就涉及到如何在多台机器上部署、存储...

  • 关系型数据库: sqlserver/mysql
  • nosql: mongodb,redis。

问题1:重点在替换,不在实现。。。。。怎么替换,以及使用方式

 

TempData继承关系:Tempdata => TempDataDictionary=> SessionStateTempDataProvider=>ITempDataProvider

 1 namespace System.Web.Mvc
 2 {
 3     using System;
 4     using System.Collections.Generic;
 5     using System.Web;
 6     using System.Web.Mvc.Properties;
 7     
 8     public class SessionStateTempDataProvider : ITempDataProvider
 9     {
10         internal const string TempDataSessionStateKey = "__ControllerTempData";
11         
12         public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
13         {
14             HttpSessionStateBase session = controllerContext.HttpContext.Session;
15             if (session != null)
16             {
17                 Dictionary<string, object> dictionary = session["__ControllerTempData"] as Dictionary<string, object>;
18                 if (dictionary != null)
19                 {
20                     session.Remove("__ControllerTempData");
21                     return dictionary;
22                 }
23             }
24             return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
25         }
26         
27         public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
28         {
29             if (controllerContext == null)
30             {
31                 throw new ArgumentNullException("controllerContext");
32             }
33             HttpSessionStateBase session = controllerContext.HttpContext.Session;
34             bool flag = (values != null) && (values.Count > 0);
35             if (session == null)
36             {
37                 if (flag)
38                 {
39                     throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
40                 }
41             }
42             else if (flag)
43             {
44                 session["__ControllerTempData"] = values;
45             }
46             else if (session["__ControllerTempData"] != null)
47             {
48                 session.Remove("__ControllerTempData");
49             }
50         }
51     }
52 }

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属性,代码如下:

 1 public ITempDataProvider TempDataProvider
 2         {
 3             get
 4             {
 5                 if (this._tempDataProvider == null)
 6                 {
 7                     this._tempDataProvider = this.CreateTempDataProvider();
 8                 }
 9                 return this._tempDataProvider;
10             }
11             set
12             {
13                 this._tempDataProvider = value;
14             }
15         }

所以注入点就找到了,在创建Controller Factory中创建Controller实例的时候,把自定义的DataProvider类,赋值给TempDataProvider就可以了

下面来实现一把分布式的tempData

实现分布式流程

继承自DefaultControllerFactory的MyControllerFactory类即自定义的Controller Factory

1 public class MyControllerFactory:DefaultControllerFactory
 2     {
 3         public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
 4         {
 5             var iController= base.CreateController(requestContext, controllerName);
 6 
 7             var controller = iController as Controller;
 8             controller.TempDataProvider = new CrossSessionTempData2();
 9 
10 
11             return iController;
12         }
13     }

TempData的值存入到cache中之文件依赖

接着我们需要自定义一个实现了ITempDataProvider接口的DataProvider类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Caching;
 6 using System.Web.Mvc;
 7 
 8 namespace CrossSessionTempData.Infrastructure
 9 {
10     public class CrossSessionTempData2 : ITempDataProvider
11     {
12 
13         internal const string TempDataSessionStateKey = "__ControllerTempData";
14 
15         public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
16         {
17             var cache = controllerContext.HttpContext.Cache;
18 
19             if (cache != null)
20             {
21                 Dictionary<string, object> dictionary = cache[TempDataSessionStateKey] as Dictionary<string, object>;
22                 if (dictionary != null)
23                 {
24                     //cache.Remove(TempDataSessionStateKey);
25                     return dictionary;
26                 }
27             }
28             return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
29         }
30 
31         /// <summary>Saves the specified values in the temporary data dictionary by using the specified controller context.</summary>
32         /// <param name="controllerContext">The controller context.</param>
33         /// <param name="values">The values.</param>
34         /// <exception cref="T:System.InvalidOperationException">An error occurred the session context was being retrieved.</exception>
35         public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
36         {
37             if (controllerContext == null)
38             {
39                 throw new ArgumentNullException("controllerContext");
40             }
41             var cache = controllerContext.HttpContext.Cache;
42             bool flag = values != null && values.Count > 0;
43             if (cache == null)
44             {
45                 if (flag)
46                 {
47                     throw new InvalidOperationException("");
48                 }
49             }
50             else
51             {
52                 CacheDependency dp = new CacheDependency(controllerContext.HttpContext.Server.MapPath("/Data/123.txt"));
53                 if (flag)
54                 {
55                     
56 
57                     //cache[TempDataSessionStateKey] = values;
58                     cache.Insert(TempDataSessionStateKey, values, dp);
59 
60                     return;
61                 }
62                 cache.Insert(TempDataSessionStateKey, values, dp);
63                 //if (cache[TempDataSessionStateKey] != null)
64                 //{
65                 //    cache.Remove(TempDataSessionStateKey);
66                 //}
67             }
68         }
69     }
70 }

把TempData的值存入到NoSQL Memcached中实现真正的分布式

1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using Memcached.ClientLibrary;
 6 
 7 namespace WebDemo.Models
 8 {
 9     public static class MemcacheHelper
10     {
11         private static MemcachedClient mc;
12 
13         static MemcacheHelper()
14         {
15             //通过客户端来进行memcached的集群配置,在插入数据的时候,使用一致性哈希算法,将对应的value值存入Memcached
16             String[] serverlist = { "127.0.0.1:11211" };
17 
18             // 初始化Memcached的服务池
19             SockIOPool pool = SockIOPool.GetInstance("test");
20             //设置服务器列表
21             pool.SetServers(serverlist);
22             //各服务器之间负载均衡的设置比例
23             pool.SetWeights(new int[] { 1 });
24             pool.Initialize();
25             //创建一个Memcached的客户端对象
26             mc = new MemcachedClient();
27             mc.PoolName = "test";
28             //是否启用压缩数据:如果启用了压缩,数据压缩长于门槛的数据将被储存在压缩的形式
29             mc.EnableCompression = false;
30             
31         }
32         /// <summary>
33         /// 插入值
34         /// </summary>
35         /// <param name="key"></param>
36         /// <param name="value"></param>
37         /// <param name="expiry">过期时间</param>
38         /// <returns></returns>
39         public static bool Set(string key, object value,DateTime expiry){
40             return mc.Set(key, value, expiry);
41         }
42         /// <summary>
43         /// 获取值
44         /// </summary>
45         /// <param name="key"></param>
46         /// <returns></returns>
47         public static object Get(string key)
48         {
49             return mc.Get(key);
50         }
51     }
52 }

自定义的我们的DataProvider:

1  public class CrossSessionTempData2 : ITempDataProvider
 2     {
 3 
 4         internal const string TempDataSessionStateKey = "__ControllerTempData";
 5 
 6         public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
 7         {
 8           
 9             Dictionary<string, object> dictionary = MemCaheHelper.Get(TempDataSessionStateKey) as Dictionary<string, object>;
10             if (dictionary != null)
11             {
12                 MemCaheHelper.Set(TempDataSessionStateKey, dictionary, DateTime.MinValue);
13                 return dictionary;
14             }
15             return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
16         }
17 
18         public virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
19         {
20             if (controllerContext == null)
21             {
22                 throw new ArgumentNullException("controllerContext");
23             }
24             
25             bool flag = values != null && values.Count > 0;
26             if (flag)
27             {
28                
29                 MemCaheHelper.Set(TempDataSessionStateKey, values,DateTime.Now.AddMinutes(1));
30                 return;
31             }
32 
33             if (MemCaheHelper.Get(TempDataSessionStateKey) != null)
34             {
35                 MemCaheHelper.Set(TempDataSessionStateKey,values,DateTime.MinValue);
36             }
37           
38 
39         }
40     }

 

posted @ 2017-08-22 17:50  大胖儿在努力  阅读(332)  评论(0编辑  收藏  举报