在TDatasetProvider.OnUpdateError中引发时无法识别EUpdateError异常。为什么?

时间:2010-05-26 10:07:42

标签: delphi delphi-2009

当我在EUpdateError事件中重新抛出TDatasetProvider.OnUpdateError异常时,它在catch块中不会被识别为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;

Hiere是相应的.OnUpdateError实现:

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

异常被重新抛出,但似乎EUpdateError被转换为普通的基本Execption。
有谁知道,为什么班级类型迷路了?
我需要这种类型才能检查.ErrorCode以了解出了什么问题并准备好正确的用户信息。

1 个答案:

答案 0 :(得分:1)

不幸的是,“旧式”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;