diff --git a/src/System.Private.ServiceModel/src/Resources/Strings.resx b/src/System.Private.ServiceModel/src/Resources/Strings.resx
index f1048f531ac..fe2720796b0 100644
--- a/src/System.Private.ServiceModel/src/Resources/Strings.resx
+++ b/src/System.Private.ServiceModel/src/Resources/Strings.resx
@@ -1932,4 +1932,22 @@
'{0}' is an invalid XmlNodeType.
-
\ No newline at end of file
+
+ RPC Message {1} in operation {0} must have a single MessageBodyMember.
+
+
+ Type {0} cannot inherit from any class other than object to be used as body object in RPC style.
+
+
+ Type {0} implements interface {1} which is not supported for body object in RPC style.
+
+
+ Message {0} must not have headers to be used in RPC encoded style.
+
+
+ Part {1}:{0} is repeating and is not supported in Soap Encoding.
+
+
+ XmlSerializer attribute {0} is not valid in {1}. Only SoapElement attribute is supported.
+
+
diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Description/XmlSerializerOperationBehavior.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Description/XmlSerializerOperationBehavior.cs
index 24963c64840..4c958796f2f 100644
--- a/src/System.Private.ServiceModel/src/System/ServiceModel/Description/XmlSerializerOperationBehavior.cs
+++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Description/XmlSerializerOperationBehavior.cs
@@ -166,6 +166,20 @@ void IOperationBehavior.ApplyClientBehavior(OperationDescription description, Cl
proxy.FaultFormatter = (IClientFaultFormatter)CreateFaultFormatter(proxy.FaultContractInfos);
}
+ public Collection GetXmlMappings()
+ {
+ var mappings = new Collection();
+ 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
@@ -226,6 +240,7 @@ internal class OperationReflector
internal readonly OperationDescription Operation;
internal readonly XmlSerializerFormatAttribute Attribute;
+ internal readonly bool IsEncoded;
internal readonly bool IsRpc;
internal readonly bool IsOneWay;
internal readonly bool RequestRequiresSerialization;
@@ -243,13 +258,14 @@ internal OperationReflector(Reflector parent, OperationDescription operation, Xm
Fx.Assert(operation != null, "");
Fx.Assert(attr != null, "");
- OperationFormatter.Validate(operation, attr.Style == OperationFormatStyle.Rpc, false/*IsEncoded*/);
+ OperationFormatter.Validate(operation, attr.Style == OperationFormatStyle.Rpc, attr.IsEncoded);
_parent = parent;
this.Operation = operation;
this.Attribute = attr;
+ IsEncoded = attr.IsEncoded;
this.IsRpc = (attr.Style == OperationFormatStyle.Rpc);
this.IsOneWay = operation.Messages.Count == 1;
@@ -342,7 +358,7 @@ internal void EnsureMessageInfos()
{
if (knownType == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxKnownTypeNull, Operation.Name)));
- _parent._importer.IncludeType(knownType);
+ _parent._importer.IncludeType(knownType, IsEncoded);
}
_request = CreateMessageInfo(this.Operation.Messages[0], ":Request");
// We don't do the following check at Net Native runtime because XmlMapping.XsdElementName
@@ -389,9 +405,8 @@ private MessageInfo CreateMessageInfo(MessageDescription message, string key)
if (message.IsUntypedMessage)
return null;
MessageInfo info = new MessageInfo();
- bool isEncoded = false;
if (message.IsTypedMessage)
- key = message.MessageType.FullName + ":" + isEncoded + ":" + IsRpc;
+ key = message.MessageType.FullName + ":" + IsEncoded + ":" + IsRpc;
XmlMembersMapping headersMapping = LoadHeadersMapping(message, key + ":Headers");
info.SetHeaders(_parent._generation.AddSerializer(headersMapping));
MessagePartDescriptionCollection rpcEncodedTypedMessgeBodyParts;
@@ -426,8 +441,17 @@ private void CreateHeaderDescriptionTable(MessageDescription message, MessageInf
else
{
string headerName, headerNs;
- headerName = memberMapping.XsdElementName;
- headerNs = memberMapping.Namespace;
+ if (IsEncoded)
+ {
+ headerName = memberMapping.TypeName;
+ headerNs = memberMapping.TypeNamespace;
+ }
+ else
+ {
+ headerName = memberMapping.XsdElementName;
+ headerNs = memberMapping.Namespace;
+ }
+
if (headerName != header.Name)
{
if (message.MessageType != null)
@@ -454,11 +478,23 @@ private XmlMembersMapping LoadBodyMapping(MessageDescription message, string map
MessagePartDescription returnPart;
string wrapperName, wrapperNs;
MessagePartDescriptionCollection bodyParts;
- rpcEncodedTypedMessageBodyParts = null;
- returnPart = OperationFormatter.IsValidReturnValue(message.Body.ReturnValue) ? message.Body.ReturnValue : null;
- bodyParts = message.Body.Parts;
- wrapperName = message.Body.WrapperName;
- wrapperNs = message.Body.WrapperNamespace;
+ 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);
@@ -470,22 +506,65 @@ private XmlMembersMapping LoadBodyMapping(MessageDescription message, string map
XmlReflectionMember[] members = new XmlReflectionMember[paramCount];
int paramIndex = 0;
if (hasReturnValue)
- members[paramIndex++] = XmlSerializerHelper.GetXmlReflectionMember(returnPart, IsRpc, isWrapped);
+ members[paramIndex++] = XmlSerializerHelper.GetXmlReflectionMember(returnPart, IsRpc, IsEncoded, isWrapped);
for (int i = 0; i < bodyParts.Count; i++)
- members[paramIndex++] = XmlSerializerHelper.GetXmlReflectionMember(bodyParts[i], IsRpc, isWrapped);
+ 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.Format(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.Format(SR.SFxBodyObjectTypeCannotBeInherited, bodyObjectType.FullName)));
+ if (typeof(IEnumerable).IsAssignableFrom(bodyObjectType))
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxBodyObjectTypeCannotBeInterface, bodyObjectType.FullName, typeof(IEnumerable).FullName)));
+ if (typeof(IXmlSerializable).IsAssignableFrom(bodyObjectType))
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(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;
+ }
+
private 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.Format(SR.SFxHeadersAreNotSupportedInEncoded, message.MessageName)));
int unknownHeaderCount = 0, headerIndex = 0;
XmlReflectionMember[] members = new XmlReflectionMember[headerCount];
@@ -494,7 +573,7 @@ private XmlMembersMapping LoadHeadersMapping(MessageDescription message, string
MessageHeaderDescription header = message.Headers[i];
if (!header.IsUnknownHeaderCollection)
{
- members[headerIndex++] = XmlSerializerHelper.GetXmlReflectionMember(header, false/*isRpc*/, false/*isWrapped*/);
+ members[headerIndex++] = XmlSerializerHelper.GetXmlReflectionMember(header, false/*isRpc*/, IsEncoded, false/*isWrapped*/);
}
else
{
@@ -520,7 +599,7 @@ private XmlMembersMapping LoadHeadersMapping(MessageDescription message, string
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 _parent._importer.ImportMembersMapping(new XmlName(elementName, true /*isEncoded*/), ns, members, hasWrapperElement, rpc, key);
+ return _parent._importer.ImportMembersMapping(new XmlName(elementName, true /*isEncoded*/), ns, members, hasWrapperElement, rpc, IsEncoded, key);
}
internal XmlMembersMapping ImportFaultElement(FaultDescription fault, out XmlQualifiedName elementName)
@@ -532,20 +611,20 @@ internal XmlMembersMapping ImportFaultElement(FaultDescription fault, out XmlQua
string faultNamespace = fault.Namespace;
if (faultElementName == null)
{
- XmlTypeMapping mapping = _parent._importer.ImportTypeMapping(fault.DetailType);
- faultElementName = new XmlName(mapping.ElementName, false /*isEncoded*/);
+ XmlTypeMapping mapping = _parent._importer.ImportTypeMapping(fault.DetailType, IsEncoded);
+ faultElementName = new XmlName(mapping.ElementName, IsEncoded);
faultNamespace = mapping.Namespace;
if (faultElementName == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxFaultTypeAnonymous, this.Operation.Name, fault.DetailType.FullName)));
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxFaultTypeAnonymous, 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*/, false /*isWrapped*/);
+ null /*additionalAttributesProvider*/, false /*isMultiple*/, IsEncoded, false /*isWrapped*/);
string mappingKey = "fault:" + faultElementName.DecodedName + ":" + faultNamespace;
- return ImportMembersMapping(faultElementName.EncodedName, faultNamespace, members, false /*hasWrapperElement*/, this.IsRpc, mappingKey);
+ return ImportMembersMapping(faultElementName.EncodedName, faultNamespace, members, false /*hasWrapperElement*/, IsRpc, mappingKey);
}
}
@@ -553,6 +632,7 @@ private class XmlSerializerImporter
{
private readonly string _defaultNs;
private XmlReflectionImporter _xmlImporter;
+ private SoapReflectionImporter _soapImporter;
private Dictionary _xmlMappings;
private HashSet _includedTypes;
@@ -560,6 +640,20 @@ internal XmlSerializerImporter(string defaultNs)
{
_defaultNs = defaultNs;
_xmlImporter = null;
+ _soapImporter = null;
+ }
+
+ private SoapReflectionImporter SoapImporter
+ {
+ get
+ {
+ if (_soapImporter == null)
+ {
+ _soapImporter = new SoapReflectionImporter(NamingHelper.CombineUriStrings(_defaultNs, "encoded"));
+ }
+
+ return _soapImporter;
+ }
}
private XmlReflectionImporter XmlImporter
@@ -598,7 +692,7 @@ private HashSet IncludedTypes
}
}
- internal XmlMembersMapping ImportMembersMapping(XmlName elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, string mappingKey)
+ internal XmlMembersMapping ImportMembersMapping(XmlName elementName, string ns, XmlReflectionMember[] members, bool hasWrapperElement, bool rpc, bool isEncoded, string mappingKey)
{
XmlMembersMapping mapping;
string mappingName = elementName.DecodedName;
@@ -607,18 +701,25 @@ internal XmlMembersMapping ImportMembersMapping(XmlName elementName, string ns,
return mapping;
}
- mapping = this.XmlImporter.ImportMembersMapping(mappingName, ns, members, hasWrapperElement, rpc);
+ if (isEncoded)
+ mapping = SoapImporter.ImportMembersMapping(mappingName, ns, members, hasWrapperElement, rpc);
+ else
+ mapping = XmlImporter.ImportMembersMapping(mappingName, ns, members, hasWrapperElement, rpc);
+
mapping.SetKey(mappingKey);
XmlMappings.Add(mappingKey, mapping);
return mapping;
}
- internal XmlTypeMapping ImportTypeMapping(Type type)
+ internal XmlTypeMapping ImportTypeMapping(Type type, bool isEncoded)
{
- return this.XmlImporter.ImportTypeMapping(type);
+ if (isEncoded)
+ return SoapImporter.ImportTypeMapping(type);
+ else
+ return XmlImporter.ImportTypeMapping(type);
}
- internal void IncludeType(Type knownType)
+ internal void IncludeType(Type knownType, bool isEncoded)
{
// XmlReflectionImporter.IncludeTypes calls XmlReflectionImporter.ImportTypeMapping to generate mappings
// for types and store those mappings.
@@ -633,7 +734,11 @@ internal void IncludeType(Type knownType)
if (IncludedTypes.Contains(knownType))
return;
- this.XmlImporter.IncludeType(knownType);
+ if (isEncoded)
+ SoapImporter.IncludeType(knownType);
+ else
+ XmlImporter.IncludeType(knownType);
+
IncludedTypes.Add(knownType);
}
}
@@ -852,19 +957,22 @@ internal void SetUnknownHeaderDescription(MessageHeaderDescription unknownHeader
internal static class XmlSerializerHelper
{
- static internal XmlReflectionMember GetXmlReflectionMember(MessagePartDescription part, bool isRpc, bool isWrapped)
+ static internal XmlReflectionMember GetXmlReflectionMember(MessagePartDescription part, bool isRpc, bool isEncoded, bool isWrapped)
{
string ns = isRpc ? null : part.Namespace;
- MemberInfo additionalAttributesProvider = null;
- if (part.AdditionalAttributesProvider.MemberInfo != null)
+ ICustomAttributeProvider additionalAttributesProvider = null;
+ if (isEncoded || part.AdditionalAttributesProvider.MemberInfo != null)
additionalAttributesProvider = part.AdditionalAttributesProvider.MemberInfo;
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, isWrapped);
+ return GetXmlReflectionMember(memberName, elementName, ns, part.Type, additionalAttributesProvider, part.Multiple, isEncoded, isWrapped);
}
- static internal XmlReflectionMember GetXmlReflectionMember(XmlName memberName, XmlName elementName, string ns, Type type, MemberInfo additionalAttributesProvider, bool isMultiple, bool 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.Format(SR.SFxMultiplePartsNotAllowedInEncoded, elementName.DecodedName, ns)));
+
XmlReflectionMember member = new XmlReflectionMember();
member.MemberName = (memberName ?? elementName).DecodedName;
member.MemberType = type;
@@ -872,79 +980,102 @@ static internal XmlReflectionMember GetXmlReflectionMember(XmlName memberName, X
member.MemberType = member.MemberType.GetElementType();
if (isMultiple)
member.MemberType = member.MemberType.MakeArrayType();
- if (additionalAttributesProvider != null)
- {
-#if NETStandard13
- member.XmlAttributes = XmlAttributesHelper.CreateXmlAttributes(additionalAttributesProvider);
-#else
- member.XmlAttributes = new XmlAttributes(additionalAttributesProvider);
-#endif
- }
- if (member.XmlAttributes == null)
- member.XmlAttributes = new XmlAttributes();
- else
+ if (additionalAttributesProvider != null)
{
- 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.Format(isWrapped ? SR.SFxInvalidXmlAttributeInWrapped : SR.SFxInvalidXmlAttributeInBare, invalidAttributeType, elementName.DecodedName)));
- if (member.XmlAttributes.XmlArray != null && isMultiple)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxXmlArrayNotAllowedForMultiple, elementName.DecodedName, ns)));
+ if (isEncoded)
+ member.SoapAttributes = new SoapAttributes(additionalAttributesProvider);
+ else
+ member.XmlAttributes = new XmlAttributes(additionalAttributesProvider);
}
-
- 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 (isEncoded)
{
- 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))
+ if (member.SoapAttributes == null)
+ member.SoapAttributes = new SoapAttributes();
+ else
{
- member.XmlAttributes.XmlArray = new XmlArrayAttribute();
- member.XmlAttributes.XmlArray.ElementName = elementName.DecodedName;
- member.XmlAttributes.XmlArray.Namespace = ns;
+ 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.Format(SR.SFxInvalidSoapAttribute, invalidAttributeType, elementName.DecodedName)));
}
+
+ if (member.SoapAttributes.SoapElement == null)
+ member.SoapAttributes.SoapElement = new SoapElementAttribute(elementName.DecodedName);
}
else
{
- if (member.XmlAttributes.XmlElements == null || member.XmlAttributes.XmlElements.Count == 0)
+ if (member.XmlAttributes == null)
+ member.XmlAttributes = new XmlAttributes();
+ else
{
- if (HasNoXmlParameterAttributes(member.XmlAttributes))
+ 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.Format(isWrapped ? SR.SFxInvalidXmlAttributeInWrapped : SR.SFxInvalidXmlAttributeInBare, invalidAttributeType, elementName.DecodedName)));
+ if (member.XmlAttributes.XmlArray != null && isMultiple)
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(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)
{
- XmlElementAttribute elementAttribute = new XmlElementAttribute();
- elementAttribute.ElementName = elementName.DecodedName;
- elementAttribute.Namespace = ns;
- member.XmlAttributes.XmlElements.Add(elementAttribute);
+ 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
{
- foreach (XmlElementAttribute elementAttribute in member.XmlAttributes.XmlElements)
+ if (member.XmlAttributes.XmlElements == null || member.XmlAttributes.XmlElements.Count == 0)
{
- if (elementAttribute.ElementName == String.Empty)
+ if (HasNoXmlParameterAttributes(member.XmlAttributes))
+ {
+ XmlElementAttribute elementAttribute = new XmlElementAttribute();
elementAttribute.ElementName = elementName.DecodedName;
- if (elementAttribute.Namespace == null)
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;
+ }
}
}
}
diff --git a/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs b/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs
index 6c2897eaa3f..d4439e49749 100644
--- a/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs
+++ b/src/System.Private.ServiceModel/tests/Common/Scenarios/Endpoints.cs
@@ -33,6 +33,11 @@ public static string HttpBaseAddress_4_4_0_Basic
{
get { return GetEndpointAddress("BasicHttp_4_4_0.svc//Basic"); }
}
+
+ public static string HttpBaseAddress_Basic_Soap
+ {
+ get { return GetEndpointAddress("BasicHttpSoap.svc//Basic"); }
+ }
public static string HttpBaseAddress_NetHttp
{
diff --git a/src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestTypes.cs b/src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestTypes.cs
index fef9d644507..449e926c222 100644
--- a/src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestTypes.cs
+++ b/src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestTypes.cs
@@ -1213,6 +1213,41 @@ public int Id
}
}
+public class SoapComplexType
+{
+ private bool _boolValue;
+ private string _stringValue;
+
+ public bool BoolValue
+ {
+ get { return _boolValue; }
+ set { _boolValue = value; }
+ }
+
+ public string StringValue
+ {
+ get { return _stringValue; }
+ set { _stringValue = value; }
+ }
+}
+
+[SoapType(Namespace = "WcfService")]
+public class CustomerObject
+{
+ public string Name { get; set; }
+ public object Data { get; set; }
+}
+
+[Serializable]
+[SoapType(Namespace = "WcfService")]
+public partial class AdditionalData
+{
+ public string Field
+ {
+ get; set;
+ }
+}
+
// This type should be used by XmlSerializerFormat_EchoVeryComplexType only.
// The type should not ever be instantiated.
public class NonInstantiatedType
diff --git a/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs b/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs
index c5e6f4779dd..334fcf55da9 100644
--- a/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs
+++ b/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs
@@ -120,6 +120,24 @@ public interface IWcfServiceXmlGenerated
XmlVeryComplexType EchoXmlVeryComplexType(XmlVeryComplexType complex);
}
+[ServiceContract(ConfigurationName = "IWcfSoapService")]
+public interface IWcfSoapService
+{
+ [OperationContract(Action = "http://tempuri.org/IWcfService/CombineStringXmlSerializerFormatSoap", ReplyAction = "http://tempuri.org/IWcfService/CombineStringXmlSerializerFormatSoapResponse")]
+ [XmlSerializerFormat(Style = OperationFormatStyle.Rpc, SupportFaults = true, Use = OperationFormatUse.Encoded)]
+ string CombineStringXmlSerializerFormatSoap(string message1, string message2);
+
+ [OperationContract(Action = "http://tempuri.org/IWcfService/EchoComositeTypeXmlSerializerFormatSoap", ReplyAction = "http://tempuri.org/IWcfService/EchoComositeTypeXmlSerializerFormatSoapResponse")]
+ [XmlSerializerFormat(Style = OperationFormatStyle.Rpc, SupportFaults = true, Use = OperationFormatUse.Encoded)]
+ SoapComplexType EchoComositeTypeXmlSerializerFormatSoap(SoapComplexType c);
+
+ [OperationContract(Action = "http://tempuri.org/IWcfService/ProcessCustomerData", ReplyAction = "http://tempuri.org/IWcfSoapService/ProcessCustomerDataResponse")]
+ [XmlSerializerFormat(Style = OperationFormatStyle.Rpc, SupportFaults = true, Use = OperationFormatUse.Encoded)]
+ [ServiceKnownType(typeof(AdditionalData))]
+ [return: MessageParameter(Name = "ProcessCustomerDataReturn")]
+ string ProcessCustomerData(CustomerObject CustomerData);
+}
+
// This type share the same name space with IWcfServiceXmlGenerated.
// And this type contains a method which is also defined in IWcfServiceXmlGenerated.
[ServiceContract(ConfigurationName = "IWcfService")]
diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Contract/XmlSerializer/XmlSerializerFormatSoapTest.cs b/src/System.Private.ServiceModel/tests/Scenarios/Contract/XmlSerializer/XmlSerializerFormatSoapTest.cs
new file mode 100644
index 00000000000..dfd7ee241b5
--- /dev/null
+++ b/src/System.Private.ServiceModel/tests/Scenarios/Contract/XmlSerializer/XmlSerializerFormatSoapTest.cs
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.Threading.Tasks;
+using Infrastructure.Common;
+using Xunit;
+using System;
+
+public static partial class XmlSerializerFormatTests
+{
+ [WcfFact]
+ [OuterLoop]
+ public static void CombineString_XmlSerializerFormat_Soap()
+ {
+ RunWcfSoapServiceTest((serviceProxy) =>
+ {
+ // *** EXECUTE *** \\
+ string message1 = "hello";
+ string message2 = "world";
+ var response = serviceProxy.CombineStringXmlSerializerFormatSoap(message1, message2);
+
+ // *** VALIDATE *** \\
+ Assert.Equal(message1 + message2, response);
+ });
+ }
+
+ [WcfFact]
+ [OuterLoop]
+ [Issue(1884)]
+ public static void EchoComositeType_XmlSerializerFormat_Soap()
+ {
+ RunWcfSoapServiceTest((serviceProxy) =>
+ {
+ // *** EXECUTE *** \\
+ var value = new SoapComplexType() { BoolValue = true, StringValue = "hello" };
+ SoapComplexType response = serviceProxy.EchoComositeTypeXmlSerializerFormatSoap(value);
+
+ // *** VALIDATE *** \\
+ Assert.NotNull(response);
+ Assert.Equal(value.BoolValue, response.BoolValue);
+ Assert.Equal(value.StringValue, response.StringValue);
+ });
+ }
+
+ [WcfFact]
+ [OuterLoop]
+ public static void ProcessCustomerData_XmlSerializerFormat_Soap()
+ {
+ RunWcfSoapServiceTest((serviceProxy) =>
+ {
+ // *** EXECUTE *** \\
+ CustomerObject value = new CustomerObject() { Name = "MyName", Data = new AdditionalData() { Field = "Foo" } };
+ string response = serviceProxy.ProcessCustomerData(value);
+
+ // *** VALIDATE *** \\
+ Assert.Equal("MyNameFoo", response);
+ });
+ }
+
+ private static void RunWcfSoapServiceTest(Action testMethod)
+ {
+ BasicHttpBinding binding;
+ EndpointAddress endpointAddress;
+ ChannelFactory factory;
+ IWcfSoapService serviceProxy = null;
+
+ try
+ {
+ // *** SETUP *** \\
+ binding = new BasicHttpBinding();
+ endpointAddress = new EndpointAddress(Endpoints.HttpBaseAddress_Basic_Soap);
+ factory = new ChannelFactory(binding, endpointAddress);
+ serviceProxy = factory.CreateChannel();
+ testMethod(serviceProxy);
+
+ // *** CLEANUP *** \\
+ factory.Close();
+ ((ICommunicationObject)serviceProxy).Close();
+ }
+ finally
+ {
+ // *** ENSURE CLEANUP *** \\
+ ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy);
+ }
+ }
+}
diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/CompositeType.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/CompositeType.cs
index 97636c77c48..34e52c77bf6 100644
--- a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/CompositeType.cs
+++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/CompositeType.cs
@@ -315,4 +315,39 @@ public override bool TryResolveType(Type type, Type declaredType, DataContractRe
return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
}
}
-}
\ No newline at end of file
+}
+
+public class SoapComplexType
+{
+ private bool _boolValue;
+ private string _stringValue;
+
+ public bool BoolValue
+ {
+ get { return _boolValue; }
+ set { _boolValue = value; }
+ }
+
+ public string StringValue
+ {
+ get { return _stringValue; }
+ set { _stringValue = value; }
+ }
+}
+
+[SoapType(Namespace = "WcfService")]
+public class CustomerObject
+{
+ public string Name { get; set; }
+ public object Data { get; set; }
+}
+
+[Serializable]
+[SoapType(Namespace = "WcfService")]
+public partial class AdditionalData
+{
+ public string Field
+ {
+ get; set;
+ }
+}
diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/IWcfSoapService.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/IWcfSoapService.cs
new file mode 100644
index 00000000000..b0cefcd2f2c
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/IWcfSoapService.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+using System;
+using System.ServiceModel;
+using System.Threading.Tasks;
+
+namespace WcfService
+{
+ [ServiceContract]
+ [XmlSerializerFormat(Use = OperationFormatUse.Encoded)]
+ public interface IWcfSoapService
+ {
+ [OperationContract(Action = "http://tempuri.org/IWcfService/CombineStringXmlSerializerFormatSoap")]
+ [XmlSerializerFormat(Use = OperationFormatUse.Encoded)]
+ string CombineStringXmlSerializerFormatSoap(string message1, string message2);
+
+ [OperationContract(Action = "http://tempuri.org/IWcfService/EchoComositeTypeXmlSerializerFormatSoap")]
+ [XmlSerializerFormat(Use = OperationFormatUse.Encoded)]
+ SoapComplexType EchoComositeTypeXmlSerializerFormatSoap(SoapComplexType c);
+
+ [OperationContract(Action = "http://tempuri.org/IWcfService/ProcessCustomerData")]
+ [XmlSerializerFormat(Style = OperationFormatStyle.Rpc, SupportFaults = true, Use = OperationFormatUse.Encoded)]
+ [ServiceKnownType(typeof(AdditionalData))]
+ [return: MessageParameter(Name = "ProcessCustomerDataReturn")]
+ [return: System.Xml.Serialization.SoapElement(DataType = "string")]
+ string ProcessCustomerData([MessageParameter(Name = "CustomerData")]CustomerObject customerData);
+ }
+}
diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/WcfSoapService.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/WcfSoapService.cs
new file mode 100644
index 00000000000..20c5d9a4030
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/WcfSoapService.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.ServiceModel;
+using System.ServiceModel.Channels;
+using System.ServiceModel.Web;
+using System.Text;
+using System.Xml.Serialization;
+
+namespace WcfService
+{
+ public class WcfSoapService : IWcfSoapService
+ {
+ public string CombineStringXmlSerializerFormatSoap(string message1, string message2)
+ {
+ return message1 + message2;
+ }
+
+ public SoapComplexType EchoComositeTypeXmlSerializerFormatSoap(SoapComplexType complexObject)
+ {
+ return complexObject;
+ }
+
+ [return: MessageParameter(Name = "ProcessCustomerDataReturn"), SoapElement(DataType = "string")]
+ public string ProcessCustomerData([MessageParameter(Name = "CustomerData")] CustomerObject customerData)
+ {
+ return customerData.Name + ((AdditionalData)customerData.Data).Field;
+ }
+ }
+}
diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/BasicHttpSoapTestServiceHost.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/BasicHttpSoapTestServiceHost.cs
new file mode 100644
index 00000000000..cfe47104bb1
--- /dev/null
+++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/testhosts/BasicHttpSoapTestServiceHost.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ServiceModel;
+using System.ServiceModel.Activation;
+using System.ServiceModel.Channels;
+
+namespace WcfService
+{
+ public class BasicHttpSoapTestServiceHostFactory : ServiceHostFactory
+ {
+ protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
+ {
+ var serviceHost = new BasicHttpSoapTestServiceHost(serviceType, baseAddresses);
+ return serviceHost;
+ }
+ }
+
+ public class BasicHttpSoapTestServiceHost : TestServiceHostBase
+ {
+ protected override string Address { get { return "Basic"; } }
+
+ protected override Binding GetBinding()
+ {
+ return new BasicHttpBinding();
+ }
+
+ public BasicHttpSoapTestServiceHost(Type serviceType, params Uri[] baseAddresses)
+ : base(serviceType, baseAddresses)
+ {
+ }
+ }
+}
diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config b/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config
index 4f55486fe4e..c9893e33196 100644
--- a/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config
+++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/Web.config
@@ -26,6 +26,7 @@
+
diff --git a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs
index 497932598cb..6de09e81151 100644
--- a/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs
+++ b/src/System.Private.ServiceModel/tools/SelfHostedWcfService/Program.cs
@@ -42,7 +42,8 @@ private static void Main()
CreateHost("BasicAuth.svc", httpsBaseAddress);
CreateHost("BasicHttps.svc", httpsBaseAddress);
CreateHost("BasicHttp.svc", httpBaseAddress);
- CreateHost("BasicHttp_4_4_0.svc", httpBaseAddress);
+ CreateHost("BasicHttp_4_4_0.svc", httpBaseAddress);
+ CreateHost("BasicHttpSoap.svc", httpBaseAddress);
CreateHost("CustomTextEncoderBuffered.svc", httpBaseAddress);
CreateHost("CustomTextEncoderStreamed.svc", httpBaseAddress);
CreateHost("DefaultCustomHttp.svc", httpBaseAddress);
diff --git a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs
index 4a291bb8184..599593a17c6 100644
--- a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs
+++ b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs
@@ -1453,6 +1453,7 @@ public partial class XmlSerializerOperationBehavior : System.ServiceModel.Descri
public XmlSerializerOperationBehavior(System.ServiceModel.Description.OperationDescription operation) { }
public XmlSerializerOperationBehavior(System.ServiceModel.Description.OperationDescription operation, System.ServiceModel.XmlSerializerFormatAttribute attribute) { }
public System.ServiceModel.XmlSerializerFormatAttribute XmlSerializerFormatAttribute { get { return default(System.ServiceModel.XmlSerializerFormatAttribute); } }
+ public System.Collections.ObjectModel.Collection GetXmlMappings() { throw null; }
void System.ServiceModel.Description.IOperationBehavior.Validate(System.ServiceModel.Description.OperationDescription description) { }
void System.ServiceModel.Description.IOperationBehavior.AddBindingParameters(System.ServiceModel.Description.OperationDescription description, System.ServiceModel.Channels.BindingParameterCollection parameters) { }
void System.ServiceModel.Description.IOperationBehavior.ApplyDispatchBehavior(System.ServiceModel.Description.OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch) { }