Polymorphic return values

6

6kjfsyg02

I am trying to return one of two different objects from the same
method, but I can not do it in WSDL or C#.

I have a web service with three methods.

I have been told that one of the methods must return either <Respuesta
....> or <ConfirmacionPeticion ...> directly under the SOAP Body. Other
methods are already capable of returning just <Respuesta ...> or just
<ConfirmacionPeticion ...>. What is new is one method being capable of
returning both types.

I have been modifying over one of the previous methods:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)]
[return: XmlElement( Respuesta.Marca, Namespace =
Respuesta.EspacioNombres)]
public Respuesta solicitaRespuestaAsincrona( ...)

The obvious thing is to substitute the return type by object:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)]
public object solicitaRespuestaAsincrona( ...)

But then the automatic WSDL becomes:

<wsdl:message name="solicitaRespuestaAsincronaSoapOut">
<wsdl:part name="solicitaRespuestaAsincronaResult"
element="tns:solicitaRespuestaAsincronaResult"/>
</wsdl:message>

That is, under <soap:Body> I get a <solicitaRespuestaAsincronaResult>
element followed by the members of the actual object being returned.
This is not what I want, I want either <Respuesta> or
<ConfirmacionRespuesta>.

I then tried to have several XML return attributes:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)
[return:
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]]
public object solicitaRespuestaAsincrona( ...)

but then I get:

System.InvalidOperationException: You need to add
XmlChoiceIdentifierAttribute to the 'solicitaRespuestaAsincronaResult'
member.


I then tried the inverse route of hacking the WSDL. I created a new
type:

<wsdl:types>
....
<!-- Since this does not have a namespace, this breaks the Basic
Profile. -->
<s:schema elementFormDefault="qualified">
<s:complexType name="RespuestaOConfirmacion" >
<s:sequence>
<s:choice minOccurs="0" maxOccurs="1">
<s:element minOccurs="1" maxOccurs="1" name="Respuesta" />
<s:element minOccurs="1" maxOccurs="1"
name="ConfirmacionPeticion" />
</s:choice>
</s:sequence>
</s:complexType>
<!-- Without an explicit element:
// CODEGEN: The operation binding 'solicitaRespuestaAsincrona'
from
namespace 'http://www.map.es/scsp/' was ignored.
Specifying a type for use=literal messages is not supported.
Type name='RespuestaOConfirmacion' from targetNamespace=''
cannot be used as top-level any element.-->
<s:element name="RespuestaOConfirmacion"
type="RespuestaOConfirmacion"/>
</s:schema>
</wsdl:types>

and

<wsdl:message name="solicitaRespuestaAsincronaSoapOut">
<wsdl:part name="solicitaRespuestaAsincronaResult"
element="RespuestaOConfirmacion"/>
</wsdl:message>

This type is stubbed as

public partial class RespuestaOConfirmacion
{
[XmlElement("ConfirmacionPeticion", typeof(ConfirmacionPeticion))]
[XmlElement("Respuesta", typeof(Respuesta))]
[XmlChoiceIdentifier("nombreElemento")]
public object unaRespuestaOUnaConfirmacion;

[System.Xml.Serialization.XmlIgnoreAttribute()]
public RespuestaOConfirmacionEleccion nombreElemento;
}

[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema =
false)]
public enum
RespuestaOConfirmacionEleccion
{
ConfirmacionPeticion,
Respuesta
}


I then tried with:

....
[return:
XmlChoiceIdentifier(MemberName = "nombreElemento"),
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]
public RespuestaOConfirmacion solicitaRespuestaAsincrona( ...)

This causes:

System.InvalidOperationException: There was an error reflecting
'solicitaRespuestaAsincronaResult'. --->
System.InvalidOperationException: Missing 'nombreElemento' member
needed for serialization of choice 'solicitaRespuestaAsincronaResult'.

in spite of me assigning a value to the nombreElemento field in the
return value.

If I have

[return:
XmlChoiceIdentifier(MemberName = "nombreElemento"),
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]
[return: XmlElement("RespuestaOConfirmacion", Namespace = "")]

the return value is serialized as
<RespuestaOConfirmacion>
<Respuesta ...>
....
</RespuestaOConfirmacion>

That is, the Respuesta or the ConfrimacionPeticion are wrapped with
<RespuestaOConfirmacion> which again is not what I want.


So summarizing, how do you express either in C# or in WSDL that you can
return any of two different elements under <soap:Body>?

Thanks in advance.
 
Y

Yunus Emre ALPÖZEN [MVP]

My advice u to use a union for multiple return types...

--
HTH

Thanks,
Yunus Emre ALPÖZEN
BSc, MCSD.NET
Microsoft .NET & Security MVP

I am trying to return one of two different objects from the same
method, but I can not do it in WSDL or C#.

I have a web service with three methods.

I have been told that one of the methods must return either <Respuesta
...> or <ConfirmacionPeticion ...> directly under the SOAP Body. Other
methods are already capable of returning just <Respuesta ...> or just
<ConfirmacionPeticion ...>. What is new is one method being capable of
returning both types.

