//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
namespace Experimental.System.Messaging
{
///
///
/// Formatter class that serializes and deserializes objects into
/// and from MessageQueue messages using binary format.
///
public class BinaryMessageFormatter : IMessageFormatter
{
private BinaryFormatter formatter;
internal const short VT_BINARY_OBJECT = 0x300;
///
///
/// Creates a new Binary message formatter object.
///
public BinaryMessageFormatter()
{
this.formatter = new BinaryFormatter();
}
///
///
/// Creates a new Binary message formatter object
/// with the given properties.
///
public BinaryMessageFormatter(FormatterAssemblyStyle topObjectFormat, FormatterTypeStyle typeFormat)
{
this.formatter = new BinaryFormatter();
this.formatter.AssemblyFormat = topObjectFormat;
this.formatter.TypeFormat = typeFormat;
}
///
///
/// Determines how the top (root) object of a graph
/// is laid out in the serialized stream.
///
[MessagingDescription(Res.MsgTopObjectFormat), DefaultValueAttribute(FormatterAssemblyStyle.Simple)]
public FormatterAssemblyStyle TopObjectFormat
{
get
{
return this.formatter.AssemblyFormat;
}
set
{
this.formatter.AssemblyFormat = value;
}
}
///
///
/// Determines how type descriptions are laid out in the
/// serialized stream.
///
[MessagingDescription(Res.MsgTypeFormat), DefaultValueAttribute(FormatterTypeStyle.TypesWhenNeeded)]
public FormatterTypeStyle TypeFormat
{
get
{
return this.formatter.TypeFormat;
}
set
{
this.formatter.TypeFormat = value;
}
}
///
///
/// When this method is called, the formatter will attempt to determine
/// if the contents of the message are something the formatter can deal with.
///
public bool CanRead(Message message)
{
if (message == null)
throw new ArgumentNullException("message");
int variantType = message.BodyType;
if (variantType != VT_BINARY_OBJECT)
return false;
return true;
}
///
///
/// This method is needed to improve scalability on Receive and ReceiveAsync scenarios. Not requiring
/// thread safety on read and write.
///
public object Clone()
{
return new BinaryMessageFormatter(TopObjectFormat, TypeFormat);
}
///
///
/// This method is used to read the contents from the given message
/// and create an object.
///
public object Read(Message message)
{
if (message == null)
throw new ArgumentNullException("message");
int variantType = message.BodyType;
if (variantType == VT_BINARY_OBJECT)
{
Stream stream = message.BodyStream;
return formatter.Deserialize(stream);
}
throw new InvalidOperationException(Res.GetString(Res.InvalidTypeDeserialization));
}
///
///
/// This method is used to write the given object into the given message.
/// If the formatter cannot understand the given object, an exception is thrown.
///
public void Write(Message message, object obj)
{
if (message == null)
throw new ArgumentNullException("message");
Stream stream = new MemoryStream();
formatter.Serialize(stream, obj);
message.BodyType = VT_BINARY_OBJECT;
message.BodyStream = stream;
}
}
}