I know, there's the Attachments demo in the source tree of D2005. But
note, that there an attachment is received, not sent.
I read on the net that using RIO.Converter.Attachments.Add(...) does not
help alone, since the Attachments are cleared.
Does anyone have a working way to upload one attachment to a web service?
If not, what is the alternative to have a Delphi application send
attachments to a web service? Code the MIME-part manually? Feed an
external application that is capable of sending SOAP attachments? (who'll
write that for me in not-Delphi?)
No! ... No?
Stefan
{ Invokable implementation File for TWebService42 which implements
IWebService42 }
unit WebService42Impl;
interface
uses SysUtils,InvokeRegistry, Types, XSBuiltIns, WebService42Intf;
type
{ TWebService42 }
TWebService42 = class(TInvokableClass, IWebService42)
public
Function UploadFile(afilename:string; afile:TSoapAttachment):Boolean;
stdcall;
Function DownloadFile(afilename:string):TSoapAttachment; stdcall;
end;
implementation
Function TWebService42.UploadFile(afilename:string;
afile:TSoapAttachment):Boolean;
var ffilename:string;
const pathdir = 'the path of the file on the server';
begin
result:=false;
ffilename:=pathdir+afilename;
try
if not directoryexists(pathdir) then
ForceDirectories(pathdir);
except
raise Exception.Create('Unable to create repository directory on the
server.');
end;
try
if not fileexists(ffilename) then
begin
afile.SaveToFile(ffilename);
result:=true;
end;
except
result:=false;
end;
end;
_______________________________________________________________________________________________________
On the client side I used this unit:
{ Invokable interface IWebService42 }
unit WebService42Intf;
interface
uses InvokeRegistry, Types, XSBuiltIns,Rio,SOAPHTTPClient;
type
{ Invokable interfaces must derive from IInvokable }
IWebService42 = interface(IInvokable)
['{3A420A27-7E3A-481A-906E-3CB7C67CBD53}']
Function UploadFile(afilename:string; afile:TSoapAttachment):Boolean;
stdcall;
Function DownloadFile(afilename:string):TSoapAttachment; stdcall;
{ Methods of Invokable interface must not use the default }
{ calling convention; stdcall is recommended }
end;
function GetIDBAttachments(UseWSDL: Boolean=System.False; Addr: string='';
HTTPRIO: THTTPRIO = nil): IWebService42;
implementation
function GetIDBAttachments(UseWSDL: Boolean; Addr: string; HTTPRIO:
THTTPRIO): IWebService42;
const
defWSDL = 'http://host/cgi-bin/WebService42.exe/wsdl/IWebService42';
defURL = 'http://localhost/scripts/WebService42.exe/soap/IWebService42';
defSvc = 'IWebService42service';
defPrt = 'IWebService42Port';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as IWebService42);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(IWebService42));
end.
And in an another form I used a button for upload:
____________________________________________________________________________________________________________________________
unit UGestFile;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,WebService42Intf,
Dialogs, InvokeRegistry, Rio, SOAPHTTPClient, StdCtrls, Buttons,
ExtCtrls,DB;
type
TGestFileForm = class(TForm)
FileLabel: TLabel;
Image1: TImage;
FileEdit: TEdit;
btnUpload: TButton;
btndownload: TButton;
Button1: TButton;
Button4: TButton;
OpenDialog1: TOpenDialog;
SaveDialog1: TSaveDialog;
btnLoadUn: TButton;
procedure btnUploadClick(Sender: TObject);
procedure btnLoadUnClick(Sender: TObject);
procedure btndownloadClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
FAttachService : IWebservice42;
procedure LoadPicture(Picture: TSoapAttachment; extens:string);
public
{ Public declarations }
function GetAttachService: IWebservice42;
end;
var
GestFileForm: TGestFileForm;
implementation
{$R *.dfm}
uses
SoapDataForm,ISampleDataModule1;
function TGestFileForm.GetAttachService: IWebservice42;
begin
if FAttachService = nil then
begin
FAttachService := GetIDBAttachments(False,
'http://host/cgi-bin/Webservice42.exe/soap/IWebservice42');
// (FAttachService as IRIOAccess).RIO.OnBeforeExecute :=
HTTPRIO1BeforeExecute;
// (FAttachService as IRIOAccess).RIO.OnAfterExecute :=
HTTPRIO1AfterExecute;
end;
Result := FAttachService;
end;
procedure TGestFileForm.btnUploadClick(Sender: TObject);
var
path:string;
FileData:TSoapAttachment;
begin
if OpenDialog1.Execute then
begin
FileData:=nil;
//path:=OpenDialog1.FileName;
fileedit.Text:=ExtractFileName(OpenDialog1.FileName);
try
FileData := tsoapattachment.Create;
FileData.SetSourceFile(OpenDialog1.FileName);
GetAttachService.UploadFile(ExtractFileName(OpenDialog1.FileName),
FileData);
Image1.Picture.LoadFromFile(OpenDialog1.FileName);
except
on E: Exception do
begin
if Assigned(FileData) then FileData.Free;
FileData := Nil;
showmessage('Errore');
end; //begin
end;//try
end;
end;
I hope I help you.
Bye
"Stefan M. Huber" <loos...@gmx.net> ha scritto nel messaggio
news:op.s03yo...@ws-4.ginalan.at...
> Hi,
> I used a Demo in the source tree of Delphi7 for writing an upload code.
> On the server side I used an invokable interface like this:
<snip>
> type
>
> { TWebService42 }
> TWebService42 = class(TInvokableClass, IWebService42)
> public
> Function UploadFile(afilename:string; afile:TSoapAttachment):Boolean;
Servus Anna!
Thanks for that piece of code, but the problem is that I cannot influence
the server, as it comes from a big Austrian authority (eCard system)...
All they gave us is the sentence "you can also attach a zip archive to the
SOAP request". There's no interface defined to hand over a TSOAPAttachment
as your UploadFile . It seems to me that all this shall be handled
similarly to eMail messages. Some kind of <attachment> element after the
SOAP body that is separated from the content of the body and not part of
the SOAP request.
I fear, I have to read deeply into the specification and insert the SOAP
attachment myself in such a code block.
I am currently doing similar things in the OnBeforeExecute and
OnAfterExecute, since they decided to switch from explicit arrays in the
WSDL files to implicit arrays (<elem ... maxoccurs="unbounded"> which the
Delphi WSDL importer can't handle. So I manually change the WSDL files to
use explicit arrays and use so called TWurschtler ("mangler") classes to
rearrange the received/sent XML to meet the needs of the other side.
It simply sucks. But it works. If anyone's interested in that code,
contact me (the chance to catch me by mail is higher)
Stefan
On Thu, 01 Dec 2005 18:48:38 +0100, Anna Di Tizio
<anna.d...@metasistemi.it> wrote:
> On the client side I used this unit:
> { Invokable interfaces must derive from IInvokable }
> IWebService42 = interface(IInvokable)
> ['{3A420A27-7E3A-481A-906E-3CB7C67CBD53}']
Did you create this interface manually or with some sort of importer? Do
you have a WSDL file for that?
The reason I am asking: I tried the Echo example in the demo sources and
found that Delphi actually uses an element to reference the MIME multipart
attachment explicitly in the SOAP body.
This is not what *they* (those who implement the service) want. They need
a simple MIME attachment. No links.
So I decided that I might modify the interface from
function sendenAnfrage(params: SendenAnfrage);
sendenAnfrageResponse; stdcall;
to this one
function sendenAnfrage(params: SendenAnfrage; attach: TSOAPAttachment);
sendenAnfrageResponse; stdcall;
and if it is necessary because the server does not accept the wrong SOAP
body (the one with the reference to the attachment) I hook myself into the
OnBeforeExecute event and remove the reference manually (which I already
do for implizit arrays).
The problem is, that I have no idea, how such an IInvokable actually works
behind the curtain. What do I have to do, if I manually want to change the
signature of the interface functions like mentioned above?
Stefan
> The problem is, that I have no idea, how such an IInvokable actually
> works behind the curtain. What do I have to do, if I manually want to
> change the signature of the interface functions like mentioned above?
I should add that I forgot to call the GetIAttachmentTestService function.
Anyway...I copied the definition of a simple service over to a new unit
and extended the definition of the function by TSOAPAttachment. The
generated SOAP request that is sent does not show a sign of this
modification.
A related question: Do I have a chance to access the HTTP POST stream at
some point? If nothing else helps, I'll have to apply the lever there.
Stefan