I have been modifying over one of the previous methods:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)]
[return: XmlElement( Respuesta.Marca, Namespace =
Respuesta.EspacioNombres)]
public Respuesta solicitaRespuestaAsincrona( ...)

The obvious thing is to substitute the return type by object:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)]
public object solicitaRespuestaAsincrona( ...)

But then the automatic WSDL becomes:

<wsdl:message name="solicitaRespuestaAsincronaSoapOut">
<wsdl:part name="solicitaRespuestaAsincronaResult"
element="tns:solicitaRespuestaAsincronaResult"/>
</wsdl:message>

That is, under <soap:Body> I get a <solicitaRespuestaAsincronaResult>
element followed by the members of the actual object being returned.
This is not what I want, I want either <Respuesta> or
<ConfirmacionRespuesta>.

I then tried to have several XML return attributes:

[WebMethodAttribute( Description = "Blah...")]
[SoapDocumentMethod( ourMethodNamespace, Use = SoapBindingUse.Literal,
ParameterStyle = SoapParameterStyle.Bare)
[return:
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]]
public object solicitaRespuestaAsincrona( ...)

but then I get:

System.InvalidOperationException: You need to add
XmlChoiceIdentifierAttribute to the 'solicitaRespuestaAsincronaResult'
member.


I then tried the inverse route of hacking the WSDL. I created a new
type:

<wsdl:types>
...
<!-- Since this does not have a namespace, this breaks the Basic
Profile. -->
<s:schema elementFormDefault="qualified">
<s:complexType name="RespuestaOConfirmacion" >
<s:sequence>
<s:choice minOccurs="0" maxOccurs="1">
<s:element minOccurs="1" maxOccurs="1" name="Respuesta" />
<s:element minOccurs="1" maxOccurs="1"
name="ConfirmacionPeticion" />
</s:choice>
</s:sequence>
</s:complexType>
<!-- Without an explicit element:
// CODEGEN: The operation binding 'solicitaRespuestaAsincrona'
from
namespace 'http://www.map.es/scsp/' was ignored.
Specifying a type for use=literal messages is not supported.
Type name='RespuestaOConfirmacion' from targetNamespace=''
cannot be used as top-level any element.-->
<s:element name="RespuestaOConfirmacion"
type="RespuestaOConfirmacion"/>
</s:schema>
</wsdl:types>

and

<wsdl:message name="solicitaRespuestaAsincronaSoapOut">
<wsdl:part name="solicitaRespuestaAsincronaResult"
element="RespuestaOConfirmacion"/>
</wsdl:message>

This type is stubbed as

public partial class RespuestaOConfirmacion
{
[XmlElement("ConfirmacionPeticion", typeof(ConfirmacionPeticion))]
[XmlElement("Respuesta", typeof(Respuesta))]
[XmlChoiceIdentifier("nombreElemento")]
public object unaRespuestaOUnaConfirmacion;

[System.Xml.Serialization.XmlIgnoreAttribute()]
public RespuestaOConfirmacionEleccion nombreElemento;
}

[System.Xml.Serialization.XmlTypeAttribute(IncludeInSchema =
false)]
public enum
RespuestaOConfirmacionEleccion
{
ConfirmacionPeticion,
Respuesta
}


I then tried with:

...
[return:
XmlChoiceIdentifier(MemberName = "nombreElemento"),
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]
public RespuestaOConfirmacion solicitaRespuestaAsincrona( ...)

This causes:

System.InvalidOperationException: There was an error reflecting
'solicitaRespuestaAsincronaResult'. --->
System.InvalidOperationException: Missing 'nombreElemento' member
needed for serialization of choice 'solicitaRespuestaAsincronaResult'.

in spite of me assigning a value to the nombreElemento field in the
return value.

If I have

[return:
XmlChoiceIdentifier(MemberName = "nombreElemento"),
XmlElement( Respuesta.Marca,
Namespace = Respuesta.EspacioNombres),
XmlElement( ConfirmacionPeticion.Marca,
Namespace = ConfirmacionPeticion.EspacioNombres)]
[return: XmlElement("RespuestaOConfirmacion", Namespace = "")]

the return value is serialized as
<RespuestaOConfirmacion>
<Respuesta ...>
...
</RespuestaOConfirmacion>

That is, the Respuesta or the ConfrimacionPeticion are wrapped with
<RespuestaOConfirmacion> which again is not what I want.


So summarizing, how do you express either in C# or in WSDL that you can
return any of two different elements under <soap:Body>?

Thanks in advance.
 
6

6kjfsyg02

Yunus said:
My advice u to use a union for multiple return types...

I appreciate your answer. From my understanding and the message from
the WSDL editor in Visual Studio, union only works with simpleType.
Respuesta and ConfirmacionPeticion are complexType.

I am going to look into abstract types, but I understand that it
requires including an xsi:type in <Respuesta ...> and
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top