|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Description
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Runtime;
using System.Security;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Xml;
using System.Xml.Serialization;
public class XmlSerializerOperationBehavior : IOperationBehavior, IWsdlExportExtension
{
readonly Reflector.OperationReflector reflector;
readonly bool builtInOperationBehavior;
public XmlSerializerOperationBehavior(OperationDescription operation)
: this(operation, null)
{
}
public XmlSerializerOperationBehavior(OperationDescription operation, XmlSerializerFormatAttribute attribute)
{
if (operation == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation");
#pragma warning suppress 56506 // Declaring contract cannot be null
Reflector parentReflector = new Reflector(operation.DeclaringContract.Namespace, operation.DeclaringContract.ContractType);
#pragma warning suppress 56506 // parentReflector cannot be null
this.reflector = parentReflector.ReflectOperation(operation, attribute ?? new XmlSerializerFormatAttribute());
}
internal XmlSerializerOperationBehavior(OperationDescription operation, XmlSerializerFormatAttribute attribute, Reflector parentReflector)
: this(operation, attribute)
{
// used by System.ServiceModel.Web
this.reflector = parentReflector.ReflectOperation(operation, attribute ?? new XmlSerializerFormatAttribute());
}
XmlSerializerOperationBehavior(Reflector.OperationReflector reflector, bool builtInOperationBehavior)
{
Fx.Assert(reflector != null, "");
this.reflector = reflector;
this.builtInOperationBehavior = builtInOperationBehavior;
}
internal Reflector.OperationReflector OperationReflector
{
get { return this.reflector; }
}
internal bool IsBuiltInOperationBehavior
{
get { return this.builtInOperationBehavior; }
}
public XmlSerializerFormatAttribute XmlSerializerFormatAttribute
{
get
{
return this.reflector.Attribute;
}
}
internal static XmlSerializerOperationFormatter CreateOperationFormatter(OperationDescription operation)
{
return new XmlSerializerOperationBehavior(operation).CreateFormatter();
}
internal static XmlSerializerOperationFormatter CreateOperationFormatter(OperationDescription operation, XmlSerializerFormatAttribute attr)
{
return new XmlSerializerOperationBehavior(operation, attr).CreateFormatter();
}
internal static void AddBehaviors(ContractDescription contract)
{
AddBehaviors(contract, false);
}
internal static void AddBuiltInBehaviors(ContractDescription contract)
{
AddBehaviors(contract, true);
}
static void AddBehaviors(ContractDescription contract, bool builtInOperationBehavior)
{
Reflector reflector = new Reflector(contract.Namespace, contract.ContractType);
foreach (OperationDescription operation in contract.Operations)
{
Reflector.OperationReflector operationReflector = reflector.ReflectOperation(operation);
if (operationReflector != null)
{
bool isInherited = operation.DeclaringContract != contract;
if (!isInherited)
{
operation.Behaviors.Add(new XmlSerializerOperationBehavior(operationReflector, builtInOperationBehavior));
operation.Behaviors.Add(new XmlSerializerOperationGenerator(new XmlSerializerImportOptions()));
}
}
}
}
internal XmlSerializerOperationFormatter CreateFormatter()
{
return new XmlSerializerOperationFormatter(reflector.Operation, reflector.Attribute, reflector.Request, reflector.Reply);
}
XmlSerializerFaultFormatter CreateFaultFormatter(SynchronizedCollection<FaultContractInfo> faultContractInfos)
{
return new XmlSerializerFaultFormatter(faultContractInfos, reflector.XmlSerializerFaultContractInfos);
}
void IOperationBehavior.Validate(OperationDescription description)
{
}
void IOperationBehavior.AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
if (description == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
if (dispatch == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dispatch");
if (dispatch.Formatter == null)
{
dispatch.Formatter = (IDispatchMessageFormatter)CreateFormatter();
dispatch.DeserializeRequest = reflector.RequestRequiresSerialization;
dispatch.SerializeReply = reflector.ReplyRequiresSerialization;
}
if (reflector.Attribute.SupportFaults)
{
if (!dispatch.IsFaultFormatterSetExplicit)
{
dispatch.FaultFormatter = (IDispatchFaultFormatter)CreateFaultFormatter(dispatch.FaultContractInfos);
}
else
{
var wrapper = dispatch.FaultFormatter as IDispatchFaultFormatterWrapper;
if (wrapper != null)
{
wrapper.InnerFaultFormatter = (IDispatchFaultFormatter)CreateFaultFormatter(dispatch.FaultContractInfos);
}
}
}
}
void IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
if (description == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
if (proxy == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("proxy");
if (proxy.Formatter == null)
{
proxy.Formatter = (IClientMessageFormatter)CreateFormatter();
proxy.SerializeRequest = reflector.RequestRequiresSerialization;
proxy.DeserializeReply = reflector.ReplyRequiresSerialization;
}
if (reflector.Attribute.SupportFaults && !proxy.IsFaultFormatterSetExplicit)
proxy.FaultFormatter = (IClientFaultFormatter)CreateFaultFormatter(proxy.FaultContractInfos);
}
void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext endpointContext)
{
if (exporter == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
if (endpointContext == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointContext");
MessageContractExporter.ExportMessageBinding(exporter, endpointContext, typeof(XmlSerializerMessageContractExporter), this.reflector.Operation);
}
void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext contractContext)
{
if (exporter == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
if (contractContext == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contractContext");
new XmlSerializerMessageContractExporter(exporter, contractContext, this.reflector.Operation, this).ExportMessageContract();
}
public Collection<XmlMapping> GetXmlMappings()
{
Collection<XmlMapping> mappings = new Collection<XmlMapping>();
if (OperationReflector.Request != null && OperationReflector.Request.HeadersMapping != null)
mappings.Add(OperationReflector.Request.HeadersMapping);
if (OperationReflector.Request != null && OperationReflector.Request.BodyMapping != null)
mappings.Add(OperationReflector.Request.BodyMapping);
if (OperationReflector.Reply != null && OperationReflector.Reply.HeadersMapping != null)
mappings.Add(OperationReflector.Reply.HeadersMapping);
if (OperationReflector.Reply != null && OperationReflector.Reply.BodyMapping != null)
mappings.Add(OperationReflector.Reply.BodyMapping);
return mappings;
}
// helper for reflecting operations
internal class Reflector
{
readonly XmlSerializerImporter importer;
readonly SerializerGenerationContext generation;
Collection<OperationReflector> operationReflectors = new Collection<OperationReflector>();
object thisLock = new object();
internal Reflector(string defaultNs, Type type)
{
this.importer = new XmlSerializerImporter(defaultNs);
this.generation = new SerializerGenerationContext(type);
}
internal void EnsureMessageInfos()
{
lock (this.thisLock)
{
foreach (OperationReflector operationReflector in operationReflectors)
{
operationReflector.EnsureMessageInfos();
}
}
}
static XmlSerializerFormatAttribute FindAttribute(OperationDescription operation)
{
Type contractType = operation.DeclaringContract != null ? operation.DeclaringContract.ContractType : null;
XmlSerializerFormatAttribute contractFormatAttribute = contractType != null ? TypeLoader.GetFormattingAttribute(contractType, null) as XmlSerializerFormatAttribute : null;
return TypeLoader.GetFormattingAttribute(operation.OperationMethod, contractFormatAttribute) as XmlSerializerFormatAttribute;
}
// auto-reflects the operation, returning null if no attribute was found or inherited
internal OperationReflector ReflectOperation(OperationDescription operation)
{
XmlSerializerFormatAttribute attr = FindAttribute(operation);
if (attr == null)
return null;
return ReflectOperation(operation, attr);
}
// overrides the auto-reflection with an attribute
internal OperationReflector ReflectOperation(OperationDescription operation, XmlSerializerFormatAttribute attrOverride)
{
OperationReflector operationReflector = new OperationReflector(this, operation, attrOverride, true/*reflectOnDemand*/);
operationReflectors.Add(operationReflector);
return operationReflector;
}
internal class OperationReflector
{
readonly Reflector parent;
internal readonly OperationDescription Operation;
internal readonly XmlSerializerFormatAttribute Attribute;
internal readonly bool IsEncoded;
internal readonly bool IsRpc;
internal readonly bool IsOneWay;
internal readonly bool RequestRequiresSerialization;
internal readonly bool ReplyRequiresSerialization;
readonly string keyBase;
MessageInfo request;
MessageInfo reply;
SynchronizedCollection<XmlSerializerFaultContractInfo> xmlSerializerFaultContractInfos;
internal OperationReflector(Reflector parent, OperationDescription operation, XmlSerializerFormatAttribute attr, bool reflectOnDemand)
{
Fx.Assert(parent != null, "");
Fx.Assert(operation != null, "");
Fx.Assert(attr != null, "");
OperationFormatter.Validate(operation, attr.Style == OperationFormatStyle.Rpc, attr.IsEncoded);
this.parent = parent;
this.Operation = operation;
this.Attribute = attr;
this.IsEncoded = attr.IsEncoded;
this.IsRpc = (attr.Style == OperationFormatStyle.Rpc);
this.IsOneWay = operation.Messages.Count == 1;
this.RequestRequiresSerialization = !operation.Messages[0].IsUntypedMessage;
this.ReplyRequiresSerialization = !this.IsOneWay && !operation.Messages[1].IsUntypedMessage;
MethodInfo methodInfo = operation.OperationMethod;
if (methodInfo == null)
{
// keyBase needs to be unique within the scope of the parent reflector
keyBase = string.Empty;
if (operation.DeclaringContract != null)
{
keyBase = operation.DeclaringContract.Name + "," + operation.DeclaringContract.Namespace + ":";
}
keyBase = keyBase + operation.Name;
}
else
keyBase = methodInfo.DeclaringType.FullName + ":" + methodInfo.ToString();
foreach (MessageDescription message in operation.Messages)
foreach (MessageHeaderDescription header in message.Headers)
SetUnknownHeaderInDescription(header);
if (!reflectOnDemand)
{
this.EnsureMessageInfos();
}
}
private void SetUnknownHeaderInDescription(MessageHeaderDescription header)
{
if (this.IsEncoded) //XmlAnyElementAttribute does not apply
return;
if (header.AdditionalAttributesProvider != null)
{
XmlAttributes xmlAttributes = new XmlAttributes(header.AdditionalAttributesProvider);
foreach (XmlAnyElementAttribute anyElement in xmlAttributes.XmlAnyElements)
{
if (String.IsNullOrEmpty(anyElement.Name))
{
header.IsUnknownHeaderCollection = true;
}
}
}
}
string ContractName
{
get { return this.Operation.DeclaringContract.Name; }
}
string ContractNamespace
{
get { return this.Operation.DeclaringContract.Namespace; }
}
internal MessageInfo Request
{
get
{
parent.EnsureMessageInfos();
return this.request;
}
}
internal MessageInfo Reply
{
get
{
parent.EnsureMessageInfos();
return this.reply;
}
}
internal SynchronizedCollection<XmlSerializerFaultContractInfo> XmlSerializerFaultContractInfos
{
get
{
parent.EnsureMessageInfos();
return this.xmlSerializerFaultContractInfos;
}
}
internal void EnsureMessageInfos()
{
if (this.request == null)
{
foreach (Type knownType in Operation.KnownTypes)
{
if (knownType == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxKnownTypeNull, Operation.Name)));
parent.importer.IncludeType(knownType, IsEncoded);
}
this.request = CreateMessageInfo(this.Operation.Messages[0], ":Request");
if (this.request != null && this.IsRpc && this.Operation.IsValidateRpcWrapperName && this.request.BodyMapping.XsdElementName != this.Operation.Name)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxRpcMessageBodyPartNameInvalid, Operation.Name, this.Operation.Messages[0].MessageName, request.BodyMapping.XsdElementName, this.Operation.Name)));
if (!this.IsOneWay)
{
this.reply = CreateMessageInfo(this.Operation.Messages[1], ":Response");
XmlName responseName = TypeLoader.GetBodyWrapperResponseName(this.Operation.Name);
if (this.reply != null && this.IsRpc && this.Operation.IsValidateRpcWrapperName && this.reply.BodyMapping.XsdElementName != responseName.EncodedName)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxRpcMessageBodyPartNameInvalid, Operation.Name, this.Operation.Messages[1].MessageName, reply.BodyMapping.XsdElementName, responseName.EncodedName)));
}
if (this.Attribute.SupportFaults)
{
GenerateXmlSerializerFaultContractInfos();
}
}
}
void GenerateXmlSerializerFaultContractInfos()
{
SynchronizedCollection<XmlSerializerFaultContractInfo> faultInfos = new SynchronizedCollection<XmlSerializerFaultContractInfo>();
for (int i = 0; i < this.Operation.Faults.Count; i++)
{
FaultDescription fault = this.Operation.Faults[i];
FaultContractInfo faultContractInfo = new FaultContractInfo(fault.Action, fault.DetailType, fault.ElementName, fault.Namespace, this.Operation.KnownTypes);
XmlQualifiedName elementName;
XmlMembersMapping xmlMembersMapping = this.ImportFaultElement(fault, out elementName);
SerializerStub serializerStub = parent.generation.AddSerializer(xmlMembersMapping);
faultInfos.Add(new XmlSerializerFaultContractInfo(faultContractInfo, serializerStub, elementName));
}
this.xmlSerializerFaultContractInfos = faultInfos;
}
MessageInfo CreateMessageInfo(MessageDescription message, string key)
{
if (message.IsUntypedMessage)
return null;
MessageInfo info = new MessageInfo();
if (message.IsTypedMessage)
key = message.MessageType.FullName + ":" + IsEncoded + ":" + IsRpc;
XmlMembersMapping headersMapping = LoadHeadersMapping(message, key + ":Headers");
info.SetHeaders(parent.generation.AddSerializer(headersMapping));
MessagePartDescriptionCollection rpcEncodedTypedMessgeBodyParts;
info.SetBody(parent.generation.AddSerializer(LoadBodyMapping(message, key, out rpcEncodedTypedMessgeBodyParts)), rpcEncodedTypedMessgeBodyParts);
CreateHeaderDescriptionTable(message, info, headersMapping);
return info;
}
private void CreateHeaderDescriptionTable(MessageDescription message, MessageInfo info, XmlMembersMapping headersMapping)
{
int headerNameIndex = 0;
OperationFormatter.MessageHeaderDescriptionTable headerDescriptionTable = new OperationFormatter.MessageHeaderDescriptionTable();
info.SetHeaderDescriptionTable(headerDescriptionTable);
foreach (MessageHeaderDescription header in message.Headers)
{
if (header.IsUnknownHeaderCollection)
info.SetUnknownHeaderDescription(header);
else if (headersMapping != null)
{
XmlMemberMapping memberMapping = headersMapping[headerNameIndex++];
string headerName, headerNs;
if (IsEncoded)
{
headerName = memberMapping.TypeName;
headerNs = memberMapping.TypeNamespace;
}
else
{
headerName = memberMapping.XsdElementName;
headerNs = memberMapping.Namespace;
}
if (headerName != header.Name)
{
if (message.MessageType != null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxHeaderNameMismatchInMessageContract, message.MessageType, header.MemberInfo.Name, header.Name, headerName)));
else
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxHeaderNameMismatchInOperation, this.Operation.Name, this.Operation.DeclaringContract.Name, this.Operation.DeclaringContract.Namespace, header.Name, headerName)));
}
if (headerNs != header.Namespace)
{
if (message.MessageType != null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxHeaderNamespaceMismatchInMessageContract, message.MessageType, header.MemberInfo.Name, header.Namespace, headerNs)));
else
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxHeaderNamespaceMismatchInOperation, this.Operation.Name, this.Operation.DeclaringContract.Name, this.Operation.DeclaringContract.Namespace, header.Namespace, headerNs)));
}
headerDescriptionTable.Add(headerName, headerNs, header);
}
}
}
XmlMembersMapping LoadBodyMapping(MessageDescription message, string mappingKey, out MessagePartDescriptionCollection rpcEncodedTypedMessageBodyParts)
{
MessagePartDescription returnPart;
string wrapperName, wrapperNs;
MessagePartDescriptionCollection bodyParts;
if (IsEncoded && message.IsTypedMessage && message.Body.WrapperName == null)
{
MessagePartDescription wrapperPart = GetWrapperPart(message);
returnPart = null;
rpcEncodedTypedMessageBodyParts = bodyParts = GetWrappedParts(wrapperPart);
wrapperName = wrapperPart.Name;
wrapperNs = wrapperPart.Namespace;
}
else
{
rpcEncodedTypedMessageBodyParts = null;
returnPart = OperationFormatter.IsValidReturnValue(message.Body.ReturnValue) ? message.Body.ReturnValue : null;
bodyParts = message.Body.Parts;
wrapperName = message.Body.WrapperName;
wrapperNs = message.Body.WrapperNamespace;
}
bool isWrapped = (wrapperName != null);
bool hasReturnValue = returnPart != null;
int paramCount = bodyParts.Count + (hasReturnValue ? 1 : 0);
if (paramCount == 0 && !isWrapped) // no need to create serializer
{
return null;
}
XmlReflectionMember[] members = new XmlReflectionMember[paramCount];
int paramIndex = 0;
if (hasReturnValue)
members[paramIndex++] = XmlSerializerHelper.GetXmlReflectionMember(returnPart, IsRpc, IsEncoded, isWrapped);
for (int i = 0; i < bodyParts.Count; i++)
members[paramIndex++] = XmlSerializerHelper.GetXmlReflectionMember(bodyParts[i], IsRpc, IsEncoded, isWrapped);
if (!isWrapped)
wrapperNs = ContractNamespace;
return ImportMembersMapping(wrapperName, wrapperNs, members, isWrapped, IsRpc, mappingKey);
}
private MessagePartDescription GetWrapperPart(MessageDescription message)
{
if (message.Body.Parts.Count != 1)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxRpcMessageMustHaveASingleBody, Operation.Name, message.MessageName)));
MessagePartDescription bodyPart = message.Body.Parts[0];
Type bodyObjectType = bodyPart.Type;
if (bodyObjectType.BaseType != null && bodyObjectType.BaseType != typeof(object))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxBodyObjectTypeCannotBeInherited, bodyObjectType.FullName)));
if (typeof(IEnumerable).IsAssignableFrom(bodyObjectType))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxBodyObjectTypeCannotBeInterface, bodyObjectType.FullName, typeof(IEnumerable).FullName)));
if (typeof(IXmlSerializable).IsAssignableFrom(bodyObjectType))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxBodyObjectTypeCannotBeInterface, bodyObjectType.FullName, typeof(IXmlSerializable).FullName)));
return bodyPart;
}
private MessagePartDescriptionCollection GetWrappedParts(MessagePartDescription bodyPart)
{
Type bodyObjectType = bodyPart.Type;
MessagePartDescriptionCollection partList = new MessagePartDescriptionCollection();
foreach (MemberInfo member in bodyObjectType.GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
if ((member.MemberType & (MemberTypes.Field | MemberTypes.Property)) == 0)
continue;
if (member.IsDefined(typeof(SoapIgnoreAttribute), false/*inherit*/))
continue;
XmlName xmlName = new XmlName(member.Name);
MessagePartDescription part = new MessagePartDescription(xmlName.EncodedName, string.Empty);
part.AdditionalAttributesProvider = part.MemberInfo = member;
part.Index = part.SerializationPosition = partList.Count;
part.Type = (member.MemberType == MemberTypes.Property) ? ((PropertyInfo)member).PropertyType : ((FieldInfo)member).FieldType;
if (bodyPart.HasProtectionLevel)
part.ProtectionLevel = bodyPart.ProtectionLevel;
partList.Add(part);
}
return partList;
}
XmlMembersMapping LoadHeadersMapping(MessageDescription message, string mappingKey)
{
int headerCount = message.Headers.Count;
if (headerCount == 0)
return null;
if (IsEncoded)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxHeadersAreNotSupportedInEncoded, message.MessageName)));
int unknownHeaderCount = 0, headerIndex = 0;
XmlReflectionMember[] members = new XmlReflectionMember[headerCount];
for (int i = 0; i < headerCount; i++)
{
MessageHeaderDescription header = message.Headers[i];
if (!header.IsUnknownHeaderCollection)
{
members[headerIndex++] = XmlSerializerHelper.GetXmlReflectionMember(header, false/*isRpc*/, IsEncoded, false/*isWrapped*/);
}
else
{
unknownHeaderCount++;
}
}
if (unknownHeaderCount == headerCount)
{
return null;
}
if (unknownHeaderCount > 0)
{
XmlReflectionMember[] newMembers = new XmlReflectionMember[headerCount - unknownHeaderCount];
Array.Copy(members, newMembers, newMembers.Length);
members = newMembers;
}
return ImportMembersMapping(ContractName, ContractNamespace, members, false /*isWrapped*/, false /*isRpc*/, mappingKey);
}
internal XmlMembersMapping ImportMembersMapping(string elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, string mappingKey)
{
string key = mappingKey.StartsWith(":", StringComparison.Ordinal) ? keyBase + mappingKey : mappingKey;
return this.parent.importer.ImportMembersMapping(new XmlName(elementName, true /*isEncoded*/), ns, members, hasWrapperElement, rpc, this.IsEncoded, key);
}
internal XmlMembersMapping ImportFaultElement(FaultDescription fault, out XmlQualifiedName elementName)
{
// the number of reflection members is always 1 because there is only one fault detail type
XmlReflectionMember[] members = new XmlReflectionMember[1];
XmlName faultElementName = fault.ElementName;
string faultNamespace = fault.Namespace;
if (faultElementName == null)
{
XmlTypeMapping mapping = this.parent.importer.ImportTypeMapping(fault.DetailType, this.IsEncoded);
faultElementName = new XmlName(mapping.ElementName, this.IsEncoded);
faultNamespace = mapping.Namespace;
if (faultElementName == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxFaultTypeAnonymous, this.Operation.Name, fault.DetailType.FullName)));
}
elementName = new XmlQualifiedName(faultElementName.DecodedName, faultNamespace);
members[0] = XmlSerializerHelper.GetXmlReflectionMember(null /*memberName*/, faultElementName, faultNamespace, fault.DetailType,
null /*additionalAttributesProvider*/, false /*isMultiple*/, this.IsEncoded, false /*isWrapped*/);
string mappingKey = "fault:" + faultElementName.DecodedName + ":" + faultNamespace;
return ImportMembersMapping(faultElementName.EncodedName, faultNamespace, members, false /*hasWrapperElement*/, this.IsRpc, mappingKey);
}
}
class XmlSerializerImporter
{
readonly string defaultNs;
XmlReflectionImporter xmlImporter;
SoapReflectionImporter soapImporter;
Dictionary<string, XmlMembersMapping> xmlMappings;
internal XmlSerializerImporter(string defaultNs)
{
this.defaultNs = defaultNs;
this.xmlImporter = null;
this.soapImporter = null;
}
SoapReflectionImporter SoapImporter
{
get
{
if (this.soapImporter == null)
{
this.soapImporter = new SoapReflectionImporter(NamingHelper.CombineUriStrings(defaultNs, "encoded"));
}
return this.soapImporter;
}
}
XmlReflectionImporter XmlImporter
{
get
{
if (this.xmlImporter == null)
{
this.xmlImporter = new XmlReflectionImporter(defaultNs);
}
return this.xmlImporter;
}
}
Dictionary<string, XmlMembersMapping> XmlMappings
{
get
{
if (this.xmlMappings == null)
{
this.xmlMappings = new Dictionary<string, XmlMembersMapping>();
}
return this.xmlMappings;
}
}
internal XmlMembersMapping ImportMembersMapping(XmlName elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool isEncoded, string mappingKey)
{
XmlMembersMapping mapping;
string mappingName = elementName.DecodedName;
if (XmlMappings.TryGetValue(mappingKey, out mapping))
{
return mapping;
}
if (isEncoded)
mapping = this.SoapImporter.ImportMembersMapping(mappingName, ns, members, hasWrapperElement, rpc);
else
mapping = this.XmlImporter.ImportMembersMapping(mappingName, ns, members, hasWrapperElement, rpc);
mapping.SetKey(mappingKey);
XmlMappings.Add(mappingKey, mapping);
return mapping;
}
internal XmlTypeMapping ImportTypeMapping(Type type, bool isEncoded)
{
if (isEncoded)
return this.SoapImporter.ImportTypeMapping(type);
else
return this.XmlImporter.ImportTypeMapping(type);
}
internal void IncludeType(Type knownType, bool isEncoded)
{
if (isEncoded)
this.SoapImporter.IncludeType(knownType);
else
this.XmlImporter.IncludeType(knownType);
}
}
internal class SerializerGenerationContext
{
List<XmlMembersMapping> Mappings = new List<XmlMembersMapping>();
XmlSerializer[] serializers = null;
Type type;
object thisLock = new object();
internal SerializerGenerationContext(Type type)
{
this.type = type;
}
// returns a stub to a serializer
internal SerializerStub AddSerializer(XmlMembersMapping mapping)
{
int handle = -1;
if (mapping != null)
{
handle = ((IList)Mappings).Add(mapping);
}
return new SerializerStub(this, mapping, handle);
}
internal XmlSerializer GetSerializer(int handle)
{
if (handle < 0)
{
return null;
}
if (this.serializers == null)
{
lock (this.thisLock)
{
if (this.serializers == null)
{
this.serializers = GenerateSerializers();
}
}
}
return this.serializers[handle];
}
XmlSerializer[] GenerateSerializers()
{
//this.Mappings may have duplicate mappings (for e.g. samed message contract is used by more than one operation)
//XmlSerializer.FromMappings require unique mappings. The following code uniquifies, calls FromMappings and deuniquifies
List<XmlMembersMapping> uniqueMappings = new List<XmlMembersMapping>();
int[] uniqueIndexes = new int[Mappings.Count];
for (int srcIndex = 0; srcIndex < Mappings.Count; srcIndex++)
{
XmlMembersMapping mapping = Mappings[srcIndex];
int uniqueIndex = uniqueMappings.IndexOf(mapping);
if (uniqueIndex < 0)
{
uniqueMappings.Add(mapping);
uniqueIndex = uniqueMappings.Count - 1;
}
uniqueIndexes[srcIndex] = uniqueIndex;
}
XmlSerializer[] uniqueSerializers = CreateSerializersFromMappings(uniqueMappings.ToArray(), type);
if (uniqueMappings.Count == Mappings.Count)
return uniqueSerializers;
XmlSerializer[] serializers = new XmlSerializer[Mappings.Count];
for (int i = 0; i < Mappings.Count; i++)
{
serializers[i] = uniqueSerializers[uniqueIndexes[i]];
}
return serializers;
}
[Fx.Tag.SecurityNote(Critical = "XmlSerializer.FromMappings has a LinkDemand.",
Safe = "LinkDemand is spurious, not protecting anything in particular.")]
[SecuritySafeCritical]
XmlSerializer[] CreateSerializersFromMappings(XmlMapping[] mappings, Type type)
{
return XmlSerializer.FromMappings(mappings, type);
}
}
internal struct SerializerStub
{
readonly SerializerGenerationContext context;
internal readonly XmlMembersMapping Mapping;
internal readonly int Handle;
internal SerializerStub(SerializerGenerationContext context, XmlMembersMapping mapping, int handle)
{
this.context = context;
this.Mapping = mapping;
this.Handle = handle;
}
internal XmlSerializer GetSerializer()
{
return context.GetSerializer(Handle);
}
}
internal class XmlSerializerFaultContractInfo
{
FaultContractInfo faultContractInfo;
SerializerStub serializerStub;
XmlQualifiedName faultContractElementName;
XmlSerializerObjectSerializer serializer;
internal XmlSerializerFaultContractInfo(FaultContractInfo faultContractInfo, SerializerStub serializerStub,
XmlQualifiedName faultContractElementName)
{
if (faultContractInfo == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("faultContractInfo");
}
if (faultContractElementName == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("faultContractElementName");
}
this.faultContractInfo = faultContractInfo;
this.serializerStub = serializerStub;
this.faultContractElementName = faultContractElementName;
}
internal FaultContractInfo FaultContractInfo
{
get { return this.faultContractInfo; }
}
internal XmlQualifiedName FaultContractElementName
{
get { return this.faultContractElementName; }
}
internal XmlSerializerObjectSerializer Serializer
{
get
{
if (this.serializer == null)
this.serializer = new XmlSerializerObjectSerializer(faultContractInfo.Detail, this.faultContractElementName, this.serializerStub.GetSerializer());
return this.serializer;
}
}
}
internal class MessageInfo : XmlSerializerOperationFormatter.MessageInfo
{
SerializerStub headers;
SerializerStub body;
OperationFormatter.MessageHeaderDescriptionTable headerDescriptionTable;
MessageHeaderDescription unknownHeaderDescription;
MessagePartDescriptionCollection rpcEncodedTypedMessageBodyParts;
internal XmlMembersMapping BodyMapping
{
get { return body.Mapping; }
}
internal override XmlSerializer BodySerializer
{
get { return body.GetSerializer(); }
}
internal XmlMembersMapping HeadersMapping
{
get { return headers.Mapping; }
}
internal override XmlSerializer HeaderSerializer
{
get { return headers.GetSerializer(); }
}
internal override OperationFormatter.MessageHeaderDescriptionTable HeaderDescriptionTable
{
get { return this.headerDescriptionTable; }
}
internal override MessageHeaderDescription UnknownHeaderDescription
{
get { return this.unknownHeaderDescription; }
}
internal override MessagePartDescriptionCollection RpcEncodedTypedMessageBodyParts
{
get { return rpcEncodedTypedMessageBodyParts; }
}
internal void SetBody(SerializerStub body, MessagePartDescriptionCollection rpcEncodedTypedMessageBodyParts)
{
this.body = body;
this.rpcEncodedTypedMessageBodyParts = rpcEncodedTypedMessageBodyParts;
}
internal void SetHeaders(SerializerStub headers)
{
this.headers = headers;
}
internal void SetHeaderDescriptionTable(OperationFormatter.MessageHeaderDescriptionTable headerDescriptionTable)
{
this.headerDescriptionTable = headerDescriptionTable;
}
internal void SetUnknownHeaderDescription(MessageHeaderDescription unknownHeaderDescription)
{
this.unknownHeaderDescription = unknownHeaderDescription;
}
}
}
}
static class XmlSerializerHelper
{
static internal XmlReflectionMember GetXmlReflectionMember(MessagePartDescription part, bool isRpc, bool isEncoded, bool isWrapped)
{
string ns = isRpc ? null : part.Namespace;
ICustomAttributeProvider additionalAttributesProvider = null;
if (isEncoded || part.AdditionalAttributesProvider is MemberInfo)
additionalAttributesProvider = part.AdditionalAttributesProvider;
XmlName memberName = string.IsNullOrEmpty(part.UniquePartName) ? null : new XmlName(part.UniquePartName, true /*isEncoded*/);
XmlName elementName = part.XmlName;
return GetXmlReflectionMember(memberName, elementName, ns, part.Type, additionalAttributesProvider, part.Multiple, isEncoded, isWrapped);
}
static internal XmlReflectionMember GetXmlReflectionMember(XmlName memberName, XmlName elementName, string ns, Type type, ICustomAttributeProvider additionalAttributesProvider, bool isMultiple, bool isEncoded, bool isWrapped)
{
if (isEncoded && isMultiple)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxMultiplePartsNotAllowedInEncoded, elementName.DecodedName, ns)));
XmlReflectionMember member = new XmlReflectionMember();
member.MemberName = (memberName ?? elementName).DecodedName;
member.MemberType = type;
if (member.MemberType.IsByRef)
member.MemberType = member.MemberType.GetElementType();
if (isMultiple)
member.MemberType = member.MemberType.MakeArrayType();
if (additionalAttributesProvider != null)
{
if (isEncoded)
member.SoapAttributes = new SoapAttributes(additionalAttributesProvider);
else
member.XmlAttributes = new XmlAttributes(additionalAttributesProvider);
}
if (isEncoded)
{
if (member.SoapAttributes == null)
member.SoapAttributes = new SoapAttributes();
else
{
Type invalidAttributeType = null;
if (member.SoapAttributes.SoapAttribute != null)
invalidAttributeType = typeof(SoapAttributeAttribute);
else if (member.SoapAttributes.SoapIgnore)
invalidAttributeType = typeof(SoapIgnoreAttribute);
else if (member.SoapAttributes.SoapType != null)
invalidAttributeType = typeof(SoapTypeAttribute);
if (invalidAttributeType != null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidSoapAttribute, invalidAttributeType, elementName.DecodedName)));
}
if (member.SoapAttributes.SoapElement == null)
member.SoapAttributes.SoapElement = new SoapElementAttribute(elementName.DecodedName);
}
else
{
if (member.XmlAttributes == null)
member.XmlAttributes = new XmlAttributes();
else
{
Type invalidAttributeType = null;
if (member.XmlAttributes.XmlAttribute != null)
invalidAttributeType = typeof(XmlAttributeAttribute);
else if (member.XmlAttributes.XmlAnyAttribute != null && !isWrapped)
invalidAttributeType = typeof(XmlAnyAttributeAttribute);
else if (member.XmlAttributes.XmlChoiceIdentifier != null)
invalidAttributeType = typeof(XmlChoiceIdentifierAttribute);
else if (member.XmlAttributes.XmlIgnore)
invalidAttributeType = typeof(XmlIgnoreAttribute);
else if (member.XmlAttributes.Xmlns)
invalidAttributeType = typeof(XmlNamespaceDeclarationsAttribute);
else if (member.XmlAttributes.XmlText != null)
invalidAttributeType = typeof(XmlTextAttribute);
else if (member.XmlAttributes.XmlEnum != null)
invalidAttributeType = typeof(XmlEnumAttribute);
if (invalidAttributeType != null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(isWrapped ? SR.SFxInvalidXmlAttributeInWrapped : SR.SFxInvalidXmlAttributeInBare, invalidAttributeType, elementName.DecodedName)));
if (member.XmlAttributes.XmlArray != null && isMultiple)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxXmlArrayNotAllowedForMultiple, elementName.DecodedName, ns)));
}
bool isArray = member.MemberType.IsArray;
if ((isArray && !isMultiple && member.MemberType != typeof(byte[])) ||
(!isArray && typeof(IEnumerable).IsAssignableFrom(member.MemberType) && member.MemberType != typeof(string) && !typeof(XmlNode).IsAssignableFrom(member.MemberType) && !typeof(IXmlSerializable).IsAssignableFrom(member.MemberType)))
{
if (member.XmlAttributes.XmlArray != null)
{
if (member.XmlAttributes.XmlArray.ElementName == String.Empty)
member.XmlAttributes.XmlArray.ElementName = elementName.DecodedName;
if (member.XmlAttributes.XmlArray.Namespace == null)
member.XmlAttributes.XmlArray.Namespace = ns;
}
else if (HasNoXmlParameterAttributes(member.XmlAttributes))
{
member.XmlAttributes.XmlArray = new XmlArrayAttribute();
member.XmlAttributes.XmlArray.ElementName = elementName.DecodedName;
member.XmlAttributes.XmlArray.Namespace = ns;
}
}
else
{
if (member.XmlAttributes.XmlElements == null || member.XmlAttributes.XmlElements.Count == 0)
{
if (HasNoXmlParameterAttributes(member.XmlAttributes))
{
XmlElementAttribute elementAttribute = new XmlElementAttribute();
elementAttribute.ElementName = elementName.DecodedName;
elementAttribute.Namespace = ns;
member.XmlAttributes.XmlElements.Add(elementAttribute);
}
}
else
{
foreach (XmlElementAttribute elementAttribute in member.XmlAttributes.XmlElements)
{
if (elementAttribute.ElementName == String.Empty)
elementAttribute.ElementName = elementName.DecodedName;
if (elementAttribute.Namespace == null)
elementAttribute.Namespace = ns;
}
}
}
}
return member;
}
static bool HasNoXmlParameterAttributes(XmlAttributes xmlAttributes)
{
return xmlAttributes.XmlAnyAttribute == null &&
(xmlAttributes.XmlAnyElements == null || xmlAttributes.XmlAnyElements.Count == 0) &&
xmlAttributes.XmlArray == null &&
xmlAttributes.XmlAttribute == null &&
!xmlAttributes.XmlIgnore &&
xmlAttributes.XmlText == null &&
xmlAttributes.XmlChoiceIdentifier == null &&
(xmlAttributes.XmlElements == null || xmlAttributes.XmlElements.Count == 0) &&
!xmlAttributes.Xmlns;
}
}
}
|