Исключение EUpdateError не распознается при возникновении в TDatasetProvider.OnUpdateError. Зачем? - PullRequest
0 голосов
/ 26 мая 2010

Когда я перебрасываю исключение EUpdateError в событии TDatasetProvider.OnUpdateError, оно не распознается как исключение EUpdateError в блоке перехвата. Он распознается только как базовый Excption.

try
  ...
  //calls the TDatasetPorvider.OnUpdateError event.
  myClientDataSet.ApplyUpdates(0);
  ...
except
 on ex: EUpdateError do
 begin
   //never goes here
   //Evaluate ex.ErrorCode
 end;
 on ex: Exception do
 begin
   //always goes here
   //the expression (ex is EUpdateError) returns false;
 end;
end;

Вот соответствующая .OnUpdateError реализация:

procedure MyDataModule.MyDatasetProviderOnUpdateError(..;E: EUpdateError;...);
beign
  //Here, the expression (E is EUpdateException) returns true;
  raise E;
end;

Исключение перебрасывается, но, как кажется, EUpdateError превращается в простое базовое исключение.
Кто-нибудь знает, почему тип класса теряется?
Мне понадобится этот тип, чтобы проверить .ErrorCode, чтобы узнать, что пошло не так, и подготовить соответствующее сообщение пользователя.

1 Ответ

1 голос
/ 26 мая 2010

К сожалению, исключения «старого стиля» сервера DataSnap направляются клиенту только в виде текста (E.Message), поэтому имя класса исключения и данные экземпляра теряются в процессе. См. SConnect единицу, TDataBlockInterpreter.InterpretData метод (исключая блок).

РЕДАКТИРОВАТЬ: Вот очень упрощенный пример, чтобы дать вам идею (не проверено вообще):

// new methods

function TDataBlockInterpreter.ReadException(const Data: IDataBlock): Exception;
var
  Flags: TVarFlags;
  AClassName, AMessage, AContext: string;
  ErrorCode, PreviousError: Integer;
  OriginalException: Exception;
begin
  AClassName := ReadVariant(Flags, Data);
  AMessage := ReadVariant(Flags, Data);
  if AClassName = 'EUpdateError' then
  begin
    AContext := ReadVariant(Flags, Data);
    ErrorCode := ReadVariant(Flags, Data);
    PreviousError := ReadVariant(Flags, Data);
    OriginalException := ReadException(Data);
    Result := EUpdateError.Create(AMessage, AContext, ErrorCode, PreviousError, OriginalException);
  end
  // else if AClassName = ... then ...
  else
    Result := Exception.Create(AMessage);
end;

procedure TDataBlockInterpreter.WriteException(E: Exception; const Data: IDataBlock);
begin
  WriteVariant(E.ClassName, Data);
  WriteVariant(E.Message, Data);
  if E is EUpdateError then
  begin
    WriteVariant(EUpdateError(E).Context, Data);
    WriteVariant(EUpdateError(E).ErrorCode, Data);
    WriteVariant(EUpdateError(E).PreviousError, Data);
    WriteException(EUpdateError(E).OriginalException, Data);
  end;
end;

// modified methods

procedure TDataBlockInterpreter.DoException(const Data: IDataBlock);
begin
  raise ReadException(Data);
end;

procedure TDataBlockInterpreter.InterpretData(const Data: IDataBlock);
var
  Action: Integer;
begin
  Action := Data.Signature;
  if (Action and asMask) = asError then DoException(Data);
  try
    case (Action and asMask) of
      asInvoke: DoInvoke(Data);
      asGetID: DoGetIDsOfNames(Data);
      asCreateObject: DoCreateObject(Data);
      asFreeObject: DoFreeObject(Data);
      asGetServers: DoGetServerList(Data);
      asGetAppServers: DoGetAppServerList(Data);
    else
      if not DoCustomAction(Action and asMask, Data) then
        raise EInterpreterError.CreateResFmt(@SInvalidAction, [Action and asMask]);
    end;
  except
    on E: Exception do
    begin
      Data.Clear;
      Data.Signature := ResultSig or asError;
      WriteException(E, Data);
      FSendDataBlock.Send(Data, False);
    end;
  end;
end;
...