SOAP nillable types in Remobjects soap server

Hello,
I posted a request to the nntp newsgroups back in July notifying RO of some issues when trying to create a webservice which will accept nil values. See
http://www.codenewsfast.com/cnf/article/0/waArticleBookmark.7451008

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”.

<Struct Name="NString" UID="{30002E81-0135-42A4-8C19-DA0A02EDBA5D}" AutoCreateParams="0">
<CustomAttributes>
  <IsSimpleTypeExtension Value="1"/>
  <Nillable Value="1"/>
</CustomAttributes>
<Elements>
  <Element Name="Value" DataType="AnsiString">
  </Element>
</Elements>
</Struct>

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…

Thx,
P.

Hi.

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.

Regards,
Will.

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.

Regards,
Will.

What I am waiting for is “nillable” attribute for simple types (logged as 46922). Do you know when you will implement this?

-> See my post “Handle NULL with RO” on April 06, 2011 13:32 in the RO SDK NNTP

Will_Honor said: Here is my test server and client.

I didn’t see any problems with Delphi server. It works fine for such request:

   
   
      
         
            text
            123
            2001-11-20
         
      
   

Do you have problem with .Net client? If so, what version of Prism you are using?

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.



Hi Will.

I tested with nil values as well, here is result for Delphi XE and latest RemObjects SDK 6.0.53.935.

What version of RemObjectsSDK and Delphi you are using?

Delphi XE and RO 6.0.53.935

I’m going to do a full reinstall to make sure I’m not linking in some old code from somewhere else.

Regards,
Will.

Hello,
I reinstalled, no change.

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.

Regards,
Will.

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)

Hi Will.

Thank you for fix.