File: System\Messaging\BinaryMessageFormatter.cs
Project: ndp\cdf\src\NetFx20\System.Messaging\System.Messaging.csproj (System.Messaging)
//------------------------------------------------------------------------------
// <copyright file="BinaryMessageFormatter.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Messaging
{
    using System;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Diagnostics;
    using System.IO;
    using System.ComponentModel;
 
    /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter"]/*' />
    /// <devdoc>
    ///    Formatter class that serializes and deserializes objects into
    ///    and from  MessageQueue messages using binary format.
    /// </devdoc>             
    public class BinaryMessageFormatter : IMessageFormatter
    {
        private BinaryFormatter formatter;
        internal const short VT_BINARY_OBJECT = 0x300;
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.BinaryMessageFormatter"]/*' />
        /// <devdoc>
        ///    Creates a new Binary message formatter object.
        /// </devdoc>
        public BinaryMessageFormatter()
        {
            this.formatter = new BinaryFormatter();
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.BinaryMessageFormatter1"]/*' />
        /// <devdoc>
        ///    Creates a new Binary message formatter object 
        ///    with the given properties.
        /// </devdoc>
        public BinaryMessageFormatter(FormatterAssemblyStyle topObjectFormat, FormatterTypeStyle typeFormat)
        {
            this.formatter = new BinaryFormatter();
            this.formatter.AssemblyFormat = topObjectFormat;
            this.formatter.TypeFormat = typeFormat;
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.TopObjectFormat"]/*' />
        /// <devdoc>
        ///    Determines how the top (root) object of a graph
        ///    is laid out in the serialized stream.
        /// </devdoc>
        [MessagingDescription(Res.MsgTopObjectFormat), DefaultValueAttribute(FormatterAssemblyStyle.Simple)]
        public FormatterAssemblyStyle TopObjectFormat
        {
            get
            {
                return this.formatter.AssemblyFormat;
            }
 
            set
            {
                this.formatter.AssemblyFormat = value;
            }
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.TypeFormat"]/*' />
        /// <devdoc>
        ///    Determines how type descriptions are laid out in the
        ///    serialized stream.
        /// </devdoc>
        [MessagingDescription(Res.MsgTypeFormat), DefaultValueAttribute(FormatterTypeStyle.TypesWhenNeeded)]
        public FormatterTypeStyle TypeFormat
        {
            get
            {
                return this.formatter.TypeFormat;
            }
 
            set
            {
                this.formatter.TypeFormat = value;
            }
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.CanRead"]/*' />
        /// <devdoc>
        ///    <para>When this method is called, the formatter will attempt to determine
        ///       if the contents of the message are something the formatter can deal with.</para>
        /// </devdoc>
        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;
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.Clone"]/*' />
        /// <devdoc>
        ///    This method is needed to improve scalability on Receive and ReceiveAsync scenarios.  Not requiring 
        ///     thread safety on read and write.
        /// </devdoc>
        public object Clone()
        {
            return new BinaryMessageFormatter(TopObjectFormat, TypeFormat);
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.Read"]/*' />
        /// <devdoc>
        ///    This method is used to read the contents from the given message 
        ///     and create an object.
        /// </devdoc>
        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));
        }
 
        /// <include file='doc\BinaryMessageFormatter.uex' path='docs/doc[@for="BinaryMessageFormatter.Write"]/*' />
        /// <devdoc>
        ///    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.
        /// </devdoc>
        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;
        }
    }
}