Так как нет желающих, я опишу, что я сделал на сегодняшний день на случай, если у кого-то еще возникнет подобная проблема.
На моем клиенте (с использованием Office 2003 Web Services Toolkit) я хочу получить коллекцию объектов, свойство которых само по себе является коллекцией объектов. Например, коллекция объектов Customer из веб-службы C #, где класс Customer выглядит примерно так:
public class Customer
{
public string Name { get; set; }
public Collection<Address> Addresses { get; }
}
У меня проблема в том, что свойство Addresses иногда может быть пустой коллекцией, и SOAP30 GenericTypeMapper не может это обработать.
В моем конкретном случае клиент на самом деле не нуждался в наборе адресов, я просто хочу иметь возможность получить другие свойства класса Customer. Поэтому мне все равно, что находится в свойстве варианта «Адреса», которое создается инструментарием веб-служб.
Я создал библиотеку ActiveX VB6 с классом минималистской реализации ISoapMapper, который всегда возвращает ссылку на неинициализированный объект:
Implements ISoapTypeMapper
Private Function ISoapTypeMapper_Iid() As String
End Function
Private Sub ISoapTypeMapper_Init(ByVal par_Factory As MSOSOAPLib30.ISoapTypeMapperFactory, ByVal par_Schema As MSXML2.IXMLDOMNode, ByVal par_WSMLNode As MSXML2.IXMLDOMNode, ByVal par_xsdType As MSOSOAPLib30.enXSDType)
End Sub
Private Function ISoapTypeMapper_Read(ByVal par_soapreader As MSOSOAPLib30.ISoapReader, ByVal par_Node As MSXML2.IXMLDOMNode, ByVal par_encoding As String, ByVal par_encodingMode As MSOSOAPLib30.enEncodingStyle, ByVal par_flags As Long) As Variant
Set ISoapTypeMapper_Read = Nothing
End Function
Private Function ISoapTypeMapper_SchemaNode() As MSXML2.IXMLDOMNode
Set ISoapTypeMapper_SchemaNode = Nothing
End Function
Private Function ISoapTypeMapper_VarType() As Long
ISoapTypeMapper_VarType = vbObject
End Function
Private Sub ISoapTypeMapper_Write(ByVal par_ISoapSerializer As MSOSOAPLib30.ISoapSerializer, ByVal par_encoding As String, ByVal par_encodingMode As MSOSOAPLib30.enEncodingStyle, ByVal par_flags As Long, par_var As Variant)
End Sub
Private Function ISoapTypeMapper_XsdType() As MSOSOAPLib30.enXSDType
ISoapTypeMapper_XsdType = enXSDUndefined
End Function
Затем я изменил WSML, сгенерированный инструментарием веб-служб, чтобы использовать эту реализацию для соответствующего свойства:
Dim str_WSML As String
str_WSML = "<servicemapping>"
str_WSML = str_WSML & "<service name='MyService'>"
str_WSML = str_WSML & "<using PROGID='MSOSOAP.GenericCustomTypeMapper30' cachable='0' ID='GCTM'/>"
str_WSML = str_WSML & "<using PROGID='SoapHelper.EmptyArrayMapper' cachable='0' ID='EATM'/>" ' <== Added this line
str_WSML = str_WSML & "<types>"
...
str_WSML = str_WSML & "<type name='ArrayOfAddress' targetNamespace='http://...' uses='EATM' targetClassName='struct_Address'/>" '<== Added this line
str_WSML = str_WSML & "<type name='Address' targetNamespace='http://mynamespace.com/myapp/services/data' uses='GCTM' targetClassName='struct_Address'/>"
...
Это достигло того, что мне было нужно для этого приложения.
Мне кажется, что можно добиться поддержки пустых массивов в более общем смысле, реализовав ISoapMapper таким образом, что:
Обнаруживает и обрабатывает случай пустого массива.
Или, если массив не пустой, он делегируется стандартному GenericTypeMapper.
Мне все равно было бы интересно узнать, решил ли кто-нибудь общую проблему. Возможно, нет, так как клиент SOAP устарел и больше не поддерживается Microsoft.