Invalid WSDL generated?

This may be related to my other issue with OpenAPI (Parameters cannot have both a "in: body" and "in: formData", as "formData" _will_ be the body) but I am getting what appears to be incorrectly generated WSDL for SOAP 1.2.

The root of the problem appears to be that the WSDL and XSD seem to expect certain types (typically array types) to be declared in a standard XSD when they’re not.

For example, in the definition of the response you find

  <xs:complexType name="ResponseStatus">
    <xs:sequence>
      <xs:element name="ErrorCode" type="xs:string" minOccurs="0" nillable="true"/>
      <xs:element name="Message" type="xs:string" minOccurs="0" nillable="true"/>
      <xs:element name="StackTrace" type="xs:string" minOccurs="0" nillable="true"/>
      <xs:element name="Errors" type="tns:ArrayOfResponseError" minOccurs="0" nillable="true"/>
      <xs:element name="Meta" type="q8:ArrayOfKeyValueOfstringstring" minOccurs="0" nillable="true" xmlns:q8="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
    </xs:sequence>
  </xs:complexType>

Which presumes there is a definition of ArrayOfKeyValueOfstringstring in the “http://schemas.microsoft.com/2003/10/Serialization/Arrays” schema – but there isn’t. Similar expectations are found throughout the XSD, with things like ArrayOfdouble and ArrayOfdateTime.

The DTO is simply:

[DataContract]
[Route("/candidate", “PUT”, Summary = “Create or update a candidate”)]
public class CandidatePut : IReturn
{
// Unique to this put
[DataMember]
[ApiMember(Description = “Details of the candidate to update or add”, IsRequired = true)]
public Candidate candidate { get; set; }
}

public class CandidatePutResponse : IHasResponseStatus
{
    [DataMember]
    [ApiMember(Description = "The unique reference for the updated or newly inserted candidate record")]
    public Int32 CandidateRef { get; set; }
    public ResponseStatus ResponseStatus { get; set; }
}


public class Candidate
{
    [DataMember]
    [ApiMember(Description = "The unique reference for this candidate. When PUTting a record if this value is 0 then a new candidate will be added")]
    public Int32 CandidateRef { get; set; }
}

If you want to use SOAP Support you need to ensure all your DTOs are in a single WSDL namespace and all classes are attributed with [DataContract] and all properties are attributed with [DataMember].

I believe that is what I have done. The sample project I’ve linked for my other question (https://forums.servicestack.net/t/parameters-cannot-have-both-a-in-body-and-in-formdata-as-formdata–will–be-the-body/6505?u=nic65535) regarding OpenAPI also demonstrates this problem. I’m sure that both issues are related to the way I have constructed and/or annotated the DTOs but I can’t figure out how.

Please read my comments and links carefully.

All DTO classes need [DataContract] attributes, i.e:

    [DataContract]
    [Route("/candidate", "PUT", Summary = "Create or update a candidate")]
    public class CandidatePut : IReturn<CandidatePutResponse>
    {
        // Unique to this put
        [DataMember]
        [ApiMember(Description = "Details of the candidate to update or add", IsRequired = true)]
        public Candidate candidate { get; set; }
    }

    [DataContract]
    public class CandidatePutResponse : IHasResponseStatus
    {
        [DataMember]
        [ApiMember(Description = "The unique reference for the updated or newly inserted candidate record")]
        public Int32 CandidateRef { get; set; }
        public ResponseStatus ResponseStatus { get; set; }
    }

    [DataContract]
    public class Candidate
    {
        [DataMember]
        [ApiMember(Description = "The unique reference for this candidate. When PUTting a record if this value is 0 then a new candidate will be added")]
        public Int32 CandidateRef { get; set; }
    }

Also all DTOs need to be in the same namespace, please add these assembly attributes to TestOpenAPI.ServiceModel\Properties\AssemblyInfo.cs:

[assembly: ContractNamespace("http://schemas.servicestack.net/types",
    ClrNamespace = "TestOpenAPI.ServiceModel")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types",
    ClrNamespace = "TestOpenAPI.ServiceModel.Types")]

Also note that SOAP Support is only supported in classic ASP.NET Framework Web Apps, it can still work in your SelfHost HttpListener App but it’s not a supported configuration.

1 Like

Thanks mythz - I couldn’t figure out what I was doing wrong - I guess “All DTO classes” should be self explanatory :blush:

I also found I needed the [DataContract] attribute on any Enum’s to get them into the right namespace (just mentioning it in case it is useful to anyone else trying to chase this down in the future).

Thanks again

Nic

1 Like