我有一个Streaming WCF服务。它接收一个名为ContentObjectData
的序列化类的流。我从流中收到的字节暂时放在ArrayList
中,因为我不知道Stream
有多大,说实话我不知道该怎么做无论如何,和他们一起。
ContentObjectData类:
[Serializable]
public class ContentObjectData
{
string Hash { get; set; }
string Data { get; set; }
string FileName { get; set; }
string DisplayImage { get; set; }
}
这是从客户端接收流的服务方法。
[OperationContract]
public void SendContentObject(Stream data)
{
ArrayList alBytes = new ArrayList();
Console.WriteLine("Client connected");
int count;
byte[] buffer = new byte[4096];
while ((count = data.Read(buffer, 0, buffer.Length)) > 0)
{
alBytes.AddRange(buffer);
}
long i = alBytes.Count;
data.Close();
}
此时我正在使用以下方法发送图像进行测试:
private void btnLoadImage_Click(object sender, EventArgs e)
{
DialogResult dr = OFD.ShowDialog();
if (dr == DialogResult.OK)
{
foreach (string filename in OFD.FileNames)
{
try
{
ContentObject co = new ContentObject();
co.Data = LoadFile(filename);
co.Hash = Hashing.HashString(co.Data);
co.DisplayImage = co.Data;
co.FileName = co.Hash;
Stream stream = SerializeToStream(co);
SendContentObject(stream);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
private void SendContentObject(Stream stream)
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);
// TimeSpan.MaxValue is interpreted with a rounding error, so use 24 days instead
binding.SendTimeout = TimeSpan.FromDays(24);
binding.TransferMode = TransferMode.Streamed;
ChannelFactory<RaptorStreamingHost> factory = new ChannelFactory<RaptorStreamingHost>(
binding, new EndpointAddress("net.tcp://ccs-labs.com:804/"));
RaptorStreamingHost service = factory.CreateChannel();
service.SendContentObject(stream);
((IClientChannel)service).Close();
}
private string LoadFile(string filename)
{
return Hashing.BytesToString(File.ReadAllBytes(filename));
}
public static Stream SerializeToStream(object objectType)
{
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, objectType);
stream.Position = 0L; // REMEMBER to reset stream or WCF will just send the stream from the end resulting in an empty stream!
return (Stream)stream;
}
我对DeSerialize有这个,但对我来说没有多大意义:
public static object DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object objectType = formatter.Deserialize(stream);
return objectType;
}
如何将Bytes的ArrayList(我猜DeSerialize它们)转换为新的ContentObject?
更新一个 啊这么近! 好的,这个方法
public static ContentObjectData DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
ContentObjectData objectType = (ContentObjectData)formatter.Deserialize(stream);
return objectType;
}
我有问题。 Deserializer无法找到ContentObjectData
,因为它在ContentObjectData
的客户端命名空间中查找,而不是此Host的命名空间。
答案 0 :(得分:1)
首先,不要使用ArrayList
来存储字节。由于ArrayList
是非泛型的,因此每个字节将为boxed,并且指向保存在数组中的字节的指针,这将使用超过必要的5(32位)或9(64位)倍的内存。
相反,您可以将Stream
复制到本地MemoryStream
,然后保存基础byte []
数组:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
}
[OperationContract]
public void SendContentObject(Stream data)
{
Console.WriteLine("Client connected");
var memoryStream = new MemoryStream();
using (data)
CopyStream(data, memoryStream);
byte [] alBytes = memoryStream.ToArray();
}
之后您可以将byte []
数组转回MemoryStream
进行反序列化:
public static object DeserializeFromStream(byte [] allBytes)
{
using (var stream = new MemoryStream(allBytes))
return DeserializeFromStream(stream);
}
public static object DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object objectType = formatter.Deserialize(stream);
return objectType;
}
(或者,只需保留原始MemoryStream
并传递它。)
<强>更新强>
BinaryFormatter
将完整的.Net类型信息(即fully qualified type name)序列化到序列化流中。如果接收系统没有具有完全相同名称的类型,在完全相同的命名空间中,在完全相同的程序集中,则反序列化失败。
如果这是您的情况,您有以下解决方法:
提取包含相关类型的共享DLL,并将其链接到客户端和服务器;问题解决了。
编写SerializationBinder
以映射类型程序集和名称。有关如何操作的说明,请参阅here以及here或here。
考虑一种不同的,更加面向合约的二进制格式。 Bson是一种选择。 protobuf-net是另一个,虽然我还没用过。更多here。