1. 程式人生 > >自定義TempData跨平臺思路

自定義TempData跨平臺思路

using add 初始化 obj logs temp 模式 既然 []

一: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     }

自定義TempData跨平臺思路