C# 命名管道传输的可序列化包装类
我正在尝试使用命名管道创建跨应用程序的asp.net缓存服务(类似于memcached或AppFabric/Velocity)。基本前提是,您可以获取或设置连接到命名管道的任何其他应用程序之间共享的缓存项 其中一部分要求将发送到缓存的对象序列化为字节[],以便于使用PipeStream.Read()和PipeStream.Write()方法。由于缓存将容纳任意数量的任意对象类型/类,我不想在每个对象上都设置[Serializable]属性,因此我选择创建一个包装类,该包装类将是[Serializable],并具有一个可用于传输缓存项的通用对象类型字段,类似于此处使用的方法: 起初,对于内置类型,一切似乎都正常,但现在我尝试发送一个自定义类型(类)的对象列表,并且我得到一个异常,我的自定义类需要是[可序列化]…这正是我试图避免的 代码如下: 服务器-C# 命名管道传输的可序列化包装类,c#,serialization,deserialization,named-pipes,binaryformatter,C#,Serialization,Deserialization,Named Pipes,Binaryformatter,我正在尝试使用命名管道创建跨应用程序的asp.net缓存服务(类似于memcached或AppFabric/Velocity)。基本前提是,您可以获取或设置连接到命名管道的任何其他应用程序之间共享的缓存项 其中一部分要求将发送到缓存的对象序列化为字节[],以便于使用PipeStream.Read()和PipeStream.Write()方法。由于缓存将容纳任意数量的任意对象类型/类,我不想在每个对象上都设置[Serializable]属性,因此我选择创建一个包装类,该包装类将是[Serializ
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());
}
}
}
}
共享代码:
[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))
SetItem(“MemCacheSessionStateProvider”,new List(),new TimeSpan(7,0,0,0))
调用bf.Serialize(ms,this)时,ToBytes()方法中引发了异常,它说:
程序集“API,版本=1.0.0.0,区域性=中性,PublicKeyToken=null”中的类型“MemCachedSession”未标记为可序列化。”
(编辑)为什么会这样,和/或我是否在做我想做的事情的正确轨道上?(编辑)
整个想法是封装类(CacheAction)是可序列化的,以防止出现这种情况,这在某种程度上是可行的,但不适用于这个自定义类(MemCachedSession)
很抱歉问了这么大的问题,也许答案也不简单(即整个方法是错误的),但如果有人能抽出时间提供一些见解,我们将不胜感激!
谢谢,默认情况下,序列化程序只能序列化基元类型。任何其他类型都必须用属性
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
可以序列化,因为它的整个对象图是基本的或可序列化的
CClass
被修饰为Serializable
,但在尝试序列化时将抛出错误,因为它包含一个不可序列化的成员。这可以通过将otherClass
声明替换为[NonSerialized]DClass otherClass来防止代码>,但这对您的情况没有帮助,因为该成员不会像属性所暗示的那样与对象图的其余部分序列化
DClass
无法序列化,即使它不包含任何非原语字段,因为它未装饰为可序列化的
有关更多信息,请访问MSDN网站:
TLDR;整个方法都是错误的——所有缓存对象都必须标记为可序列化。默认情况下,序列化程序只能序列化基本类型。任何其他类型都必须用属性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
可以序列化,因为它的整个对象图是基本的或可序列化的
CClass
被修饰为Serializable
,但在尝试序列化时将抛出错误,因为它包含一个不可序列化的成员。这可以通过将otherClass
声明替换为[NonSerialized]DClass otherClass来防止代码>,但这对您的情况没有帮助,因为该成员不会像属性所暗示的那样与对象图的其余部分序列化
DClass
无法序列化,即使它不包含任何非原语字段,因为它未装饰为可序列化的
有关更多信息,请访问MSDN网站:
TLDR;整个方法是错误的——所有缓存对象都必须标记为可序列化。您实际上似乎忘记了编写问题。谢谢,明确添加了问题。您实际上似乎忘记了编写问题。谢谢,明确添加了问题。