Initial commit - Delphi MES client project
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
unit uExceptionHandler;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes, System.JSON, System.Threading, FMX.Forms;
|
||||
|
||||
type
|
||||
EBaseException = class(Exception)
|
||||
private
|
||||
FErrorCode: Integer;
|
||||
FErrorType: string;
|
||||
FCause: string;
|
||||
FContext: TStrings;
|
||||
FTimestamp: TDateTime;
|
||||
public
|
||||
constructor Create(const AMessage: string; AErrorCode: Integer = 0; AErrorType: string = ''); overload;
|
||||
constructor Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer = 0; AErrorType: string = ''); overload;
|
||||
destructor Destroy; override;
|
||||
function ToJSON: TJSONObject;
|
||||
function ToDetailString: string;
|
||||
property ErrorCode: Integer read FErrorCode write FErrorCode;
|
||||
property ErrorType: string read FErrorType write FErrorType;
|
||||
property Cause: string read FCause write FCause;
|
||||
property Context: TStrings read FContext;
|
||||
property Timestamp: TDateTime read FTimestamp;
|
||||
end;
|
||||
|
||||
ENetworkException = class(EBaseException)
|
||||
public
|
||||
constructor Create(const AMessage: string; AErrorCode: Integer = 0); overload;
|
||||
constructor Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer = 0); overload;
|
||||
end;
|
||||
|
||||
EDataException = class(EBaseException)
|
||||
public
|
||||
constructor Create(const AMessage: string; AErrorCode: Integer = 0); overload;
|
||||
constructor Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer = 0); overload;
|
||||
end;
|
||||
|
||||
EBusinessException = class(EBaseException)
|
||||
public
|
||||
constructor Create(const AMessage: string; AErrorCode: Integer = 0); overload;
|
||||
constructor Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer = 0); overload;
|
||||
end;
|
||||
|
||||
EDeviceException = class(EBaseException)
|
||||
public
|
||||
constructor Create(const AMessage: string; AErrorCode: Integer = 0); overload;
|
||||
constructor Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer = 0); overload;
|
||||
end;
|
||||
|
||||
EValidationException = class(EBaseException)
|
||||
private
|
||||
FFieldName: string;
|
||||
FFieldValue: string;
|
||||
public
|
||||
constructor Create(const AFieldName, AFieldValue, AMessage: string);
|
||||
property FieldName: string read FFieldName write FFieldName;
|
||||
property FieldValue: string read FFieldValue write FFieldValue;
|
||||
end;
|
||||
|
||||
TExceptionHandler = class
|
||||
private
|
||||
class var
|
||||
FInstance: TExceptionHandler;
|
||||
var
|
||||
FOnException: TProc<Exception, TObject>;
|
||||
FLogEnabled: Boolean;
|
||||
FShowDialogEnabled: Boolean;
|
||||
FErrorPrefix: string;
|
||||
class function GetInstance: TExceptionHandler; static;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure HandleException(E: Exception; Context: TObject = nil);
|
||||
procedure HandleAndRethrow(E: Exception; const AdditionalInfo: string = '');
|
||||
function SafeCall<T>(Func: TFunc<T>; const DefaultValue: T; const ErrorMsg: string = ''): T; overload;
|
||||
procedure SafeCall(Func: TProc; const ErrorMsg: string = ''); overload;
|
||||
property OnException: TProc<Exception, TObject> read FOnException write FOnException;
|
||||
property LogEnabled: Boolean read FLogEnabled write FLogEnabled;
|
||||
property ShowDialogEnabled: Boolean read FShowDialogEnabled write FShowDialogEnabled;
|
||||
property ErrorPrefix: string read FErrorPrefix write FErrorPrefix;
|
||||
class property Instance: TExceptionHandler read GetInstance;
|
||||
class procedure SetAsDefaultInstance;
|
||||
class procedure LogException(E: Exception; const Context: string = '');
|
||||
class function GetExceptionDetail(E: Exception): string;
|
||||
end;
|
||||
|
||||
procedure RaiseNetworkException(const AMsg: string; AErrorCode: Integer = 0);
|
||||
procedure RaiseDataException(const AMsg: string; AErrorCode: Integer = 0);
|
||||
procedure RaiseBusinessException(const AMsg: string; AErrorCode: Integer = 0);
|
||||
procedure RaiseDeviceException(const AMsg: string; AErrorCode: Integer = 0);
|
||||
procedure RaiseValidationException(const AFieldName, AFieldValue, AMsg: string);
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
uSafeLog;
|
||||
|
||||
{ EBaseException }
|
||||
|
||||
constructor EBaseException.Create(const AMessage: string; AErrorCode: Integer; AErrorType: string);
|
||||
begin
|
||||
inherited Create(AMessage);
|
||||
FErrorCode := AErrorCode;
|
||||
FErrorType := AErrorType;
|
||||
FCause := '';
|
||||
FContext := TStringList.Create;
|
||||
FTimestamp := Now;
|
||||
end;
|
||||
|
||||
constructor EBaseException.Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer; AErrorType: string);
|
||||
begin
|
||||
Create(Format(AMessage, AArgs), AErrorCode, AErrorType);
|
||||
end;
|
||||
|
||||
destructor EBaseException.Destroy;
|
||||
begin
|
||||
FContext.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function EBaseException.ToJSON: TJSONObject;
|
||||
begin
|
||||
Result := TJSONObject.Create;
|
||||
Result.AddPair('message', Message);
|
||||
Result.AddPair('errorCode', TJSONNumber.Create(FErrorCode));
|
||||
Result.AddPair('errorType', FErrorType);
|
||||
Result.AddPair('cause', FCause);
|
||||
Result.AddPair('timestamp', FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', FTimestamp));
|
||||
end;
|
||||
|
||||
function EBaseException.ToDetailString: string;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := Format('[%s] %s (Code: %d, Type: %s)',
|
||||
[FormatDateTime('yyyy-mm-dd hh:nn:ss', FTimestamp), Message, FErrorCode, FErrorType]);
|
||||
if FCause <> '' then
|
||||
Result := Result + sLineBreak + 'Cause: ' + FCause;
|
||||
if FContext.Count > 0 then
|
||||
begin
|
||||
Result := Result + sLineBreak + 'Context:';
|
||||
for I := 0 to FContext.Count - 1 do
|
||||
Result := Result + sLineBreak + ' ' + FContext.Names[I] + ' = ' + FContext.ValueFromIndex[I];
|
||||
end;
|
||||
end;
|
||||
|
||||
{ ENetworkException }
|
||||
|
||||
constructor ENetworkException.Create(const AMessage: string; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(AMessage, AErrorCode, 'Network');
|
||||
end;
|
||||
|
||||
constructor ENetworkException.Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(Format(AMessage, AArgs), AErrorCode, 'Network');
|
||||
end;
|
||||
|
||||
{ EDataException }
|
||||
|
||||
constructor EDataException.Create(const AMessage: string; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(AMessage, AErrorCode, 'Data');
|
||||
end;
|
||||
|
||||
constructor EDataException.Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(Format(AMessage, AArgs), AErrorCode, 'Data');
|
||||
end;
|
||||
|
||||
{ EBusinessException }
|
||||
|
||||
constructor EBusinessException.Create(const AMessage: string; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(AMessage, AErrorCode, 'Business');
|
||||
end;
|
||||
|
||||
constructor EBusinessException.Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(Format(AMessage, AArgs), AErrorCode, 'Business');
|
||||
end;
|
||||
|
||||
{ EDeviceException }
|
||||
|
||||
constructor EDeviceException.Create(const AMessage: string; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(AMessage, AErrorCode, 'Device');
|
||||
end;
|
||||
|
||||
constructor EDeviceException.Create(const AMessage: string; const AArgs: array of const; AErrorCode: Integer);
|
||||
begin
|
||||
inherited Create(Format(AMessage, AArgs), AErrorCode, 'Device');
|
||||
end;
|
||||
|
||||
{ EValidationException }
|
||||
|
||||
constructor EValidationException.Create(const AFieldName, AFieldValue, AMessage: string);
|
||||
begin
|
||||
inherited Create(AMessage, -1, 'Validation');
|
||||
FFieldName := AFieldName;
|
||||
FFieldValue := AFieldValue;
|
||||
end;
|
||||
|
||||
{ TExceptionHandler }
|
||||
|
||||
constructor TExceptionHandler.Create;
|
||||
begin
|
||||
inherited;
|
||||
FLogEnabled := True;
|
||||
FShowDialogEnabled := True;
|
||||
FErrorPrefix := '[Error]';
|
||||
end;
|
||||
|
||||
destructor TExceptionHandler.Destroy;
|
||||
begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
class function TExceptionHandler.GetInstance: TExceptionHandler;
|
||||
begin
|
||||
if FInstance = nil then
|
||||
FInstance := TExceptionHandler.Create;
|
||||
Result := FInstance;
|
||||
end;
|
||||
|
||||
procedure TExceptionHandler.HandleException(E: Exception; Context: TObject);
|
||||
begin
|
||||
if FLogEnabled then
|
||||
LogException(E);
|
||||
|
||||
if FShowDialogEnabled and Assigned(FOnException) then
|
||||
FOnException(E, Context);
|
||||
end;
|
||||
|
||||
procedure TExceptionHandler.HandleAndRethrow(E: Exception; const AdditionalInfo: string);
|
||||
var
|
||||
Ex: EBaseException;
|
||||
begin
|
||||
if E is EBaseException then
|
||||
begin
|
||||
Ex := E as EBaseException;
|
||||
if AdditionalInfo <> '' then
|
||||
Ex.Cause := AdditionalInfo;
|
||||
raise Ex;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Ex := EBusinessException.Create(E.Message);
|
||||
if AdditionalInfo <> '' then
|
||||
Ex.Cause := AdditionalInfo;
|
||||
raise Ex;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExceptionHandler.SafeCall<T>(Func: TFunc<T>; const DefaultValue: T; const ErrorMsg: string): T;
|
||||
begin
|
||||
try
|
||||
Result := Func;
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
if ErrorMsg <> '' then
|
||||
LogException(E, ErrorMsg)
|
||||
else
|
||||
LogException(E);
|
||||
Result := DefaultValue;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TExceptionHandler.SafeCall(Func: TProc; const ErrorMsg: string);
|
||||
begin
|
||||
try
|
||||
Func;
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
if ErrorMsg <> '' then
|
||||
LogException(E, ErrorMsg)
|
||||
else
|
||||
LogException(E);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
class procedure TExceptionHandler.SetAsDefaultInstance;
|
||||
begin
|
||||
if FInstance = nil then
|
||||
FInstance := TExceptionHandler.Create;
|
||||
end;
|
||||
|
||||
class procedure TExceptionHandler.LogException(E: Exception; const Context: string);
|
||||
begin
|
||||
if not Assigned(FInstance) then
|
||||
Exit;
|
||||
|
||||
try
|
||||
if Context <> '' then
|
||||
WorkLog.Error('[Context: %s] %s: %s', [Context, E.ClassName, E.Message])
|
||||
else
|
||||
WorkLog.Error('%s: %s', [E.ClassName, E.Message]);
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TExceptionHandler.GetExceptionDetail(E: Exception): string;
|
||||
begin
|
||||
if E is EBaseException then
|
||||
Result := (E as EBaseException).ToDetailString
|
||||
else
|
||||
Result := Format('[%s] %s', [E.ClassName, E.Message]);
|
||||
end;
|
||||
|
||||
procedure RaiseNetworkException(const AMsg: string; AErrorCode: Integer);
|
||||
begin
|
||||
raise ENetworkException.Create(AMsg, AErrorCode);
|
||||
end;
|
||||
|
||||
procedure RaiseDataException(const AMsg: string; AErrorCode: Integer);
|
||||
begin
|
||||
raise EDataException.Create(AMsg, AErrorCode);
|
||||
end;
|
||||
|
||||
procedure RaiseBusinessException(const AMsg: string; AErrorCode: Integer);
|
||||
begin
|
||||
raise EBusinessException.Create(AMsg, AErrorCode);
|
||||
end;
|
||||
|
||||
procedure RaiseDeviceException(const AMsg: string; AErrorCode: Integer);
|
||||
begin
|
||||
raise EDeviceException.Create(AMsg, AErrorCode);
|
||||
end;
|
||||
|
||||
procedure RaiseValidationException(const AFieldName, AFieldValue, AMsg: string);
|
||||
begin
|
||||
raise EValidationException.Create(AFieldName, AFieldValue, AMsg);
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user