How to customize .NET 4.0's System.Runtime.Caching.ChangeMonitor

  • 18329
  • 0
  • C#
  • 2013-06-18

How to customize .NET 4.0's System.Runtime.Caching.ChangeMonitor

筆者很久以前寫過一篇.NET 4.0 New Feature - System.Runtime.Caching,稍稍的簡單介紹了一下.NET 4.0新加入的快取框架。基本上的操作只要參閱那篇應該都不成問題,但是該快取框架內建只提供HostFileChangeMonitor與SqlChangeMonitor兩個ChangeMonitor的實作,我們要快取的資料不可能永遠在磁碟與SQL DB這兩個快取介質內,有時候我們可能會要自己串些Restful API抓取資料並做快取,或是是要套些比較複雜的檢查規則,這時我們就必須善用該快取框架易於擴充的特點,客制自己的ChangeMonitor。

 

要客制自己的ChangeMonitor不難,大概只有五個流程步驟:

image

 

依序是:

  1. Create a class that Inherited ChangeMonitor
  2. Implement UniqueId property and Dispose method
  3. Init in constructor
  4. Invoke InitializationComplete method after init
  5. Invoke OnChanged method when content must update

 

 

簡單的說就是要建立一個類別繼承至ChangeMonitor,並覆寫它的Uniqueid屬性與Dispose方法,接著在建構子這邊做些初始的動作,初始完呼叫InitializationComplete方法告知初始動作完成,最後在偵測到資料變動時呼叫OnChanged方法就可以了。

 

這邊可參閱MSDN ChangeMonitor Class 這篇的Notes to Inheritors這段,裡面有提到很多實作的眉眉角角需要注意。

 

實際的來看個例子加深印象,筆者在這邊簡單的實做了一個ClipboardChangeMonitor,期望Cache的內容能在剪貼簿資料發生變動時失效。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CustomChangeMonitorDemo
{
	public class ClipboardChangeMonitor : ChangeMonitor
	{
		#region Var
		private string _clipboardText;
		private Timer _timer;
		private string _uniqueID; 
		#endregion


		#region Private Property
		private string m_ClipboardText
		{
			get { return _clipboardText ?? string.Empty; }
			set 
			{
				if (_clipboardText == value)
					return;

				_clipboardText = value;
				OnChanged(value);
			}
		}

		private System.Windows.Forms.Timer m_Timer 
		{
			get
			{
				return _timer ?? (_timer = new System.Windows.Forms.Timer());
			}
		} 
		#endregion


		#region Public Property
		public override string UniqueId
		{
            get { return _uniqueID ?? (_uniqueID = Guid.NewGuid().ToString()); }
		} 
		#endregion


		#region Constructor
		public ClipboardChangeMonitor()
		{
			m_Timer.Interval = 1000;
			m_Timer.Tick += m_Timer_Tick;
			m_Timer.Start();

			_clipboardText = Clipboard.GetText();

			InitializationComplete();
		}
		#endregion


		#region Protected Method
		protected override void Dispose(bool disposing)
		{
		} 
		#endregion


		#region Event Process
		void m_Timer_Tick(object sender, EventArgs e)
		{
			m_ClipboardText = Clipboard.GetText();
		}  
		#endregion
	}
}

 

整個實作非常的簡單,只是在建構子這邊擷取剪貼簿的內容與設定Timer,然後叫用InitializationComplete,後面就只是定時的去看剪貼簿是否有所更動。Uniqueid屬性這邊筆者也只是簡單的傳回一個識別用的GUID,而Dispose方法因為該類別沒什麼非託管的資源,這邊就姑且讓它是空的。

 

這邊寫個簡單的Console程式測試一下:


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CustomChangeMonitorDemo
{
	class Program
	{
		[STAThread]
		static void Main(string[] args)
		{
			FileContentProvider textFile = new FileContentProvider();
			Stopwatch sw = new Stopwatch();
			while (true)
			{
				sw.Reset();
				sw.Start();
				Console.WriteLine(textFile.Content);
				sw.Stop();
				Console.WriteLine("Elapsed Time: {0} ms", sw.ElapsedMilliseconds);
				Console.WriteLine(new string('=', 50));
				Console.ReadLine();
				Application.DoEvents();
			}
		}
	}

	public class FileContentProvider
	{
		public String Content
		{
			get
			{
				const string CACHE_KEY = "Content";
				string content = m_Cache[CACHE_KEY] as string;
				if (content == null)
				{
					CacheItemPolicy policy = new CacheItemPolicy();
					//policy.SlidingExpiration = TimeSpan.FromMilliseconds(1500);

					var changeMonitor = new ClipboardChangeMonitor();

					policy.ChangeMonitors.Add(changeMonitor);

					content = Guid.NewGuid().ToString();
					Thread.Sleep(1000);
					m_Cache.Set(CACHE_KEY, content, policy);
				}
				return content;
			}
		}

		private ObjectCache _cache;
		private ObjectCache m_Cache
		{
			get
			{
				if (_cache == null)
					_cache = MemoryCache.Default;
				return _cache;
			}
		}
	}
}

 

運行起來會像下面這樣,不論怎麼按Enter更新,Cache的GUID都是一樣的。

image

 

但是一經選取複製。

image

 

ClipboardChangeMonitor就會偵測到剪貼簿有變動,Cache的資料就會過期進而更新,因此複製完後按下Enter更新,這邊會重新抓取新的Guid。

image

 

若有需要可至CustomChangeMonitorDemo下載完整的程式範例。

 

Link