File: System\ServiceModel\MsmqIntegration\MsmqIntegrationChannelFactory.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------  
// Copyright (c) Microsoft Corporation.  All rights reserved.   
//------------------------------------------------------------  
namespace System.ServiceModel.MsmqIntegration
{
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Runtime.Serialization.Formatters.Binary; // for BinaryFormatter
    using System.Xml.Serialization; // for XmlSerializer 
    using System.IO; // for Stream
    using System.Collections.Specialized; //For HybridDictionary
    using System.ServiceModel.Channels;
 
    sealed class MsmqIntegrationChannelFactory : MsmqChannelFactoryBase<IOutputChannel>
    {
        ActiveXSerializer activeXSerializer;
        BinaryFormatter binaryFormatter;
        MsmqMessageSerializationFormat serializationFormat;
        HybridDictionary xmlSerializerTable;
        const int maxSerializerTableSize = 1024;
 
        internal MsmqIntegrationChannelFactory(MsmqIntegrationBindingElement bindingElement, BindingContext context)
            : base(bindingElement, context, null)
        {
            this.serializationFormat = bindingElement.SerializationFormat;
        }
 
        BinaryFormatter BinaryFormatter
        {
            get
            {
                if (this.binaryFormatter == null)
                {
                    lock (ThisLock)
                    {
                        if (this.binaryFormatter == null)
                            this.binaryFormatter = new BinaryFormatter();
                    }
                }
 
                return this.binaryFormatter;
            }
        }
 
 
        ActiveXSerializer ActiveXSerializer
        {
            get
            {
                if (this.activeXSerializer == null)
                {
                    lock (ThisLock)
                    {
                        if (this.activeXSerializer == null)
                            this.activeXSerializer = new ActiveXSerializer();
                    }
                }
 
                return this.activeXSerializer;
            }
        }
 
 
        XmlSerializer GetXmlSerializerForType(Type serializedType)
        {
            if (this.xmlSerializerTable == null)
            {
                lock (ThisLock)
                {
                    if (this.xmlSerializerTable == null)
                        this.xmlSerializerTable = new HybridDictionary();
                }
            }
 
            XmlSerializer serializer = (XmlSerializer)this.xmlSerializerTable[serializedType];
            if (serializer != null)
            {
                return serializer;
            }
 
            lock (ThisLock)
            {
                if (this.xmlSerializerTable.Count >= maxSerializerTableSize)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CommunicationException(SR.GetString(SR.MsmqSerializationTableFull, maxSerializerTableSize)));
                // double-locking
                serializer = (XmlSerializer)this.xmlSerializerTable[serializedType];
                if (serializer != null)
                {
                    return serializer;
                }
 
                serializer = new XmlSerializer(serializedType);
                this.xmlSerializerTable[serializedType] = serializer;
 
                return serializer;
            }
        }
 
 
        public MsmqMessageSerializationFormat SerializationFormat
        {
            get
            {
                ThrowIfDisposed();
                return this.serializationFormat;
            }
        }
 
        protected override IOutputChannel OnCreateChannel(EndpointAddress to, Uri via)
        {
            base.ValidateScheme(via);
            return new MsmqIntegrationOutputChannel(this, to, via, ManualAddressing);
        }
 
        //
        // Returns stream containing serialized body
        // In case of MsmqMessageSerializationFormat.Stream,
        // returns body as Stream, and throws exception if body is not a Stream
        //
        internal Stream Serialize(MsmqIntegrationMessageProperty property)
        {
            Stream stream;
            switch (this.SerializationFormat)
            {
                case MsmqMessageSerializationFormat.Xml:
                    stream = new MemoryStream();
                    XmlSerializer serializer = GetXmlSerializerForType(property.Body.GetType());
                    serializer.Serialize(stream, property.Body);
                    return stream;
 
                case MsmqMessageSerializationFormat.Binary:
                    stream = new MemoryStream();
                    BinaryFormatter.Serialize(stream, property.Body);
                    // need to set BodyType to a magic number used by System.Messaging
                    property.BodyType = 0x300;
                    return stream;
 
                case MsmqMessageSerializationFormat.ActiveX:
                    if (property.BodyType.HasValue)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqCannotUseBodyTypeWithActiveXSerialization)));
                    }
 
                    stream = new MemoryStream();
                    int bodyType = 0;
                    ActiveXSerializer.Serialize(stream as MemoryStream, property.Body, ref bodyType);
                    property.BodyType = bodyType;
                    return stream;
 
                case MsmqMessageSerializationFormat.ByteArray:
                    // body MUST be byte array
                    byte[] byteArray = property.Body as byte[];
                    if (byteArray == null)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.MsmqByteArrayBodyExpected)));
 
                    stream = new MemoryStream();
                    stream.Write(byteArray, 0, byteArray.Length);
                    return stream;
 
                case MsmqMessageSerializationFormat.Stream:
                    // body MUST be a stream
                    Stream bodyStream = property.Body as Stream;
                    if (bodyStream == null)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.MsmqStreamBodyExpected)));
 
                    // NOTE: we don't copy here as a perf optimization, but this might be dangerous
                    return bodyStream;
 
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.GetString(SR.MsmqUnsupportedSerializationFormat, this.SerializationFormat)));
            }
 
        }
 
    }
}