1

我試圖創建使用命名管道交叉應用asp.net緩存服務(類似於memcached的,或AppFabric中/速度)。基本前提是您可以獲取或設置連接到命名管道的任何其他應用程序共享的緩存項目。序列化包裝類的命名管道運輸

這需要將發送到緩存的對象序列化爲byte []以方便PipeStream.Read()和PipeStream.Write()方法。由於高速緩存將保持任意數量任意對象類型/類的,我不希望有設置在每一個[Serializable]屬性,所以我選擇創建一個包裝類,這將是[Serializable接口],並有通用對象類型的字段,我可以用來傳輸緩存項目,類似於這裏使用的方法:http://www.eggheadcafe.com/articles/20060404.asp

一切似乎最初的內置類型,但現在我試圖發送列表<>的對象是一個自定義類型(一個類),我得到一個異常,我的自定義類需要[序列化] ...這正是我想要避免的。

下面的代碼:

服務器 -

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()); 
      } 
     } 
    } 
} 

Client方法(靜態類) -

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); 
    } 
} 

最後的特別使用cas Ë導致了一個問題:

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)) 

引發的異常是在ToBytes()方法調用bf.Serialize(MS,這一點),它說: 「在'Assembly'API版本= 1.0.0.0,Culture = neutral,PublicKeyToken = null'中鍵入'MemCachedSession''未標記爲可序列化'」

(編輯)爲什麼會這樣,和/或我是否在正確的軌道上做我想做的事情?(編輯)

總體思路是,封裝類(CACHEACTION)將可序列化的,以防止這一點,這確實工作在一定程度上,但不是這個自定義類(MemCachedSession)。

很抱歉的大問題,或許答案不是簡單的是(即整個方法是錯誤的),但如果任何人都可以花時間給一些有識之士我們將不勝感激! 謝謝,

+1

你實際上似乎忘了寫這個問題。 – asawyer

+0

謝謝,明確添加問題。 – evilertoaster

回答

1

默認情況下,串行器能夠只序列化基本類型。任何其他類型必須使用屬性Serializable進行標記才能符合序列化條件。

舉個例子:

[Serializable] class AClass { 
    int myInt; 
    long myLong; 
    string myString; 
} 

[Serializable] class BClass { 
    int myInt; 
    AClass myAClass; 
} 

[Serializable] class CClass { 
    int myInt; 
    DClass otherClass; 
} 

class DClass { 
    int myInt; 
    long myLong; 
    string myString; 
} 

AClass可序列化,因爲它僅包含原語和裝飾爲Serializable

BClass可以序列化,因爲它是整個對象圖是原始的或Serializable

CClass裝飾爲Serializable,但在嘗試序列化時會拋出錯誤,因爲它包含的成員不是。這可以通過將otherClass聲明替換爲[NonSerialized] DClass otherClass;來避免,但這不會幫助您解決您的情況,因爲該成員不會按照屬性暗示的順序與對象圖的其餘部分進行序列化。

DClass不能序列,即使它不包含任何非原始字段,因爲它不是作爲裝飾Serializable

的更多信息可以在MSDN網站上找到:http://msdn.microsoft.com/en-us/library/vstudio/ms233843.aspx

TLDR;整個方法都是錯誤的 - 所有緩存的對象都必須標記爲Serializable。