WCF Handling Nested Attributes in AttributeGroup

tldr; SVCUtil does not Generate Code for Nested Attributes in AttributeGroup; here is the code (github repo) and explanation of a workaround.

Beyond Controlled HelloWorld() samples, interoperability standards are not black and white, rather a process that has shades of gray. If you've worked on consuming 3rd party 'enterprise' API's, you may have encountered problems with flattening of WSDL’s, or when generating a service proxy using svcutil.exe, noticed that not all attribute groups gets generated.  For instance, an attributeGroup wrapping another which contains attributes, those attributes will NOT be generated.

I tried a few things like using the DataContractSerializer but it appears that the attributeGroup is ignored by design. The only workaround appears to be removing the extra attributeGroup wrapping. DataContractSerializer does not recognize the attributeGroup (see Data Contract Schema Reference) and as you have already noticed, Xsd (essentially the XmlSerializer) does not recognize nested attributeGroups.

One Reference workaround that is described here, essentially asks you to replace the attributeGroup elements with the actual attributes.

For example:

<xs:attributeGroup name="myAttributeGroup">
<xs:attribute name="someattribute1" type="xs:integer"/>
<xs:attribute name="someattribute2" type="xs:string"/>
</xs:attributeGroup>

<xs:complexType name="myElementType">
<xs:attributeGroup ref="myAttributeGroup"/>
</xs:complexType>

should be transformed into:

<xs:complexType name="myElementType">
<xs:attribute name="someattribute1" type="xs:integer"/>
<xs:attribute name="someattribute2" type="xs:string"/>
</xs:complexType>

To do this in a repeatable manner, following code provides a good starting point on how to handle the attributeGroup issue. Here is a before and after screenshot of WSDL's.

SVCUtil does not Generate Code for Nested Attributes in AttributeGroup

 

I created a small C# app to transform the data, and then run svcutil to generate the WSDL. essentially replacing all instances of <attributeGroup ref=”xxx”> with the definitions of <attributeGroupname=”xxx”>, just as described in the link that I provided earlier.

XDocument wsdl = XDocument.Load(inputFile);

IEnumerable<XElement> attributeGroupDefs =
wsdl.Root.Descendants("{http://www.w3.org/2001/XMLSchema}attributeGroup")
.Where(w => w.Attribute("name") != null)
.Select(x => x);

foreach (
XElement r in
wsdl.Root.Descendants("{http://www.w3.org/2001/XMLSchema}attributeGroup")
.Where(w => w.Attribute("ref") != null))
{
string refValue = r.Attribute("ref").Value;

foreach (XElement d in attributeGroupDefs)
{
string defValue = d.Attribute("name").Value;
if (refValue == defValue)
{
IEnumerable<XElement> s =
d.Elements("{http://www.w3.org/2001/XMLSchema}attribute").Select(x => x);
foreach (XElement e in s)
{
r.AddBeforeSelf(e);
}
break;
}
}
}

wsdl.Root.Descendants("{http://www.w3.org/2001/XMLSchema}attributeGroup")
.Where(w => w.Attribute("ref") != null)
.Remove();
wsdl.Save(outFile);

 

This may require some more tweaking, but it appears have corrected all / most of the attributeGroup issues (I only spot checked this).

Happy Coding!

Share