Breaking changes in SoapSerializer.XmlSerializer for previously generated ASMX client code
See original GitHub issueI have legacy ASMX webservices, which are being used by some third-party stakeholders, who we cannot control. So our ultimate goal is to migrate .NET 4.7.2 solution to .NET 6 without (major) breaking changes for our clients. SoapCore looked like a savior here, and it was really promising when we were prototyping it with some basic web services. However testing it in our main solution - there are some corner cases, which we cannot to find a way how to workaround.
1. Guid[] type in requests object in a legacy solution was specified as “ArrayOfGuid” complex type. It was looking like this (here and below - WSDL definition is truncated for brevity, but I can provide a full one if it would help):
<s:complexType name="GetPricesRequest">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" ref="s1:Product"/>
<s:element minOccurs="0" maxOccurs="1" name="ProductIds" type="tns:ArrayOfGuid"/>
</s:sequence>
</s:complexType>
<s:complexType name="ArrayOfGuid">
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="guid" type="s2:guid"/>
</s:sequence>
</s:complexType>
<s:schema elementFormDefault="qualified" targetNamespace="http://microsoft.com/wsdl/types/">
<s:simpleType name="guid">
<s:restriction base="s:string">
<s:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
</s:restriction>
</s:simpleType>
</s:schema>
With SoapCore, using XmlSerializer - it’s just “ArrayOfString”:
<xsd:complexType name="GetPricesRequest">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="Product" type="tns:ProductDto"/>
<xsd:element minOccurs="0" maxOccurs="1" name="ProductIds" type="tns:ArrayOfString"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfString">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="unbounded" name="string" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
As the result, using that client - it fails to map, and webservices receives an empty array. Is it by design, is it a configuration issue, or some potential missing feature? Any ideas where we could look at in case we would like to contribute with some pull-request?
2. Another issue with same contract is with XmlElement
attributes usage.
We have the following request object with a complex type inside:
[XmlType(Namespace = "urn:Bbb.Services.Management")]
public class GetPricesRequest
{
[XmlElement("Product", Namespace = "urn:Bbb.Services.Common")]
public ProductDto Product { get; set; }
public Guid[] ProductIds { get; set; }
}
In a legacy solution it was looking like this:
<s:element name="Product" type="s1:ProductDto"/>
<s:complexType name="ProductDto">
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Id" type="s2:guid"/>
<s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="Type" type="s:string"/>
</s:sequence>
</s:complexType>
In new one there is something completely broken, it returns invalid WSDL, with duplicated elements, which cannot be consumed (note how name="Product"
is duplicated):
<xsd:element minOccurs="0" maxOccurs="1" name="Product" type="tns:ProductDto"/>
<xsd:complexType name="ProductDto">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="Product" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="Product" type="xsd:string"/>
<xsd:element minOccurs="1" maxOccurs="1" name="Product" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
If I drop XmlElement
attribute - it produces a valid WSDL, but it still cannot be consumed by legacy clients (due to the first issue, and due to breaking change).
I won’t advocate, that it was correctly configured in our legacy solution, but it was working like that for years. (If it was a bug, it was used as a feature.😃 )
Any ideas how we could workaround it, or at least minimize possible breaking changes?
Update: my intermediate achievement - old clients are working, but new ones are failing to map request parameters correctly (webservice receives empty parameters). 🤷♂️
It was achieved by leaving XmlElement
without “ElementName”, just with “Namesapce”.
Issue Analytics
- State:
- Created a year ago
- Comments:10 (6 by maintainers)
If you’re only having issue with newly generated clients then I believe a focus on WSDL differences is the correct approach.
There is an option to use a file as your WSDL https://github.com/DigDes/SoapCore#using-with-external-wsdl--xsd-schemas
Try using the legacy WSDL this way, and see if newly generated clients work. If you then feel like making it work with the WSDL generated by SoapCore, remove differences from the file until you find the culprit (for example, remove the “schema” bit and see if it stops working). Then support could be added for the critical bits.
So, seems like external WSDL schemas support are fully enough for us, since we are not planning to add any new features to our legacy ASMX web services. Thanks for pointing it out once again! 👍 I said fully, but actually there were some missing options. 😃 It kind of was working, but some additional workarounds were needed (like duplicated endpoints with different paths for same webservice). As promised about contributing to this project, I created my first pull-request with potential improvements - https://github.com/DigDes/SoapCore/pull/904. Will see how it goes, but I hope someone manages to review it and move further. 😃
(The mentioned pull-request is not to fix this issue, but perhaps others would be able to solve similar issues in a similar way.)