Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XmlArray and XmlArrayItem are not honored in method parameters #1106

Closed
Eddenn opened this issue Dec 20, 2024 · 5 comments
Closed

XmlArray and XmlArrayItem are not honored in method parameters #1106

Eddenn opened this issue Dec 20, 2024 · 5 comments
Labels

Comments

@Eddenn
Copy link

Eddenn commented Dec 20, 2024

Hello,
I have an issue with [XmlArray] and [XmlArrayItem] attributes that are not honored only when used in method parameters.
These works well when used in an serialized object but not when used on a parameter.

Version used : SoapCore 1.1.0.51 in a .NET 8 project.

To summary, this code :

[OperationContract]
public Result DeleteEntities(UserToken user,
                             [XmlArray("EntityCodes", IsNullable = true)] 
                             [XmlArrayItem("EntityCode", IsNullable = true)] 
                             List<string> entityCodeList)

result in WSDL :

<xsd:element name="DeleteEntities">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element minOccurs="0" maxOccurs="1" name="user" type="tns:UserToken"/>
      <xsd:element minOccurs="0" maxOccurs="1" name="entityCodeList" nillable="true" type="tns:ArrayOfString"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>

instead of :

<xsd:element name="DeleteEntities">
  <xsd:complexType>
    <xsd:sequence>
      <xsd:element minOccurs="0" maxOccurs="1" name="user" type="tns:UserToken"/>
      <xsd:element minOccurs="0" maxOccurs="1" name="EntityCodes" nillable="true" type="tns:ArrayOfEntityCode"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>
@Eddenn
Copy link
Author

Eddenn commented Dec 23, 2024

A first issue seems to be located when you test if the argument is an array or not here :

if (!parameterType.IsArray || parameterType.GetElementType()?.IsArray == true)
{
// case [XmlElement("parameter")] int parameter
// case [XmlArray("parameter")] int[] parameter
return DeserializeObject(xmlReader, parameterType, parameterName, parameterNs);
}
else
{
// case int[] parameter
// case [XmlElement("parameter")] int[] parameter
// case [XmlArray("parameter"), XmlArrayItem(ElementName = "item")] int[] parameter
return DeserializeArrayXmlSerializer(xmlReader, parameterType, parameterName, parameterNs, customAttributeProvider);
}

parameterType.IsArray only return true if the type is a real array like string[] and that's good
but parameterType.GetElementType()?.IsArray == true should return true if it's a IList or a more specifically a ICollection.
I would propose to use parameterType.GetInterfaces().Contains(typeof(IList)) to detect that.

Important note :
[XmlArray] and [XmlArrayItem] on a string[] parameter : Serialization work BUT wsdl generation doesn't !
It mean that the WSDL is wrongly generated.

My tests, for references :
image

@Eddenn
Copy link
Author

Eddenn commented Dec 23, 2024

In my opinion the first change would be :

if (!parameterType.IsArray && !parameterType.GetInterfaces().Contains(typeof(IList)))
{
  // case [XmlElement("parameter")] int parameter
  // case [XmlArray("parameter")] int[] parameter
  return DeserializeObject(xmlReader, parameterType, parameterName, parameterNs);
}
else
{
  // case int[] or List<int> parameter 
  // case [XmlElement("parameter")] int[] or List<int> parameter
  // case [XmlArray("parameter"), XmlArrayItem(ElementName = "item")] int[] or List<int> parameter
  return DeserializeArrayXmlSerializer(xmlReader, parameterType, parameterName, parameterNs, customAttributeProvider);
}

But it the WSDL generation error will remain.
Could you fix it too or indicate me witch part of code manage WSDL generation so I could take a look ?

@Eddenn
Copy link
Author

Eddenn commented Dec 23, 2024

WSDL definition of the parameter name seems to be here ?

private void WriteParameterElement(XmlDictionaryWriter writer, SoapMethodParameterInfo parameterInfo)
{
var elementAttribute = parameterInfo.Parameter.GetCustomAttribute<XmlElementAttribute>();
bool isUnqualified = elementAttribute?.Form == XmlSchemaForm.Unqualified;
var elementName = string.IsNullOrWhiteSpace(elementAttribute?.ElementName) ? null : elementAttribute.ElementName;
var xmlRootAttr = parameterInfo.Parameter.ParameterType.GetCustomAttributes<XmlRootAttribute>().FirstOrDefault();
var typeRootName = string.IsNullOrWhiteSpace(xmlRootAttr?.ElementName) ? null : xmlRootAttr.ElementName;
var parameterName = elementName
?? parameterInfo.Parameter.GetCustomAttribute<MessageParameterAttribute>()?.Name
?? typeRootName
?? parameterInfo.Parameter.Name;
AddSchemaType(writer, parameterInfo.Parameter.ParameterType, parameterName, @namespace: elementAttribute?.Namespace, isUnqualified: isUnqualified);
}

Maybe you should add a part where you get the [XmlArray] attribute if it's an array or a list ?
FYI : (parameterType.IsArray || parameterType.GetInterfaces().Contains(typeof(IList)))

And maybe add the check for the List here too ?

private bool HasBaseType(Type type)
{
var isArrayType = type.IsArray || typeof(IEnumerable).IsAssignableFrom(type);
var baseType = type.GetTypeInfo().BaseType;
return !isArrayType && !type.IsEnum && !type.IsPrimitive && !type.IsValueType && baseType != null
&& !baseType.Name.Equals("Object")
&& type.BaseType?.BaseType?.FullName?.Equals("System.Attribute") != true;
}

Copy link

This issue is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale label Jan 23, 2025
Copy link

github-actions bot commented Feb 6, 2025

This issue was closed because it has been inactive for 14 days since being marked as stale.

@github-actions github-actions bot closed this as completed Feb 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant