|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System.Collections;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Reflection;
using System.Xml;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Channels;
using System.Runtime.Diagnostics;
using System.Runtime;
using System.Threading;
abstract class OperationFormatter : IClientMessageFormatter, IDispatchMessageFormatter
{
MessageDescription replyDescription;
MessageDescription requestDescription;
XmlDictionaryString action;
XmlDictionaryString replyAction;
protected StreamFormatter requestStreamFormatter, replyStreamFormatter;
XmlDictionary dictionary;
string operationName;
static object[] emptyObjectArray = new object[0];
public OperationFormatter(OperationDescription description, bool isRpc, bool isEncoded)
{
Validate(description, isRpc, isEncoded);
this.requestDescription = description.Messages[0];
if (description.Messages.Count == 2)
this.replyDescription = description.Messages[1];
int stringCount = 3 + requestDescription.Body.Parts.Count;
if (replyDescription != null)
stringCount += 2 + replyDescription.Body.Parts.Count;
dictionary = new XmlDictionary(stringCount * 2);
GetActions(description, dictionary, out this.action, out this.replyAction);
operationName = description.Name;
requestStreamFormatter = StreamFormatter.Create(requestDescription, operationName, true/*isRequest*/);
if (replyDescription != null)
replyStreamFormatter = StreamFormatter.Create(replyDescription, operationName, false/*isResponse*/);
}
protected abstract void AddHeadersToMessage(Message message, MessageDescription messageDescription, object[] parameters, bool isRequest);
protected abstract void SerializeBody(XmlDictionaryWriter writer, MessageVersion version, string action, MessageDescription messageDescription, object returnValue, object[] parameters, bool isRequest);
protected abstract void GetHeadersFromMessage(Message message, MessageDescription messageDescription, object[] parameters, bool isRequest);
protected abstract object DeserializeBody(XmlDictionaryReader reader, MessageVersion version, string action, MessageDescription messageDescription, object[] parameters, bool isRequest);
protected virtual void WriteBodyAttributes(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
}
internal string RequestAction
{
get
{
if (action != null)
return action.Value;
return null;
}
}
internal string ReplyAction
{
get
{
if (replyAction != null)
return replyAction.Value;
return null;
}
}
protected XmlDictionary Dictionary
{
get { return dictionary; }
}
protected string OperationName
{
get { return this.operationName; }
}
protected MessageDescription ReplyDescription
{
get { return replyDescription; }
}
protected MessageDescription RequestDescription
{
get { return requestDescription; }
}
protected XmlDictionaryString AddToDictionary(string s)
{
return AddToDictionary(dictionary, s);
}
public object DeserializeReply(Message message, object[] parameters)
{
if (message == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
if (parameters == null)
throw TraceUtility.ThrowHelperError(new ArgumentNullException("parameters"), message);
try
{
object result = null;
if (replyDescription.IsTypedMessage)
{
object typeMessageInstance = CreateTypedMessageInstance(replyDescription.MessageType);
TypedMessageParts typedMessageParts = new TypedMessageParts(typeMessageInstance, replyDescription);
object[] parts = new object[typedMessageParts.Count];
GetPropertiesFromMessage(message, replyDescription, parts);
GetHeadersFromMessage(message, replyDescription, parts, false/*isRequest*/);
DeserializeBodyContents(message, parts, false/*isRequest*/);
// copy values into the actual field/properties
typedMessageParts.SetTypedMessageParts(parts);
result = typeMessageInstance;
}
else
{
GetPropertiesFromMessage(message, replyDescription, parameters);
GetHeadersFromMessage(message, replyDescription, parameters, false/*isRequest*/);
result = DeserializeBodyContents(message, parameters, false/*isRequest*/);
}
return result;
}
catch (XmlException xe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, this.operationName, xe.Message), xe));
}
catch (FormatException fe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, this.operationName, fe.Message), fe));
}
catch (SerializationException se)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
SR.GetString(SR.SFxErrorDeserializingReplyBodyMore, this.operationName, se.Message), se));
}
}
private static object CreateTypedMessageInstance(Type messageContractType)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.NonPublic;
try
{
object typeMessageInstance = Activator.CreateInstance(
messageContractType,
bindingFlags,
null, emptyObjectArray, null);
return typeMessageInstance;
}
catch (MissingMethodException mme)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxMessageContractRequiresDefaultConstructor, messageContractType.FullName), mme));
}
}
public void DeserializeRequest(Message message, object[] parameters)
{
if (message == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
if (parameters == null)
throw TraceUtility.ThrowHelperError(new ArgumentNullException("parameters"), message);
try
{
if (requestDescription.IsTypedMessage)
{
object typeMessageInstance = CreateTypedMessageInstance(requestDescription.MessageType);
TypedMessageParts typedMessageParts = new TypedMessageParts(typeMessageInstance, requestDescription);
object[] parts = new object[typedMessageParts.Count];
GetPropertiesFromMessage(message, requestDescription, parts);
GetHeadersFromMessage(message, requestDescription, parts, true/*isRequest*/);
DeserializeBodyContents(message, parts, true/*isRequest*/);
// copy values into the actual field/properties
typedMessageParts.SetTypedMessageParts(parts);
parameters[0] = typeMessageInstance;
}
else
{
GetPropertiesFromMessage(message, requestDescription, parameters);
GetHeadersFromMessage(message, requestDescription, parameters, true/*isRequest*/);
DeserializeBodyContents(message, parameters, true/*isRequest*/);
}
}
catch (XmlException xe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
OperationFormatter.CreateDeserializationFailedFault(
SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, this.operationName, xe.Message),
xe));
}
catch (FormatException fe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
OperationFormatter.CreateDeserializationFailedFault(
SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, this.operationName, fe.Message),
fe));
}
catch (SerializationException se)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
SR.GetString(SR.SFxErrorDeserializingRequestBodyMore, this.operationName, se.Message),
se));
}
}
object DeserializeBodyContents(Message message, object[] parameters, bool isRequest)
{
MessageDescription messageDescription;
StreamFormatter streamFormatter;
SetupStreamAndMessageDescription(isRequest, out streamFormatter, out messageDescription);
if (streamFormatter != null)
{
object retVal = null;
streamFormatter.Deserialize(parameters, ref retVal, message);
return retVal;
}
if (message.IsEmpty)
{
return null;
}
else
{
XmlDictionaryReader reader = message.GetReaderAtBodyContents();
using (reader)
{
object body = DeserializeBody(reader, message.Version, RequestAction, messageDescription, parameters, isRequest);
message.ReadFromBodyContentsToEnd(reader);
return body;
}
}
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
object[] parts = null;
if (messageVersion == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageVersion");
if (parameters == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters");
if (requestDescription.IsTypedMessage)
{
TypedMessageParts typedMessageParts = new TypedMessageParts(parameters[0], requestDescription);
// copy values from the actual field/properties
parts = new object[typedMessageParts.Count];
typedMessageParts.GetTypedMessageParts(parts);
}
else
{
parts = parameters;
}
Message msg = new OperationFormatterMessage(this, messageVersion,
action == null ? null : ActionHeader.Create(action, messageVersion.Addressing),
parts, null, true/*isRequest*/);
AddPropertiesToMessage(msg, requestDescription, parts);
AddHeadersToMessage(msg, requestDescription, parts, true /*isRequest*/);
return msg;
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
object[] parts = null;
object resultPart = null;
if (messageVersion == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageVersion");
if (parameters == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters");
if (replyDescription.IsTypedMessage)
{
// If the response is a typed message then it must
// me the response (as opposed to an out param). We will
// serialize the response in the exact same way that we
// would serialize a bunch of outs (with no return value).
TypedMessageParts typedMessageParts = new TypedMessageParts(result, replyDescription);
// make a copy of the list so that we have the actual values of the field/properties
parts = new object[typedMessageParts.Count];
typedMessageParts.GetTypedMessageParts(parts);
resultPart = null;
}
else
{
parts = parameters;
resultPart = result;
}
Message msg = new OperationFormatterMessage(this, messageVersion,
replyAction == null ? null : ActionHeader.Create(replyAction, messageVersion.Addressing),
parts, resultPart, false/*isRequest*/);
AddPropertiesToMessage(msg, replyDescription, parts);
AddHeadersToMessage(msg, replyDescription, parts, false /*isRequest*/);
return msg;
}
void SetupStreamAndMessageDescription(bool isRequest, out StreamFormatter streamFormatter, out MessageDescription messageDescription)
{
if (isRequest)
{
streamFormatter = requestStreamFormatter;
messageDescription = requestDescription;
}
else
{
streamFormatter = replyStreamFormatter;
messageDescription = replyDescription;
}
}
void SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, object[] parameters, object returnValue, bool isRequest)
{
MessageDescription messageDescription;
StreamFormatter streamFormatter;
SetupStreamAndMessageDescription(isRequest, out streamFormatter, out messageDescription);
if (streamFormatter != null)
{
streamFormatter.Serialize(writer, parameters, returnValue);
return;
}
SerializeBody(writer, version, RequestAction, messageDescription, returnValue, parameters, isRequest);
}
IAsyncResult BeginSerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, object[] parameters, object returnValue, bool isRequest,
AsyncCallback callback, object state)
{
return new SerializeBodyContentsAsyncResult(this, writer, version, parameters, returnValue, isRequest, callback, state);
}
void EndSerializeBodyContents(IAsyncResult result)
{
SerializeBodyContentsAsyncResult.End(result);
}
class SerializeBodyContentsAsyncResult : AsyncResult
{
static AsyncCompletion handleEndSerializeBodyContents = new AsyncCompletion(HandleEndSerializeBodyContents);
StreamFormatter streamFormatter;
internal SerializeBodyContentsAsyncResult(OperationFormatter operationFormatter, XmlDictionaryWriter writer, MessageVersion version, object[] parameters,
object returnValue, bool isRequest, AsyncCallback callback, object state)
: base(callback, state)
{
bool completeSelf = true;
MessageDescription messageDescription;
StreamFormatter streamFormatter;
operationFormatter.SetupStreamAndMessageDescription(isRequest, out streamFormatter, out messageDescription);
if (streamFormatter != null)
{
this.streamFormatter = streamFormatter;
IAsyncResult result = streamFormatter.BeginSerialize(writer, parameters, returnValue, PrepareAsyncCompletion(handleEndSerializeBodyContents), this);
completeSelf = SyncContinue(result);
}
else
{
operationFormatter.SerializeBody(writer, version, operationFormatter.RequestAction, messageDescription, returnValue, parameters, isRequest);
completeSelf = true;
}
if (completeSelf)
{
Complete(true);
}
}
static bool HandleEndSerializeBodyContents(IAsyncResult result)
{
SerializeBodyContentsAsyncResult thisPtr = (SerializeBodyContentsAsyncResult)result.AsyncState;
thisPtr.streamFormatter.EndSerialize(result);
return true;
}
public static void End(IAsyncResult result)
{
AsyncResult.End<SerializeBodyContentsAsyncResult>(result);
}
}
void AddPropertiesToMessage(Message message, MessageDescription messageDescription, object[] parameters)
{
if (messageDescription.Properties.Count > 0)
{
AddPropertiesToMessageCore(message, messageDescription, parameters);
}
}
void AddPropertiesToMessageCore(Message message, MessageDescription messageDescription, object[] parameters)
{
MessageProperties properties = message.Properties;
MessagePropertyDescriptionCollection propertyDescriptions = messageDescription.Properties;
for (int i = 0; i < propertyDescriptions.Count; i++)
{
MessagePropertyDescription propertyDescription = propertyDescriptions[i];
object parameter = parameters[propertyDescription.Index];
if (null != parameter)
properties.Add(propertyDescription.Name, parameter);
}
}
void GetPropertiesFromMessage(Message message, MessageDescription messageDescription, object[] parameters)
{
if (messageDescription.Properties.Count > 0)
{
GetPropertiesFromMessageCore(message, messageDescription, parameters);
}
}
void GetPropertiesFromMessageCore(Message message, MessageDescription messageDescription, object[] parameters)
{
MessageProperties properties = message.Properties;
MessagePropertyDescriptionCollection propertyDescriptions = messageDescription.Properties;
for (int i = 0; i < propertyDescriptions.Count; i++)
{
MessagePropertyDescription propertyDescription = propertyDescriptions[i];
if (properties.ContainsKey(propertyDescription.Name))
{
parameters[propertyDescription.Index] = properties[propertyDescription.Name];
}
}
}
internal static object GetContentOfMessageHeaderOfT(MessageHeaderDescription headerDescription, object parameterValue, out bool mustUnderstand, out bool relay, out string actor)
{
actor = headerDescription.Actor;
mustUnderstand = headerDescription.MustUnderstand;
relay = headerDescription.Relay;
if (headerDescription.TypedHeader && parameterValue != null)
parameterValue = TypedHeaderManager.GetContent(headerDescription.Type, parameterValue, out mustUnderstand, out relay, out actor);
return parameterValue;
}
internal static bool IsValidReturnValue(MessagePartDescription returnValue)
{
return (returnValue != null) && (returnValue.Type != typeof(void));
}
internal static XmlDictionaryString AddToDictionary(XmlDictionary dictionary, string s)
{
XmlDictionaryString dictionaryString;
if (!dictionary.TryLookup(s, out dictionaryString))
{
dictionaryString = dictionary.Add(s);
}
return dictionaryString;
}
internal static void Validate(OperationDescription operation, bool isRpc, bool isEncoded)
{
if (isEncoded && !isRpc)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDocEncodedNotSupported, operation.Name)));
}
bool hasVoid = false;
bool hasTypedOrUntypedMessage = false;
bool hasParameter = false;
for (int i = 0; i < operation.Messages.Count; i++)
{
MessageDescription message = operation.Messages[i];
if (message.IsTypedMessage || message.IsUntypedMessage)
{
if (isRpc && operation.IsValidateRpcWrapperName)
{
if (!isEncoded)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxTypedMessageCannotBeRpcLiteral, operation.Name)));
}
hasTypedOrUntypedMessage = true;
}
else if (message.IsVoid)
hasVoid = true;
else
hasParameter = true;
}
if (hasParameter && hasTypedOrUntypedMessage)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxTypedOrUntypedMessageCannotBeMixedWithParameters, operation.Name)));
if (isRpc && hasTypedOrUntypedMessage && hasVoid)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxTypedOrUntypedMessageCannotBeMixedWithVoidInRpc, operation.Name)));
}
internal static void GetActions(OperationDescription description, XmlDictionary dictionary, out XmlDictionaryString action, out XmlDictionaryString replyAction)
{
string actionString, replyActionString;
actionString = description.Messages[0].Action;
if (actionString == MessageHeaders.WildcardAction)
actionString = null;
if (!description.IsOneWay)
replyActionString = description.Messages[1].Action;
else
replyActionString = null;
if (replyActionString == MessageHeaders.WildcardAction)
replyActionString = null;
action = replyAction = null;
if (actionString != null)
action = AddToDictionary(dictionary, actionString);
if (replyActionString != null)
replyAction = AddToDictionary(dictionary, replyActionString);
}
internal static NetDispatcherFaultException CreateDeserializationFailedFault(string reason, Exception innerException)
{
reason = SR.GetString(SR.SFxDeserializationFailed1, reason);
FaultCode code = new FaultCode(FaultCodeConstants.Codes.DeserializationFailed, FaultCodeConstants.Namespaces.NetDispatch);
code = FaultCode.CreateSenderFaultCode(code);
return new NetDispatcherFaultException(reason, code, innerException);
}
internal static void TraceAndSkipElement(XmlReader xmlReader)
{
if (DiagnosticUtility.ShouldTraceVerbose)
{
TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.ElementIgnored, SR.GetString(SR.SFxTraceCodeElementIgnored), new StringTraceRecord("Element", xmlReader.NamespaceURI + ":" + xmlReader.LocalName));
}
xmlReader.Skip();
}
class TypedMessageParts
{
object instance;
MemberInfo[] members;
public TypedMessageParts(object instance, MessageDescription description)
{
if (description == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("description"));
}
if (instance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(SR.GetString(SR.SFxTypedMessageCannotBeNull, description.Action)));
}
members = new MemberInfo[description.Body.Parts.Count + description.Properties.Count + description.Headers.Count];
foreach (MessagePartDescription part in description.Headers)
members[part.Index] = part.MemberInfo;
foreach (MessagePartDescription part in description.Properties)
members[part.Index] = part.MemberInfo;
foreach (MessagePartDescription part in description.Body.Parts)
members[part.Index] = part.MemberInfo;
this.instance = instance;
}
object GetValue(int index)
{
MemberInfo memberInfo = members[index];
if (memberInfo.MemberType == MemberTypes.Property)
{
return ((PropertyInfo)members[index]).GetValue(instance, null);
}
else
{
return ((FieldInfo)members[index]).GetValue(instance);
}
}
void SetValue(object value, int index)
{
MemberInfo memberInfo = members[index];
if (memberInfo.MemberType == MemberTypes.Property)
{
((PropertyInfo)members[index]).SetValue(instance, value, null);
}
else
{
((FieldInfo)members[index]).SetValue(instance, value);
}
}
internal void GetTypedMessageParts(object[] values)
{
for (int i = 0; i < this.members.Length; i++)
{
values[i] = GetValue(i);
}
}
internal void SetTypedMessageParts(object[] values)
{
for (int i = 0; i < this.members.Length; i++)
{
SetValue(values[i], i);
}
}
internal int Count
{
get { return this.members.Length; }
}
}
internal class OperationFormatterMessage : BodyWriterMessage
{
OperationFormatter operationFormatter;
public OperationFormatterMessage(OperationFormatter operationFormatter, MessageVersion version, ActionHeader action,
object[] parameters, object returnValue, bool isRequest)
: base(version, action, new OperationFormatterBodyWriter(operationFormatter, version, parameters, returnValue, isRequest))
{
this.operationFormatter = operationFormatter;
}
public OperationFormatterMessage(MessageVersion version, string action, BodyWriter bodyWriter) : base(version, action, bodyWriter) { }
OperationFormatterMessage(MessageHeaders headers, KeyValuePair<string, object>[] properties, OperationFormatterBodyWriter bodyWriter)
: base(headers, properties, bodyWriter)
{
operationFormatter = bodyWriter.OperationFormatter;
}
protected override void OnWriteStartBody(XmlDictionaryWriter writer)
{
base.OnWriteStartBody(writer);
operationFormatter.WriteBodyAttributes(writer, this.Version);
}
protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
{
BodyWriter bufferedBodyWriter;
if (BodyWriter.IsBuffered)
{
bufferedBodyWriter = base.BodyWriter;
}
else
{
bufferedBodyWriter = base.BodyWriter.CreateBufferedCopy(maxBufferSize);
}
KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[base.Properties.Count];
((ICollection<KeyValuePair<string, object>>)base.Properties).CopyTo(properties, 0);
return new OperationFormatterMessageBuffer(base.Headers, properties, bufferedBodyWriter);
}
class OperationFormatterBodyWriter : BodyWriter
{
bool isRequest;
OperationFormatter operationFormatter;
object[] parameters;
object returnValue;
MessageVersion version;
bool onBeginWriteBodyContentsCalled;
public OperationFormatterBodyWriter(OperationFormatter operationFormatter, MessageVersion version,
object[] parameters, object returnValue, bool isRequest)
: base(AreParametersBuffered(isRequest, operationFormatter))
{
this.parameters = parameters;
this.returnValue = returnValue;
this.isRequest = isRequest;
this.operationFormatter = operationFormatter;
this.version = version;
}
object ThisLock
{
get { return this; }
}
static bool AreParametersBuffered(bool isRequest, OperationFormatter operationFormatter)
{
StreamFormatter streamFormatter = isRequest ? operationFormatter.requestStreamFormatter : operationFormatter.replyStreamFormatter;
return streamFormatter == null;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
lock (ThisLock)
{
this.operationFormatter.SerializeBodyContents(writer, this.version, this.parameters, this.returnValue, this.isRequest);
}
}
protected override IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
{
Fx.Assert(!onBeginWriteBodyContentsCalled, "OnBeginWriteBodyContents has already been called");
this.onBeginWriteBodyContentsCalled = true;
return new OnWriteBodyContentsAsyncResult(this, writer, callback, state);
}
protected override void OnEndWriteBodyContents(IAsyncResult result)
{
OnWriteBodyContentsAsyncResult.End(result);
}
internal OperationFormatter OperationFormatter
{
get { return operationFormatter; }
}
class OnWriteBodyContentsAsyncResult : AsyncResult
{
static AsyncCompletion handleEndOnWriteBodyContents = new AsyncCompletion(HandleEndOnWriteBodyContents);
OperationFormatter operationFormatter;
internal OnWriteBodyContentsAsyncResult(OperationFormatterBodyWriter operationFormatterBodyWriter, XmlDictionaryWriter writer, AsyncCallback callback, object state)
: base(callback, state)
{
bool completeSelf = true;
this.operationFormatter = operationFormatterBodyWriter.OperationFormatter;
IAsyncResult result = this.operationFormatter.BeginSerializeBodyContents(writer, operationFormatterBodyWriter.version,
operationFormatterBodyWriter.parameters, operationFormatterBodyWriter.returnValue, operationFormatterBodyWriter.isRequest,
PrepareAsyncCompletion(handleEndOnWriteBodyContents), this);
completeSelf = SyncContinue(result);
if (completeSelf)
{
Complete(true);
}
}
static bool HandleEndOnWriteBodyContents(IAsyncResult result)
{
OnWriteBodyContentsAsyncResult thisPtr = (OnWriteBodyContentsAsyncResult)result.AsyncState;
thisPtr.operationFormatter.EndSerializeBodyContents(result);
return true;
}
public static void End(IAsyncResult result)
{
AsyncResult.End<OnWriteBodyContentsAsyncResult>(result);
}
}
}
class OperationFormatterMessageBuffer : BodyWriterMessageBuffer
{
public OperationFormatterMessageBuffer(MessageHeaders headers,
KeyValuePair<string, object>[] properties, BodyWriter bodyWriter)
: base(headers, properties, bodyWriter)
{
}
public override Message CreateMessage()
{
OperationFormatterBodyWriter operationFormatterBodyWriter = base.BodyWriter as OperationFormatterBodyWriter;
if (operationFormatterBodyWriter == null)
return base.CreateMessage();
lock (ThisLock)
{
if (base.Closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
return new OperationFormatterMessage(base.Headers, base.Properties, operationFormatterBodyWriter);
}
}
}
}
internal abstract class OperationFormatterHeader : MessageHeader
{
protected MessageHeader innerHeader; //use innerHeader to handle versionSupported, actor/role handling etc.
protected OperationFormatter operationFormatter;
protected MessageVersion version;
public OperationFormatterHeader(OperationFormatter operationFormatter, MessageVersion version, string name, string ns, bool mustUnderstand, string actor, bool relay)
{
this.operationFormatter = operationFormatter;
this.version = version;
if (actor != null)
innerHeader = MessageHeader.CreateHeader(name, ns, null/*headerValue*/, mustUnderstand, actor, relay);
else
innerHeader = MessageHeader.CreateHeader(name, ns, null/*headerValue*/, mustUnderstand, "", relay);
}
public override bool IsMessageVersionSupported(MessageVersion messageVersion)
{
return innerHeader.IsMessageVersionSupported(messageVersion);
}
public override string Name
{
get { return innerHeader.Name; }
}
public override string Namespace
{
get { return innerHeader.Namespace; }
}
public override bool MustUnderstand
{
get { return innerHeader.MustUnderstand; }
}
public override bool Relay
{
get { return innerHeader.Relay; }
}
public override string Actor
{
get { return innerHeader.Actor; }
}
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
//Prefix needed since there may be xsi:type attribute at toplevel with qname value where ns = ""
writer.WriteStartElement((this.Namespace == null || this.Namespace.Length == 0) ? string.Empty : "h", this.Name, this.Namespace);
OnWriteHeaderAttributes(writer, messageVersion);
}
protected virtual void OnWriteHeaderAttributes(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
base.WriteHeaderAttributes(writer, messageVersion);
}
}
internal class XmlElementMessageHeader : OperationFormatterHeader
{
protected XmlElement headerValue;
public XmlElementMessageHeader(OperationFormatter operationFormatter, MessageVersion version, string name, string ns, bool mustUnderstand, string actor, bool relay, XmlElement headerValue) :
base(operationFormatter, version, name, ns, mustUnderstand, actor, relay)
{
this.headerValue = headerValue;
}
protected override void OnWriteHeaderAttributes(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
base.WriteHeaderAttributes(writer, messageVersion);
XmlDictionaryReader nodeReader = XmlDictionaryReader.CreateDictionaryReader(new XmlNodeReader(headerValue));
nodeReader.MoveToContent();
writer.WriteAttributes(nodeReader, false);
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
headerValue.WriteContentTo(writer);
}
}
internal struct QName
{
internal string Name;
internal string Namespace;
internal QName(string name, string ns)
{
Name = name;
Namespace = ns;
}
}
internal class QNameComparer : IEqualityComparer<QName>
{
static internal QNameComparer Singleton = new QNameComparer();
QNameComparer() { }
public bool Equals(QName x, QName y)
{
return x.Name == y.Name && x.Namespace == y.Namespace;
}
public int GetHashCode(QName obj)
{
return obj.Name.GetHashCode();
}
}
internal class MessageHeaderDescriptionTable : Dictionary<QName, MessageHeaderDescription>
{
internal MessageHeaderDescriptionTable() : base(QNameComparer.Singleton) { }
internal void Add(string name, string ns, MessageHeaderDescription message)
{
base.Add(new QName(name, ns), message);
}
internal MessageHeaderDescription Get(string name, string ns)
{
MessageHeaderDescription message;
if (base.TryGetValue(new QName(name, ns), out message))
return message;
return null;
}
}
}
}
|