I made a simple .NET WCF wsDualHttpBinding that does callback to client. Now I am trying to make a simple delphi console application that implements my wcf service. Here is the code that wsdl soap 1.2 generated for me in delphi
I think what I need to do this is something like this but can't get an understanding what Delphi expects for the OnMessageAdded
Listener := MessageService.GetIMessage(true);
Listener.Subscribe(MessageService.Subscribe.Create);
Listener.OnMessageAdded :=
Sender := MessageService.GetIMessage(true);
Sender.Subscribe(MessageService.Subscribe.Create);
Here is the WSDL http://pastebin.com/H4mJmjS4
Here is the generated code made by delphi xe2
// ************************************************************************ //
// The types declared in this file were generated from data read from the
// WSDL File described below:
// WSDL : http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/?wsdl
// >Import : http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/?wsdl>0
// >Import : http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/?xsd=xsd0
// >Import : http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/?xsd=xsd1
// Encoding : utf-8
// Codegen : [wfForceSOAP12+]
// Version : 1.0
// (06/15/2012 2:43:02 PM - - $Rev: 45757 $)
// ************************************************************************ //
unit MessageService;
interface
uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;
const
IS_OPTN = $0001;
IS_NLBL = $0004;
IS_REF = $0080;
type
// ************************************************************************ //
// The following types, referred to in the WSDL document are not being represented
// in this file. They are either aliases[@] of other types represented or were referred
// to but never[!] declared in the document. The types from the latter category
// typically map to predefined/known XML or Embarcadero types; however, they could also
// indicate incorrect WSDL documents that failed to declare or import a schema type.
// ************************************************************************ //
// !:string - "http://www.w3.org/2001/XMLSchema"[Gbl]
// !:dateTime - "http://www.w3.org/2001/XMLSchema"[Gbl]
// !:boolean - "http://www.w3.org/2001/XMLSchema"[Gbl]
Subscribe = class; { "http://tempuri.org/"[Lit][GblElm] }
AddMessageResponse = class; { "http://tempuri.org/"[Lit][GblElm] }
AddMessage = class; { "http://tempuri.org/"[Lit][GblElm] }
OnMessageAdded = class; { "http://tempuri.org/"[Lit][GblElm] }
UnsubscribeResponse = class; { "http://tempuri.org/"[Lit][GblElm] }
SubscribeResponse = class; { "http://tempuri.org/"[Lit][GblElm] }
Unsubscribe = class; { "http://tempuri.org/"[Lit][GblElm] }
// ************************************************************************ //
// XML : Subscribe, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
Subscribe = class(TRemotable)
private
public
constructor Create; override;
published
end;
// ************************************************************************ //
// XML : AddMessageResponse, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
AddMessageResponse = class(TRemotable)
private
public
constructor Create; override;
published
end;
// ************************************************************************ //
// XML : AddMessage, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
AddMessage = class(TRemotable)
private
Fmessage_: string;
Fmessage__Specified: boolean;
procedure Setmessage_(Index: Integer; const Astring: string);
function message__Specified(Index: Integer): boolean;
public
constructor Create; override;
published
property message_: string Index (IS_OPTN or IS_NLBL) read Fmessage_ write Setmessage_ stored message__Specified;
end;
// ************************************************************************ //
// XML : OnMessageAdded, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
OnMessageAdded = class(TRemotable)
private
Fmessage_: string;
Fmessage__Specified: boolean;
Ftimestamp: TXSDateTime;
Ftimestamp_Specified: boolean;
procedure Setmessage_(Index: Integer; const Astring: string);
function message__Specified(Index: Integer): boolean;
procedure Settimestamp(Index: Integer; const ATXSDateTime: TXSDateTime);
function timestamp_Specified(Index: Integer): boolean;
public
constructor Create; override;
destructor Destroy; override;
published
property message_: string Index (IS_OPTN or IS_NLBL) read Fmessage_ write Setmessage_ stored message__Specified;
property timestamp: TXSDateTime Index (IS_OPTN) read Ftimestamp write Settimestamp stored timestamp_Specified;
end;
// ************************************************************************ //
// XML : UnsubscribeResponse, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
UnsubscribeResponse = class(TRemotable)
private
FUnsubscribeResult: Boolean;
FUnsubscribeResult_Specified: boolean;
procedure SetUnsubscribeResult(Index: Integer; const ABoolean: Boolean);
function UnsubscribeResult_Specified(Index: Integer): boolean;
public
constructor Create; override;
published
property UnsubscribeResult: Boolean Index (IS_OPTN) read FUnsubscribeResult write SetUnsubscribeResult stored UnsubscribeResult_Specified;
end;
// ************************************************************************ //
// XML : SubscribeResponse, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
SubscribeResponse = class(TRemotable)
private
FSubscribeResult: Boolean;
FSubscribeResult_Specified: boolean;
procedure SetSubscribeResult(Index: Integer; const ABoolean: Boolean);
function SubscribeResult_Specified(Index: Integer): boolean;
public
constructor Create; override;
published
property SubscribeResult: Boolean Index (IS_OPTN) read FSubscribeResult write SetSubscribeResult stored SubscribeResult_Specified;
end;
// ************************************************************************ //
// XML : Unsubscribe, global, <element>
// Namespace : http://tempuri.org/
// Serializtn: [xoLiteralParam]
// Info : Wrapper
// ************************************************************************ //
Unsubscribe = class(TRemotable)
private
public
constructor Create; override;
published
end;
// ************************************************************************ //
// Namespace : http://tempuri.org/
// soapAction: http://tempuri.org/IMessage/%operationName%
// transport : http://schemas.xmlsoap.org/soap/http
// style : document
// use : literal
// binding : WSDualHttpBinding_IMessage
// service : MessageService
// port : WSDualHttpBinding_IMessage
// URL : http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/
// ************************************************************************ //
IMessage = interface(IInvokable)
['{8AE9E38B-51D7-6EB7-5470-5B197F54CF0A}']
function AddMessage(const parameters: AddMessage): AddMessageResponse; stdcall;
function Subscribe(const parameters: Subscribe): SubscribeResponse; stdcall;
function Unsubscribe(const parameters: Unsubscribe): UnsubscribeResponse; stdcall;
// Cannot unwrap:
// - More than one strictly out element was found
function OnMessageAdded: OnMessageAdded; stdcall;
end;
function GetIMessage(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): IMessage;
implementation
uses SysUtils;
function GetIMessage(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): IMessage;
const
defWSDL = 'http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/?wsdl';
defURL = 'http://localhost:8700/Design_Time_Addresses/WCFCallbacks/Message/';
defSvc = 'MessageService';
defPrt = 'WSDualHttpBinding_IMessage';
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 IMessage);
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;
constructor Subscribe.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
constructor AddMessageResponse.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
constructor AddMessage.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
procedure AddMessage.Setmessage_(Index: Integer; const Astring: string);
begin
Fmessage_ := Astring;
Fmessage__Specified := True;
end;
function AddMessage.message__Specified(Index: Integer): boolean;
begin
Result := Fmessage__Specified;
end;
constructor OnMessageAdded.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
destructor OnMessageAdded.Destroy;
begin
SysUtils.FreeAndNil(Ftimestamp);
inherited Destroy;
end;
procedure OnMessageAdded.Setmessage_(Index: Integer; const Astring: string);
begin
Fmessage_ := Astring;
Fmessage__Specified := True;
end;
function OnMessageAdded.message__Specified(Index: Integer): boolean;
begin
Result := Fmessage__Specified;
end;
procedure OnMessageAdded.Settimestamp(Index: Integer; const ATXSDateTime: TXSDateTime);
begin
Ftimestamp := ATXSDateTime;
Ftimestamp_Specified := True;
end;
function OnMessageAdded.timestamp_Specified(Index: Integer): boolean;
begin
Result := Ftimestamp_Specified;
end;
constructor UnsubscribeResponse.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
procedure UnsubscribeResponse.SetUnsubscribeResult(Index: Integer; const ABoolean: Boolean);
begin
FUnsubscribeResult := ABoolean;
FUnsubscribeResult_Specified := True;
end;
function UnsubscribeResponse.UnsubscribeResult_Specified(Index: Integer): boolean;
begin
Result := FUnsubscribeResult_Specified;
end;
constructor SubscribeResponse.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
procedure SubscribeResponse.SetSubscribeResult(Index: Integer; const ABoolean: Boolean);
begin
FSubscribeResult := ABoolean;
FSubscribeResult_Specified := True;
end;
function SubscribeResponse.SubscribeResult_Specified(Index: Integer): boolean;
begin
Result := FSubscribeResult_Specified;
end;
constructor Unsubscribe.Create;
begin
inherited Create;
FSerializationOptions := [xoLiteralParam];
end;
initialization
{ IMessage }
InvRegistry.RegisterInterface(TypeInfo(IMessage), 'http://tempuri.org/', 'utf-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IMessage), 'http://tempuri.org/IMessage/%operationName%');
InvRegistry.RegisterInvokeOptions(TypeInfo(IMessage), ioDocument);
InvRegistry.RegisterInvokeOptions(TypeInfo(IMessage), ioLiteral);
InvRegistry.RegisterInvokeOptions(TypeInfo(IMessage), ioSOAP12);
RemClassRegistry.RegisterXSClass(Subscribe, 'http://tempuri.org/', 'Subscribe');
RemClassRegistry.RegisterSerializeOptions(Subscribe, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(AddMessageResponse, 'http://tempuri.org/', 'AddMessageResponse');
RemClassRegistry.RegisterSerializeOptions(AddMessageResponse, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(AddMessage, 'http://tempuri.org/', 'AddMessage');
RemClassRegistry.RegisterExternalPropName(TypeInfo(AddMessage), 'message_', '[ExtName="message"]');
RemClassRegistry.RegisterSerializeOptions(AddMessage, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(OnMessageAdded, 'http://tempuri.org/', 'OnMessageAdded');
RemClassRegistry.RegisterExternalPropName(TypeInfo(OnMessageAdded), 'message_', '[ExtName="message"]');
RemClassRegistry.RegisterSerializeOptions(OnMessageAdded, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(UnsubscribeResponse, 'http://tempuri.org/', 'UnsubscribeResponse');
RemClassRegistry.RegisterSerializeOptions(UnsubscribeResponse, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(SubscribeResponse, 'http://tempuri.org/', 'SubscribeResponse');
RemClassRegistry.RegisterSerializeOptions(SubscribeResponse, [xoLiteralParam]);
RemClassRegistry.RegisterXSClass(Unsubscribe, 'http://tempuri.org/', 'Unsubscribe');
RemClassRegistry.RegisterSerializeOptions(Unsubscribe, [xoLiteralParam]);
end.
With wsDualHttpBinding, the WCF side wants to send the response asynchronously to the client as a HTTP request.
So actually your Delphi application needs to supply a HTTP server too which accepts the WCF request.
Async operation support is not included in Delphis SOAP client implementation - adding a Delphi SOAP server which provides only the matching method(s) for the callback operations would be a workaround.