Vyacheslav Dulnev responded to the issue with the following :
Nillable Types.
Now this works. Unfortunately I can’t give you a patch but our next release will be soon. Now structure for nillable simple type should have two attributes: “IsSimpleTypeExtension” and “Nillable”.
I waited, updated remobjects to 6.0.53.935 and tried this solution but it is still a non starter. For instance, although the server will accept the xml with the nil flags on data types it still does not decode the types properly and strings end up as empty strings, integers give ‘’ is not a valid integer conversion errors.
Am I doing something wrong or is this code still broken?
I can provide sample applications if required.
Regards,
Will.
(01-Nov-2013 edited to quote the code properly in the new RO:Talk Forums)
I’d like to support this thread as I also would love to have nillable support. Six months back this was not possible and empty integer parameters would throw errors -> I ended up hacking the RO source code to avoid these exceptions… So it works now but it is not clean…
In general for nillable simple type is used wrapper, structure with one element with this simple type. If in SOAP request it value is nil, corresponding object instance in Delphi also is nil, so I don’t understand what means
Will_Honor said: strings end up as empty strings, integers give '' is not a valid integer conversion errors.
because nothing to decode. I’ve attached small test case, please look at it.
Thankyou.
Your sample works but is very simple. I have made a change to better illustrate what I’m seeing. It seems that if the nil vale is passed as a parameter to the RPC method then it works ok. If the call has a complextype with some nillable fields then it does not work.
A modified version of your sample is attached to this message. I will attach my examples to the next message.
Here is my test server and client. The server is written in delphi and the client is written in Prism. The client sets up an object to send. The server just sends that object back to the client. You will see that nil integers result in an error and nothing will ever be sent back to the client as nil.
Slavad,
Given that the issue is to do with nillable types I wonder why the SOAP packet you posted does not contain a nil. Did you really try the example app I gave you? I have attached some images showing the issues I am having. Note that the server does nothing more than bounce the complextype back to the client. What I have seen in the case of String and DateTime is that the nil value is lost. It is lost before it surfaces in the Delphi service so it is not possible to tell that they were nil when sent.
Integer types raise an EConvert error when the incoming xml is decoded on the server causing a soap fault to be sent to the client.
Please see the images and take another look at the test case. I am convinced this functionality is broken.
I think I have found the issue. In your working example the namespace for the nil values is xsi:nil. For my examples the namespace is something different.
I have looked through the RO source code and it seems that it is hard coded to require xsi as the namespace prefix. see tag_nil in uROXMLSerializer. I don’t think this is correct as different implementations of soap clients could use anything as the namespace prefix.
Namespacing is certainly the issue here. I have modified uROXMLSerializer to properly determine if a field is nil without using the hard coded xsi:nil value.
I created a new function called IsNodeValueNil and replaced all the instances where nil was incorrectly read from the node. There were lots of instances of the following in the code.
if (subnode<>NIL) then
lNilAttr := subnode.GetAttributeByName(tag_Nil);
if Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) then subnode := nil;
These have now been replaced with the new function. Fully updated uROXMLSerializer attached for anyone interested.
Regards,
Will.
function TROXMLSerializer.IsNodeValueNil(aNode : IXMLNode) : Boolean ;
const
tag_XSI_SCHEMA = 'http://www.w3.org/2001/XMLSchema-instance' ;
var
i : integer ;
lNilAttr : IXMLNode ;
begin
if aNode=nil then
begin
result := true ;
exit ;
end;
for I := 0 to aNode.AttributeCount-1 do
begin
// note some clients inclue the trailing '/' in the namespace uri so use copy to look for the bulk of the uri.
if comparetext(tag_XSI_SCHEMA,copy(aNode.Attributes[i].NamespaceURI,1,length(tag_XSI_SCHEMA)))=0 then
if pos(':nil',aNode.Attributes[i].Name)>0 then
begin
lNilAttr := aNode.Attributes[i] ;
break;
end;
end;
result := (Assigned(lNilAttr) and (lNilAttr.Value = tag_NilValue) )
end;
(01-Nov-2013 edited to quote the code properly in the new RO:Talk Forums)