123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- //------------------------------------------------------------------------------
- // <copyright file="XmlMessageFormatter.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- //------------------------------------------------------------------------------
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.Xml;
- using System.Xml.Serialization;
- namespace Experimental.System.Messaging
- {
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter"]/*' />
- /// <devdoc>
- /// Formatter class that serializes and deserializes objects into
- /// and from MessageQueue messages using Xml.
- /// </devdoc>
- public class XmlMessageFormatter : IMessageFormatter
- {
- private Type[] targetTypes;
- private string[] targetTypeNames;
- Hashtable targetSerializerTable = new Hashtable();
- private bool typeNamesAdded;
- private bool typesAdded;
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.XmlMessageFormatter"]/*' />
- /// <devdoc>
- /// Creates a new Xml message formatter object.
- /// </devdoc>
- public XmlMessageFormatter()
- {
- this.TargetTypes = new Type[0];
- this.TargetTypeNames = new string[0];
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.XmlMessageFormatter1"]/*' />
- /// <devdoc>
- /// Creates a new Xml message formatter object,
- /// using the given properties.
- /// </devdoc>
- public XmlMessageFormatter(string[] targetTypeNames)
- {
- this.TargetTypeNames = targetTypeNames;
- this.TargetTypes = new Type[0];
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.XmlMessageFormatter2"]/*' />
- /// <devdoc>
- /// Creates a new Xml message formatter object,
- /// using the given properties.
- /// </devdoc>
- public XmlMessageFormatter(Type[] targetTypes)
- {
- this.TargetTypes = targetTypes;
- this.TargetTypeNames = new string[0];
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.TargetTypeNames"]/*' />
- /// <devdoc>
- /// Specifies the set of possible types that will
- /// be deserialized by the formatter from the
- /// message provided.
- /// </devdoc>
- [MessagingDescription(Res.XmlMsgTargetTypeNames)]
- [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
- [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
- public string[] TargetTypeNames
- {
- get
- {
- return this.targetTypeNames;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException("value");
- this.typeNamesAdded = false;
- this.targetTypeNames = value;
- }
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.TargetTypes"]/*' />
- /// <devdoc>
- /// Specifies the set of possible types that will
- /// be deserialized by the formatter from the
- /// message provided.
- /// </devdoc>
- [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.XmlMsgTargetTypes)]
- [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
- [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
- public Type[] TargetTypes
- {
- get
- {
- return this.targetTypes;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException("value");
- this.typesAdded = false;
- this.targetTypes = value;
- }
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.CanRead"]/*' />
- /// <devdoc>
- /// When this method is called, the formatter will attempt to determine
- /// if the contents of the message are something the formatter can deal with.
- /// </devdoc>
- public bool CanRead(Message message)
- {
- if (message == null)
- throw new ArgumentNullException("message");
- this.CreateTargetSerializerTable();
- Stream stream = message.BodyStream;
- XmlTextReader reader = new XmlTextReader(stream);
- reader.WhitespaceHandling = WhitespaceHandling.Significant;
- reader.DtdProcessing = DtdProcessing.Prohibit;
- bool result = false;
- foreach (XmlSerializer serializer in targetSerializerTable.Values)
- {
- if (serializer.CanDeserialize(reader))
- {
- result = true;
- break;
- }
- }
- message.BodyStream.Position = 0; // reset stream in case CanRead is followed by Deserialize
- return result;
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.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()
- {
- XmlMessageFormatter formatter = new XmlMessageFormatter();
- formatter.targetTypes = targetTypes;
- formatter.targetTypeNames = targetTypeNames;
- formatter.typesAdded = typesAdded;
- formatter.typeNamesAdded = typeNamesAdded;
- foreach (Type targetType in targetSerializerTable.Keys)
- formatter.targetSerializerTable[targetType] = new XmlSerializer(targetType);
- return formatter;
- }
- /// <internalonly/>
- private void CreateTargetSerializerTable()
- {
- if (!this.typeNamesAdded)
- {
- for (int index = 0; index < this.targetTypeNames.Length; ++index)
- {
- Type targetType = Type.GetType(this.targetTypeNames[index], true);
- if (targetType != null)
- this.targetSerializerTable[targetType] = new XmlSerializer(targetType);
- }
- this.typeNamesAdded = true;
- }
- if (!this.typesAdded)
- {
- for (int index = 0; index < this.targetTypes.Length; ++index)
- this.targetSerializerTable[this.targetTypes[index]] = new XmlSerializer(this.targetTypes[index]);
- this.typesAdded = true;
- }
- if (this.targetSerializerTable.Count == 0)
- throw new InvalidOperationException(Res.GetString(Res.TypeListMissing));
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.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");
- this.CreateTargetSerializerTable();
- Stream stream = message.BodyStream;
- XmlTextReader reader = new XmlTextReader(stream);
- reader.WhitespaceHandling = WhitespaceHandling.Significant;
- reader.DtdProcessing = DtdProcessing.Prohibit;
- foreach (XmlSerializer serializer in targetSerializerTable.Values)
- {
- if (serializer.CanDeserialize(reader))
- return serializer.Deserialize(reader);
- }
- throw new InvalidOperationException(Res.GetString(Res.InvalidTypeDeserialization));
- }
- /// <include file='doc\XmlMessageFormatter.uex' path='docs/doc[@for="XmlMessageFormatter.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");
- if (obj == null)
- throw new ArgumentNullException("obj");
- Stream stream = new MemoryStream();
- Type serializedType = obj.GetType();
- XmlSerializer serializer = null;
- if (this.targetSerializerTable.ContainsKey(serializedType))
- serializer = (XmlSerializer)this.targetSerializerTable[serializedType];
- else
- {
- serializer = new XmlSerializer(serializedType);
- this.targetSerializerTable[serializedType] = serializer;
- }
- serializer.Serialize(stream, obj);
- message.BodyStream = stream;
- //Need to reset the body type, in case the same message
- //is reused by some other formatter.
- message.BodyType = 0;
- }
- }
- }
|