/ / Bug no método de execução sobrecarregado do TDBXCallback que aceita e retorna um TObject - delphi, callback, datasnap

Bug no método de execução sobrecarregado de TDBXCallback que aceita e retorna um TObject - delphi, callback, datasnap

Há uma versão sobrecarregada da função Execute das chamadas TDBXCallback no Data.DBXJSon que se parece com isso

function Execute(Arg: TObject): TObject; overload; virtual; abstract;

Que no meu cliente Datasnap, eu implementei assim:

type
ServerChannelCallBack = class(TDBXCallback)
public
function Execute(const Arg: TJSONValue): TJSONValue; overload; override; // this works!
function Execute(Arg: TObject): TObject; overload; override; // this doesn"t
end;

function ServerChannelCallBack.Execute(Arg: TObject): TObject;
var
i: Integer;
begin
Result := TObject.Create; // is this correct?
try
if Arg is TStringList then
begin
FormClient.QueueLogMsg("ServerChannel", "Got TStringList");
for i := 0 to TStrings(Arg).Count - 1 do
FormClient.QueueLogMsg("ServerChannel", TStringList(Arg)[i]);
end;
finally
end;
end;

Isso é chamado no servidor Datasnap, assim:

procedure TFormServer.Button2Click(Sender: TObject);
var
sr: TStringList;
begin
sr := TStringList.Create;
try
sr.Add("one");
sr.Add("two");
ServerContainer2.DSServer1.BroadcastObject("SERVERCHANNEL", sr);
finally
// sr
end;
end;

Isso segue um exemplo no vídeo apresentado por Matt DeLong

Retornos de chamada pesados ​​com o DataSnap - Parte 1: Cliente Grosso

O retorno de chamada funciona perfeitamente, mas apenas exatamenteuma vez! Na segunda chamada do servidor (Button2Click), recebo um AV no cliente. Pode ser um erro no código DBX. Eu não sei. Não consigo rastrear lá. Ou talvez eu tenha inicializado o resultado do ServerChannelCallBack.Execute incorretamente. Qualquer assistência é apreciada.

ATUALIZAR

O retorno de chamada é registrado no cliente assim:

        TFormClient = class(TForm)
CMServerChannel: TDSClientCallbackChannelManager;
...
private
ServerChannelCBID: string;
...
procedure TFormClient.FormCreate(Sender: TObject);
begin
ServerChannelCBID := DateTimeToStr(now);
CMServerChannel.RegisterCallback(
ServerChannelCBID,
ServerChannelCallback.Create
);
...

Respostas:

2 para resposta № 1

Estou baseando esta resposta nos projetos DataSnap Server + Client, que podem ser baixados de dentro do Delphi Seattle usando `File | Open from version control"

https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE/Delphi/DataSnap/CallbackChannels

isso é mencionado aqui: http://edn.embarcadero.com/article/41374.

Os formulários no servidor e no cliente exigem uma leve correção para compilar, nome para adicionar JSon à lista de usos.

No formulário do servidor, adicionei o seguinte:

procedure TForm3.Button1Click(Sender: TObject);
var
sr: TStringList;
begin
Inc(CallbackCount);   // A form variable
sr := TStringList.Create;
try
sr.Add("Callback: " + IntToStr(CallbackCount));
sr.Add("two");
ServerContainer1.DSServer1.BroadcastObject("ChannelOne", sr);
finally
// No need for sr.free
end;
end;

(Estou usando o ChannelOne para obter consistência com o cliente)

e no cliente eu tenho:

function TCallbackClient.Execute(Arg: TObject): TObject;
var
i: Integer;
begin
//  Result := TObject.Create; // is this correct?
Result := TJSONTrue.Create;
try
if Arg is TStringList then
begin
QueueLogValue("Server: Got TStringList");
for i := 0 to TStrings(Arg).Count - 1 do
QueueLogValue("Server:" + TStringList(Arg)[i]);
end;
finally
end;
end;

Com essas variações do código que você mostrouno seu q, o servidor e o cliente funcionam bem, e posso clicar no botão do servidor quantas vezes quiser e nem o servidor nem nenhum dos clientes ficam "presos". Portanto, acho que seu problema deve ser específico para algo no código que você está usando, mas pelo menos o projeto vinculado fornece algo para trabalhar e comparar.

Btw, eu mudei o TCallbackClient.Execute retornar tipo para TJSONTrue.Create (igual à outra substituição) porque é isso quediz no manual do Delphi 2010 de Marco Cantu que ele deve retornar, reconhecidamente no contexto de um retorno de chamada "leve" enquanto um ServerMethod está executando: retornar TJSONFalse diz ao servidor para cancelar o ServerMethod em execução. No entanto, os retornos de chamada do servidor funcionam igualmente bem com o TObject.Create você costumava.