名前付きパイプを使用してクロスアプリケーション asp.net キャッシュ サービス (memcached または AppFabric/Velocity に類似) を作成しようとしています。基本的な前提は、名前付きパイプに接続する他のアプリケーション間で共有されるキャッシュ項目を取得または設定できることです。
これには、PipeStream.Read() および PipeStream.Write() メソッドを容易にするために、キャッシュに送信するオブジェクトを byte[] にシリアル化する必要があります。キャッシュには任意のオブジェクト タイプ/クラスがいくつでも保持されるため、それぞれに [Serializable] 属性を設定する必要はありません。そのため、[Serializable] であるラッパー クラスを作成することにしました。ここで使用されている方法と同様に、キャッシュ アイテムを転送するために使用できる汎用オブジェクト型フィールド: http://www.eggheadcafe.com/articles/20060404.asp
最初はすべて組み込み型で機能しているように見えましたが、カスタム型 (クラス) のオブジェクトの List<> を送信しようとすると、カスタム クラスが [ である必要があるという例外が発生します。 Serializable]...これは私が避けようとしているものです。
コードは次のとおりです。
サーバ-
class Server
{
static Dictionary<string, object> Cache = new Dictionary<string, object>();
static Dictionary<string, DateTime> CacheExpireTime = new Dictionary<string, DateTime>();
static void Main(string[] args)
{
new Thread(HandleGets).Start();
new Thread(HandleSets).Start();
}
static protected void HandleSets()
{
PipeSecurity ps = new PipeSecurity();
PipeAccessRule par = new PipeAccessRule("Everyone", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
ps.AddAccessRule(par);
while (true)
{
using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("MemCacheSet", PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0, ps))
{
pipeServer.WaitForConnection();
CacheAction ca = CacheAction.FromBytes(pipeServer.ReadAll());
Cache[ca.DictionaryKey] = ca.DictionaryValue;
CacheExpireTime[ca.DictionaryKey] = ca.TimeOfExpire;
}
}
}
static protected void HandleGets()
{
PipeSecurity ps = new PipeSecurity();
PipeAccessRule par = new PipeAccessRule("Everyone", PipeAccessRights.ReadWrite, System.Security.AccessControl.AccessControlType.Allow);
ps.AddAccessRule(par);
while (true)
{
using (NamedPipeServerStream pipeServer = new NamedPipeServerStream("MemCacheGet", PipeDirection.InOut,1,PipeTransmissionMode.Byte,PipeOptions.None,0,0,ps))
{
pipeServer.WaitForConnection();
CacheAction ca = CacheAction.FromBytes(pipeServer.ReadAll());
CacheAction resp = new CacheAction();
resp.DictionaryKey = ca.DictionaryKey;
if (Cache.ContainsKey(ca.DictionaryKey) && CacheExpireTime[ca.DictionaryKey]>=DateTime.Now)
resp.DictionaryValue = Cache[ca.DictionaryKey];
pipeServer.WriteAll(resp.ToBytes());
}
}
}
}
クライアント メソッド (静的クラス内)-
static object GetItem(string inKey)
{
object rVal;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "MemCacheGet", PipeDirection.InOut))
{
pipeStream.Connect();
CacheAction ca = new CacheAction();
ca.DictionaryKey = inKey;
pipeStream.WriteAll(ca.ToBytes());
ca = CacheAction.FromBytes(pipeStream.ReadAll());
rVal = ca.DictionaryValue;
}
return rVal;
}
static void SetItem(string inName, object inItem, TimeSpan? expireTime = null)
{
if (!expireTime.HasValue)
expireTime = new TimeSpan(0, 10, 0);
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "MemCacheSet", PipeDirection.Out))
{
pipeStream.Connect();
CacheAction ca = new CacheAction();
ca.DictionaryKey = inName;
ca.DictionaryValue = inItem;
ca.TimeOfExpire = DateTime.Now + expireTime.Value;
pipeStream.WriteAll(ca.ToBytes());
}
}
共有コード:
[Serializable]
public class CacheAction
{
public string DictionaryKey;
public object DictionaryValue;
public DateTime TimeOfExpire;
public static CacheAction FromBytes(byte[] inBytes)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream(inBytes);
CacheAction p = (CacheAction)bf.Deserialize(ms);
return p;
}
public byte[] ToBytes()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, this);
return ms.ToArray();
}
}
public static class MyExtensions
{
public static byte[] ReadAll(this NamedPipeClientStream np)
{
byte[] size = new byte[4];
np.Read(size, 0, 4);
int iSize = BitConverter.ToInt32(size, 0);
byte[] rVal = new byte[iSize];
np.Read(rVal, 0, iSize);
return rVal;
}
public static byte[] ReadAll(this NamedPipeServerStream np)
{
byte[] size = new byte[4];
np.Read(size, 0, 4);
int iSize = BitConverter.ToInt32(size, 0);
byte[] rVal = new byte[iSize];
np.Read(rVal, 0, iSize);
return rVal;
}
public static void WriteAll(this NamedPipeClientStream np, byte[] toWrite)
{
byte[] size = BitConverter.GetBytes(toWrite.Length);
np.Write(size, 0, size.Length);
np.Write(toWrite, 0, toWrite.Length);
}
public static void WriteAll(this NamedPipeServerStream np, byte[] toWrite)
{
byte[] size = BitConverter.GetBytes(toWrite.Length);
np.Write(size, 0, size.Length);
np.Write(toWrite, 0, toWrite.Length);
}
}
最後に、問題を引き起こす特定の使用例:
class MemCachedSession
{
public string SessionId { get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
public DateTime LockDate { get; set; }
public int LockId { get; set; }
public int Timeout { get; set; }
public bool Locked { get; set; }
public string SessionItems { get; set; }
public int Flags { get; set; }
}
次のように使用します。
SetItem("MemCacheSessionStateProvider", new List<MemCachedSession>(), new TimeSpan(7, 0, 0, 0, 0))
スローされた例外は、bf.Serialize(ms,this) の呼び出しで ToBytes() メソッドにあり、次のように表示されます。シリアライズ可能としてマークされていません。」
(編集)それはなぜですか?(編集)
全体的なアイデアは、これを防ぐためにカプセル化クラス (CacheAction) をシリアライズ可能にすることでした。これはある程度機能しますが、このカスタム クラス (MemCachedSession) では機能しません。
大きな質問で申し訳ありませんが、答えも単純ではないかもしれません(つまり、方法論全体が間違っています)が、誰かが時間をかけて洞察を与えることができれば幸いです!ありがとう、