I have been having trouble trying to transfer a file between a Delphi
Client and a Java Web Service. We wanted to use Base64 encoding - but
there is a bug in D6 that doesn't allow the TByteDynArray to auto
encode/decode the Base64 stream. So - I couldn't transfer the file
without changing the code in the Java WS.
However - many thanks to Dan Miser who basically gave me the solution -
so I thought I would pass it on to other here. (Thanks again to Dan!)
When I import the WSDL in to my Delphi App - the Base64 return is shown
as a TByteDynArray. However, this won't work. But change the return
type to Variant (Manually) and then you can decode the Base64 stream
yourself. So below in the Interface I show the new and then the
original.
-------- INTERFACE GEN FROM WSDL --------
function get(const buzpak_handle: Int64): Variant; stdcall;
// function get(const buzpak_handle: Int64): TByteDynArray; stdcall;
Now in the Implementation I use a nice little component from Ralf Junker
<ralfj...@gmx.de> http://www.zeitungsjunge.de/delphi/ - and is now part
of the Jedi Code Library. This routine is very easy to use - and only
requires one line of code.
-------- IMPLEMENTATION --------
Var
TempStr :Variant;
TempStr2 :String;
FS :TFileStream;
SS :TStringStream;
begin
TempStr := (httprio1 as buzpakservice).Get(1);
TempStr2 := TempStr;
SS := TStringStream.Create('');
SS.WriteString(TempStr2);
FS := TFileStream.Create('c:\buzPAKs\aaaaTest2.buz', fmCreate);
FS.Position := 0;
SS.Position := 0;
MimeDecodeStream(ss, fs);
The result is a fully decoded file - stored in the FileStream - in other
words - written to file.
G. Bradley MacDonald
Thanks for sharing this information!
FYI - Indy has Base64 encode/decode routines and if I'm not mistaken (I
remember seeing the unit) Delphi 6 comes with its own Base64 encode/decode
routines as well.
--
Shiv Kumar
The Delphi Apostle
http://www.matlus.com
http://www.delphisoap.com
You are correct about Indy - in fact Indy 8.1 (beta ?) has the ability to
encode/decode a Steam in place. Very nice - and you don't have to use
two!
Bradley
My kettle just spews it out <g> But then it's probably an older model than
yours.
As stated in my previous post I have a solution to receiving Base64
streams - but now I need to send one and I am getting a variant error
when I try.
The Java side uses the Base64 XML field to auto encode the stream. So I
have to encode and decode it manually right now (bug soon to be fixed in
D6). When I import the Web service I get a field type of TByteDynArray.
I have to change this to a Variant in order to be able to manually
decode/encode the stream. This works really well for incoming streams -
how ever it is failing on the outgoing. I keep getting an Invalid
Variant Operation when I try this.
Any thoughts off the top of your head? Am I doing something obviously
wrong?
Bradley
procedure TForm1.Button_SendBuzPAKClick(Sender: TObject);
Var
TempStr :Variant;
TempStr2 :String;
FS :TFileStream;
SS :TStringStream;
SendResult :Integer;
begin
// Get the file to transfer
If OpenDialog_Input.Execute Then Begin
// Create the two streams
FS := TFileStream.Create(OpenDialog_Input.FileName, fmOpenRead);
SS := TStringStream.Create('');
Try
FS.Position := 0;
SS.Position := 0;
// This Base64 Encodes the Stream and puts it in the String Stream
MimeEncodeStream(fs, ss);
SS.Position := 0;
// Now Read the Base64 String into a reg String
TempStr2 := SS.ReadString(SS.Size);
SS.Position := 0;
SS.Position := 0;
// Now here I am trying to create the Variant. I have tried just
// using a Variant without an array,
// I have also tried other variant types (ie varString) - but it
// fails as well.
TempStr := VarArrayCreate([0,(Length(TempStr2) -1)], varVariant);
TempStr := TempStr2;
// At this point in the code - I get a Variant Error - Invalid Variant
// Operation
SendResult := (httprio1 as buzpakservice).openFromData(TempStr);
ShowMessage('Send Result : ' + InttoStr(Sendresult));
Finally
FS.Free;
SS.Free;
End; { Try..Finally }
End; { If }
end;
Do you have control of both ends ? ( server and client ), if so
you may try "hexBinary" encoding.
Does Delphi supports "xsd:hexBinary" ? Maybe you should try this type
of binary mapping.
Rosimildo.
the variant is declared as a Const parameter. However, if I change this
to not be a Const - then I get a Internal Server Error 500.
Anyone have any ideas on this?
Bradley
WOW !, I feel your pain..... <g>
Rosimildo.
Sounds like a good plan....
>
>As well we have various other WebService clients that will have to access
>these services so doing special coding is out of the question -
Who talked about special coding. ?
I mentioned another XML Schema 2001 simple type, xsd:hexBinary
as another type to carry binary information. Most of the SOAP stacks
that I know of, supports it. I just asked if Delphi supports ? From the
application standpoint, it does not matter if you use base64 or
hexBinary does it ? ( as long as works !!! ).
>especially if we will be converting back after ward. So we have to use
>Base64
>
OK. looks like base64 is a requirement. <G>
Rosimildo.
As well we have various other WebService clients that will have to access
these services so doing special coding is out of the question -
especially if we will be converting back after ward. So we have to use
Base64
Thanks
Bradley
type
PByte = ^Byte;
var
barray: TByteDynArray;
s: string;
p: pointer;
bp: PByte;
i: integer;
begin
// think of s as your streamed string...
s := 'Hello World';
// this function is in the idcoder3to4.pas file
s := Base64Encode(s);
SetLength(barray, StrLen(PChar(s)));
for i := 1 to StrLen(PChar(s)) do
begin
// use pointers to stick the actual byte value of the character into the
array...
p := @s[i];
bp := PByte(p);
barray[i-1] := bp^;
end;
// kick it back out...
result := barray;
end;
Does this help? Did I understand your problem correctly? Let me know, I'd
be interested to see how it turns out.
"G. Bradley MacDonald" <Bradley_...@telus.net> wrote in message
news:MPG.15c21b18d...@newsgroups.borland.com...
I will not be able to test this until Monday. But I will let you know
ASAP. Thank you for the reply!
Bradley
I'm trying to do the same and tried your code. I also got the Internal Server Error 500. I noticed that I got this with file that were a bit longer...
I used the following code to monitor what was happening:
procedure TWebModule1.WebModuleBeforeDispatch(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
idsmtp.QuickSend('smtp.comp.nl', 'test','m...@comp.nl',
'm...@comp.nl', request.content);
end;
This sends me an Email with the SOAP document. A part looks like this (just an example):
<NS1:filecontent xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:unsignedByte[477]"><NS1:item>91</NS1:item><NS1:item>98</NS1:item><NS1:item>13</NS1:item></NS1:filecontent>
Every byte in the array is translated into something like <NS1:item>98</NS1:item>. So at least 23 bytes! This is not what we want, is it? We want it to be Base64 encoded.
In case you send a bit longer file the line seems to be truncated, hence the Internal Server Error 500.
I haven't found the solution yet, but I hope this helps. Keep us posted...
Frits.
Borland is aware of the issue with the TByteDynArray - and is working on
a fix. However, with the conference going on - I think they might be a
little distracted <g> and will probably not have a fix until after.
Bradley
PS. If you need a work around - you can get PocketSoap and use it until
the fix for D6 comes out.
Thanks for the post - but the problem with using a TByteDynArray is that
it is not converted properly. Each byte is converted and surrounded in
<ns1> tags - so the Java server doesn't know what to do with it.
I was hoping that I would be able to fudge it with the variant - but I
think I am going to have to wait for Borland's fix :(
Bradley
Wow! Great stuff. This class seems to be sending things across the wire
correctly - but our Java server is still dieing on the Send of the
Base64. So I can receive the Base64 - but not send it to the server.
However, the Server guys are starting to think that it may be something
on their side <g> So - I will keep you posted as to what we discover
today!
Thank you for the assistance
Bradley
In article <3b5cec96_2@dnews>, nkri...@thedswgroup.com says...
> I see what you mean, however, you got me thinking and I think I have a
> solution for you
Your analysis is correct. From the Envelopes below, this should not work.
The SOAP-ENC namespace "http://schemas.xmlsoap.org/soap/encoding/"
defines a type called "base64", using this namespace should work.
The XML Schema 2001 changed the name of the "base64" to "base64Binary".
So, xmlns:xsd="http://www.w3.org/2001/XMLSchema" for the "xsd" namepsace,
the type used should be "xsd:base64Binary", otherwise it is an invalid type
for the given namespace.
Another thing to watch for is the XML Schema used. It looks like that you
java server only accepts "2001" XML schema. If this is true, it most likely
would not know what to do with "1999" schema.
Rosimildo.
The saga continues... <g> It looks like it may be an interop issue.
The real issue - as far a I can see is that we are having an issue with
how Delphi is setting up the soap packet. The error I am now getting is
shown below in the error section. It is basically saying what we
suspected is that the delphi stream being sent is using a different
encoder than what the Java side seems to want to use - according to the
Soap Envelope.
For example the ItWorks section below shows a snipet of a Soap Envelope
we have been able to use to make it work with PocketSoap. We basically
force just this packet to be sent. Notice the declaration of 'NS2' -
xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/". Now take a look
at the D6 Section and notice the declaration of the xds name space
xmlns:xsd="http://www.w3.org/1999/XMLSchema".
So (bare with my lack of knowledge here) it seems that Delphi is saying
that is using 'X' to encode something - and then the Java side is saying
that it can't find X in the name space it thinks it should be using.
Note that there is another call to a function to get a simple list before
the Base64 call in the dumpfile.
Also note that the two calls in the samples below are different - but are
attempting to do the same basic thing - send a base64 file across.
Bradley MacDonald
---------------------------------
Error Section
---------------------------------
<SOAP-ENV:Envelope xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>No Deserializer found to deserialize a
'http://www.w3.org/1999/XMLSchema:base64' using encoding style
'http://schemas.xmlsoap.org/soap/encoding/'.</faultstring>
<faultactor>/soap/servlet/rpcrouter</faultactor>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
---------------------------------
---------------------------------
It Works Section
---------------------------------
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:openFromData xmlns:ns1="urn:buzpakservice"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<buzpak-data xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:base64">
-----------BASE 64 ENCODED FILE HERE------
</buzpak-data>
</ns1:openFromData>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
---------------------------------
---------------------------------
D6 Section
---------------------------------
<?xml version="1.0" encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-
ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-
ENV:Body><NS1:requestActivation xmlns:NS1="urn:activationservice-service"
SOAP-
ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><NS1:userid
xsi:type="xsd:string">kent</NS1:userid><NS1:password
xsi:type="xsd:string">kentpw</NS1:password><NS1:buzPackName
xsi:type="xsd:string">aaabDecoded2.buz</NS1:buzPackName><NS1:buzPackData
xsi:type="xsd:base64">UEsDBBQAAgAIAEBt6ir7egNPYwMAAEcLAAALAAAAV2ViRGVzay5
YT
---------------------------------
Thanks for the reply! And the information.
Noah Kriegel sent me a new version of his Base64 Remotable class that
works GREAT!!!
This new class allows me to send and receive BASE 64 Binary files to/from
our Java server.
Bradley