This commit is contained in:
Pedro 2019-03-18 10:08:43 -03:00
commit 0a49f8e539
9 changed files with 276 additions and 89 deletions

View File

@ -9,9 +9,10 @@ object dmMain: TdmMain
'B'
'User_Name=sysdba'
'Password=masterkey'
'Protocol=TCPIP'
'Server=localhost'
'DriverID=FB')
ConnectedStoredUsage = []
Connected = True
LoginPrompt = False
BeforeConnect = ConnectionBeforeConnect
Left = 64

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{300F83FF-8F7B-43FD-B740-A3DFDF7238ED}</ProjectGuid>
<ProjectVersion>18.5</ProjectVersion>
<ProjectVersion>18.6</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>jsonrpcclientwithobjects.dpr</MainSource>
<Base>True</Base>

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{AF5FBC36-0D1D-4C07-B2E3-C2A2E688AC6F}</ProjectGuid>
<ProjectVersion>18.5</ProjectVersion>
<ProjectVersion>18.6</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>jsonrpcserverwithobjects.dpr</MainSource>
<Base>True</Base>

View File

@ -105,7 +105,7 @@ type
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers/($id).html')]
[MVCProduces('text/html')]
procedure GetPerson_AsHTML(CTX: TWebContext);
procedure GetPerson_AsHTML;
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers.csv')]
@ -114,7 +114,7 @@ type
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers/unicode/($id).html')]
[MVCProduces('text/html', 'UTF-8')]
procedure GetUnicodeText_AsHTML(CTX: TWebContext);
procedure GetUnicodeText_AsHTML;
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers/($id)')]
@ -133,7 +133,16 @@ type
[MVCHTTPMethod([httpGET])]
[MVCPath('/images/customers/($id)')]
procedure GetPersonPhotoAsStream(CTX: TWebContext);
procedure GetPersonPhotoAsStream;
[MVCHTTPMethod([httpPOST])]
[MVCConsumes(TMVCMediaType.MULTIPART_FORM_DATA)]
[MVCPath('/files')]
procedure UploadBinaryData;
[MVCHTTPMethod([httpGET])]
[MVCPath('/files/($filename)')]
procedure GetBinaryData(const filename: string);
[MVCHTTPMethod([httpGET])]
[MVCPath('/exception')]
@ -153,7 +162,9 @@ uses
MVCFramework.DataSet.Utils,
MVCFramework.Serializer.Commons,
MVCFramework.Serializer.Defaults,
MVCFramework.Logger,
MyDataModuleU,
System.IOUtils,
System.Classes,
System.SysUtils,
WebModuleU,
@ -161,11 +172,12 @@ uses
InMemoryDataU,
JsonDataObjects,
MVCFramework.Serializer.JsonDataObjects,
Data.DB;
Data.DB,
Web.HTTPApp;
{ TRoutingSampleController }
procedure TRenderSampleController.GetUnicodeText_AsHTML(CTX: TWebContext);
procedure TRenderSampleController.GetUnicodeText_AsHTML;
var
s: string;
begin
@ -192,6 +204,76 @@ begin
Render(IntToStr(10 div a));
end;
procedure TRenderSampleController.UploadBinaryData;
var
lFile: TAbstractWebRequestFile;
lFileExt: string;
lOutputFileName: string;
lOutputFullPath: string;
lOutFile: TFileStream;
lOutputFolder: string;
begin
if Context.Request.Files.Count <> 1 then
begin
raise EMVCException.Create(HTTP_STATUS.BadRequest, 'Expected exactly 1 file');
end;
lFile := Context.Request.Files[0];
LogI(Format('Upload: [FieldName: %s] [FileName: %s] [ContentType: %s] [Size: %d bytes]',
[lFile.FieldName, lFile.filename, lFile.ContentType, lFile.Stream.Size]));
{ Be sure that our data directory always exists. We could also do it in the server startup. }
lOutputFolder := TPath.Combine(AppPath, 'uploadedfiles');
if not TDirectory.Exists(lOutputFolder) then
begin
TDirectory.CreateDirectory(lOutputFolder);
end;
lFileExt := TPath.GetExtension(lFile.filename);
{
Here we could check for allowed extensions or check the file contents looking for
accepted file headers (e.g. Zip, PNG, BMP, TIFF etc).
In this case we just use the extension of the filename sent by the client.
}
{ Find a valid random filename to store the stream on disk. }
repeat
lOutputFileName := TPath.ChangeExtension(TPath.GetRandomFileName, lFileExt);
lOutputFullPath := TPath.Combine(lOutputFolder, lOutputFileName);
until not TFile.Exists(lOutputFullPath);
lOutFile := TFileStream.Create(lOutputFullPath, fmCreate);
try
lOutFile.CopyFrom(lFile.Stream, 0);
finally
lOutFile.Free;
end;
{ Inform the client about the name assigned to the file
on disk and how to retrieve it. }
Context.Response.ContentType := TMVCMediaType.APPLICATION_JSON;
Context.Response.StatusCode := HTTP_STATUS.OK;
Render(Dict(['filename', 'ref'], [lOutputFileName, '/files/' + lOutputFileName]));
end;
procedure TRenderSampleController.GetBinaryData(const filename: string);
var
lFilesFolder: string;
lFullFilePath: string;
begin
lFilesFolder := TPath.Combine(AppPath, 'uploadedfiles');
lFullFilePath := TPath.Combine(lFilesFolder, filename);
if not TFile.Exists(lFullFilePath) then
begin
raise EMVCException.Create('File not found');
end;
Context.Response.ContentType := TMVCMediaType.APPLICATION_OCTET_STREAM;
Context.Response.StatusCode := HTTP_STATUS.OK;
Context.Response.CustomHeaders.Values['Content-Disposition'] := 'attachment; filename=' +
filename + ';';
Render(TFileStream.Create(lFullFilePath, fmOpenRead or fmShareDenyNone));
end;
procedure TRenderSampleController.GetCustomerByID_AsTObject(const id: Integer);
var
Cust: TCustomer;
@ -302,7 +384,7 @@ begin
Render<TPerson>(GetPeopleList, False);
end;
procedure TRenderSampleController.GetPerson_AsHTML(CTX: TWebContext);
procedure TRenderSampleController.GetPerson_AsHTML;
begin
ResponseStream.Append('<html><body><ul>').Append('<li>FirstName: Daniele</li>')
.Append('<li>LastName: Teti')
@ -537,7 +619,7 @@ begin
SendFile('..\..\_\customer.png');
end;
procedure TRenderSampleController.GetPersonPhotoAsStream(CTX: TWebContext);
procedure TRenderSampleController.GetPersonPhotoAsStream;
var
LPhoto: TFileStream;
begin

View File

@ -315,31 +315,31 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\RenderSampleControllerU\default.txaPackage" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders1\default.txvpck" Configuration="Debug" Class="ProjectFile">
<Platform Name="Linux64">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txaPackage" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Debug" Class="ProjectFile">
<Platform Name="Linux64">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\RenderSampleControllerU\default.txaPackage" Configuration="Release" Class="ProjectFile">
<DeployFile LocalName="ModelSupport_renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
@ -357,7 +357,7 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<DeployFile LocalName="ModelSupport_renders\renders\default.txaPackage" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>

View File

@ -725,7 +725,7 @@ var
begin
lQry := TFDQuery.Create(nil);
try
lQry.FetchOptions.Unidirectional := True;
lQry.FetchOptions.Unidirectional := False; //True;
if Connection = nil then
begin
lQry.Connection := ActiveRecordConnectionsRegistry.GetCurrent;

View File

@ -43,16 +43,17 @@ uses
{$I dmvcframeworkbuildconsts.inc}
type
TMVCHTTPMethodType = (httpGET, httpPOST, httpPUT, httpDELETE, httpHEAD, httpOPTIONS, httpPATCH, httpTRACE);
TMVCHTTPMethodType = (httpGET, httpPOST, httpPUT, httpDELETE, httpHEAD, httpOPTIONS, httpPATCH,
httpTRACE);
TMVCHTTPMethods = set of TMVCHTTPMethodType;
TMVCMediaType = record
public const
APPLICATION_ATOM_XML = 'application/atom+xml';
APPLICATION_FORM_URLENCODED = 'application/x-www-form-urlencoded';
APPLICATION_JSON = 'application/json';
APPLICATION_OCTET_STREAM = 'application/octet-stream';
APPLICATION_SVG_XML = 'application/svg+xml';
@ -61,6 +62,7 @@ type
APPLICATION_OCTETSTREAM = 'application/octet-stream';
MEDIA_TYPE_WILDCARD = '*';
MULTIPART_FORM_DATA = 'multipart/form-data';
APPLICATION_FORM_URLENCODED = 'application/x-www-form-urlencoded';
TEXT_HTML = 'text/html';
TEXT_PLAIN = 'text/plain';
TEXT_XML = 'text/xml';
@ -288,7 +290,8 @@ type
{ protected declarations }
public
constructor Create(const AMsg: string); overload; virtual;
constructor Create(const AMsg: string; const ADetailedMessage: string; const AAppErrorCode: UInt16;
constructor Create(const AMsg: string; const ADetailedMessage: string;
const AAppErrorCode: UInt16;
const AHttpErrorCode: UInt16 = HTTP_STATUS.InternalServerError); overload; virtual;
constructor Create(const AHttpErrorCode: UInt16; const AMsg: string); overload; virtual;
constructor CreateFmt(const AMsg: string; const AArgs: array of const); reintroduce;
@ -354,7 +357,8 @@ type
protected
FDict: TDictionary<string, string>;
public
constructor Create; virtual;
constructor Create; overload; virtual;
constructor Create(const aKey, aValue: String); overload; virtual;
destructor Destroy; override;
procedure Clear;
function Add(const Name, Value: string): TMVCStringDictionary;
@ -416,7 +420,7 @@ type
function GetValue(const AIndex: string): string;
function GetValueAsInt64(const AIndex: string): Int64;
procedure SetValue(const AIndex: string; const AValue: string);
procedure SetValue(const AIndex: string; const aValue: string);
protected
{ protected declarations }
public
@ -451,9 +455,9 @@ function AppPath: string;
function IsReservedOrPrivateIP(const AIP: string): Boolean; inline;
function IP2Long(const AIP: string): UInt32; inline;
function B64Encode(const AValue: string): string; overload;
function B64Encode(const AValue: TBytes): string; overload;
function B64Decode(const AValue: string): string;
function B64Encode(const aValue: string): string; overload;
function B64Encode(const aValue: TBytes): string; overload;
function B64Decode(const aValue: string): string;
function URLSafeB64encode(const Value: string; IncludePadding: Boolean): string; overload;
function URLSafeB64encode(const Value: TBytes; IncludePadding: Boolean): string; overload;
@ -466,12 +470,17 @@ procedure SplitContentMediaTypeAndCharset(const aContentType: string; var aConte
var aContentCharSet: string);
function BuildContentType(const aContentMediaType: string; const aContentCharSet: string): string;
function Dict: TMVCStringDictionary; overload;
function Dict(const aKeys: array of string; const aValues: array of string)
: TMVCStringDictionary; overload;
const
MVC_HTTP_METHODS_WITHOUT_CONTENT: TMVCHTTPMethods = [httpGET, httpDELETE, httpHEAD, httpOPTIONS];
MVC_HTTP_METHODS_WITH_CONTENT: TMVCHTTPMethods = [httpPOST, httpPUT, httpPATCH];
const
MVC_COMPRESSION_TYPE_AS_STRING: array [TMVCCompressionType] of string = ('none', 'deflate', 'gzip');
MVC_COMPRESSION_TYPE_AS_STRING: array [TMVCCompressionType] of string = ('none',
'deflate', 'gzip');
MVC_COMPRESSION_ZLIB_WINDOW_BITS: array [TMVCCompressionType] of Integer = (0, -15, 31);
// WindowBits: http://zlib.net/manual.html#Advanced
@ -480,15 +489,19 @@ var
const
RESERVED_IPS: array [1 .. 11] of array [1 .. 2] of string = (('0.0.0.0', '0.255.255.255'),
('10.0.0.0', '10.255.255.255'), ('127.0.0.0', '127.255.255.255'), ('169.254.0.0', '169.254.255.255'),
('10.0.0.0', '10.255.255.255'), ('127.0.0.0', '127.255.255.255'),
('169.254.0.0', '169.254.255.255'),
('172.16.0.0', '172.31.255.255'), ('192.0.2.0', '192.0.2.255'), ('192.88.99.0', '192.88.99.255'),
('192.168.0.0', '192.168.255.255'), ('198.18.0.0', '198.19.255.255'), ('224.0.0.0', '239.255.255.255'),
('192.168.0.0', '192.168.255.255'), ('198.18.0.0', '198.19.255.255'),
('224.0.0.0', '239.255.255.255'),
('240.0.0.0', '255.255.255.255'));
implementation
uses
IdCoder3to4, JsonDataObjects, MVCFramework.Serializer.JsonDataObjects;
IdCoder3to4,
JsonDataObjects,
MVCFramework.Serializer.JsonDataObjects;
var
GlobalAppName, GlobalAppPath, GlobalAppExe: string;
@ -517,7 +530,8 @@ begin
if AIP.IsEmpty then
Exit(0);
lPieces := AIP.Split(['.']);
Result := (StrToInt(lPieces[0]) * 16777216) + (StrToInt(lPieces[1]) * 65536) + (StrToInt(lPieces[2]) * 256) +
Result := (StrToInt(lPieces[0]) * 16777216) + (StrToInt(lPieces[1]) * 65536) +
(StrToInt(lPieces[2]) * 256) +
StrToInt(lPieces[3]);
end;
@ -526,22 +540,22 @@ end;
// Result := IdGlobal.IPv4ToUInt32(AIP);
// end;
function B64Encode(const AValue: string): string; overload;
function B64Encode(const aValue: string): string; overload;
begin
// Do not use TNetEncoding
Result := TIdEncoderMIME.EncodeString(AValue);
Result := TIdEncoderMIME.EncodeString(aValue);
end;
function B64Encode(const AValue: TBytes): string; overload;
function B64Encode(const aValue: TBytes): string; overload;
begin
// Do not use TNetEncoding
Result := TIdEncoderMIME.EncodeBytes(TIdBytes(AValue));
Result := TIdEncoderMIME.EncodeBytes(TIdBytes(aValue));
end;
function B64Decode(const AValue: string): string;
function B64Decode(const aValue: string): string;
begin
// Do not use TNetEncoding
Result := TIdDecoderMIME.DecodeString(AValue);
Result := TIdDecoderMIME.DecodeString(aValue);
end;
function ByteToHex(AInByte: Byte): string;
@ -576,7 +590,8 @@ begin
begin
Result := lContentMediaType;
end
else if lContentMediaType.StartsWith('text/') or lContentMediaType.StartsWith('application/') then
else if lContentMediaType.StartsWith('text/') or lContentMediaType.StartsWith('application/')
then
begin
Result := lContentMediaType + ';charset=' + aContentCharSet.ToLower;
end
@ -596,7 +611,8 @@ begin
begin
lContentTypeValues := aContentType.Split([';']);
aContentMediaType := Trim(lContentTypeValues[0]);
if (Length(lContentTypeValues) > 1) and (lContentTypeValues[1].Trim.StartsWith('charset', True)) then
if (Length(lContentTypeValues) > 1) and (lContentTypeValues[1].Trim.StartsWith('charset', True))
then
begin
aContentCharSet := lContentTypeValues[1].Trim.Split(['='])[1].Trim;
end
@ -622,7 +638,8 @@ begin
FAppErrorCode := 0;
end;
constructor EMVCException.Create(const AMsg, ADetailedMessage: string; const AAppErrorCode, AHttpErrorCode: UInt16);
constructor EMVCException.Create(const AMsg, ADetailedMessage: string;
const AAppErrorCode, AHttpErrorCode: UInt16);
begin
Create(AMsg);
FHttpErrorCode := AHttpErrorCode;
@ -667,7 +684,8 @@ begin
end;
end;
function TMVCCriticalSectionHelper.DoWithLockTimeout(const AAction: TProc; const ATimeOut: UInt32): TWaitResult;
function TMVCCriticalSectionHelper.DoWithLockTimeout(const AAction: TProc; const ATimeOut: UInt32)
: TWaitResult;
begin
Result := Self.WaitFor(ATimeOut);
if (Result = TWaitResult.wrSignaled) then
@ -716,7 +734,8 @@ var
lStreamReader: TStreamReader;
lSer: TMVCJsonDataObjectsSerializer;
begin
lStreamReader := TStreamReader.Create(TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite), TEncoding.ASCII);
lStreamReader := TStreamReader.Create(TFileStream.Create(AFileName,
fmOpenRead or fmShareDenyWrite), TEncoding.ASCII);
try
lStreamReader.OwnStream;
lConfigString := lStreamReader.ReadToEnd;
@ -738,9 +757,9 @@ begin
TFile.WriteAllText(AFileName, ToString, TEncoding.ASCII);
end;
procedure TMVCConfig.SetValue(const AIndex, AValue: string);
procedure TMVCConfig.SetValue(const AIndex, aValue: string);
begin
FConfig.Add(AIndex, AValue);
FConfig.Add(AIndex, aValue);
end;
function TMVCConfig.ToString: string;
@ -778,6 +797,12 @@ begin
Result := FDict.Count;
end;
constructor TMVCStringDictionary.Create(const aKey, aValue: String);
begin
Create;
Add(aKey, aValue);
end;
constructor TMVCStringDictionary.Create;
begin
inherited;
@ -877,7 +902,8 @@ type
end;
const
GURLSafeBase64CodeTable: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
GURLSafeBase64CodeTable
: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
{ Do not Localize }
procedure TURLSafeEncode.InitComponent;
@ -984,12 +1010,35 @@ begin
Self.WriteBuffer(UFTStr[Low(UFTStr)], Length(UFTStr));
end;
function Dict: TMVCStringDictionary; overload;
begin
Result := TMVCStringDictionary.Create;
end;
function Dict(const aKeys: array of string; const aValues: array of string)
: TMVCStringDictionary; overload;
var
I: Integer;
begin
if Length(aKeys) <> Length(aValues) then
begin
raise EMVCException.CreateFmt('Dict error. Got %d keys but %d values',
[Length(aKeys), Length(aValues)]);
end;
Result := Dict();
for I := Low(aKeys) to High(aKeys) do
begin
Result.Add(aKeys[i], aValues[i]);
end;
end;
initialization
Lock := TObject.Create;
// SGR 2017-07-03 : Initialize decoding table for URLSafe Gb64 encoding
TURLSafeDecode.ConstructDecodeTable(GURLSafeBase64CodeTable, TURLSafeDecode.GSafeBaseBase64DecodeTable);
TURLSafeDecode.ConstructDecodeTable(GURLSafeBase64CodeTable,
TURLSafeDecode.GSafeBaseBase64DecodeTable);
GlobalAppExe := ExtractFileName(GetModuleName(HInstance));
GlobalAppName := ChangeFileExt(GlobalAppExe, EmptyStr);

View File

@ -79,8 +79,7 @@ uses
LoggerPro,
IdGlobal,
IdGlobalProtocols,
IdURI,
MVCFramework.Commons;
IdURI, MVCFramework.Commons;
type
@ -438,7 +437,7 @@ type
procedure ResponseStatus(const AStatusCode: Integer; const AReasonString: string = '');
// Serializer access
function Serializer: IMVCSerializer; overload;
function Serializer(const AContentType: string): IMVCSerializer; overload;
function Serializer(const AContentType: string; const ARaiseExcpIfNotExists: Boolean = True): IMVCSerializer; overload;
end;
IMVCAuthenticationHandler = interface
@ -465,7 +464,7 @@ type
procedure Redirect(const AUrl: string); virtual;
procedure ResponseStatus(const AStatusCode: Integer; const AReasonString: string = ''); virtual;
function Serializer: IMVCSerializer; overload;
function Serializer(const AContentType: string): IMVCSerializer; overload;
function Serializer(const AContentType: string; const ARaiseExceptionIfNotExists: Boolean = True): IMVCSerializer; overload;
procedure SendStream(const AStream: TStream; const AOwns: Boolean = True; const ARewind: Boolean = False); virtual;
procedure SendFile(const AFileName: string); virtual;
procedure RenderResponseStream; virtual;
@ -712,7 +711,7 @@ type
procedure HTTP404(const AContext: TWebContext);
procedure HTTP500(const AContext: TWebContext; const AReasonString: string = '');
procedure SendRawHTTPStatus(const AContext: TWebContext; const HTTPStatusCode: Integer;
const AReasonString: string);
const AReasonString: string; const AClassName: String = '');
property ViewEngineClass: TMVCViewEngineClass read GetViewEngineClass;
property WebModule: TWebModule read FWebModule;
@ -1893,7 +1892,7 @@ begin
end
else
begin
SendRawHTTPStatus(LContext, E.HTTPErrorCode, Format('[%s] %s', [E.Classname, E.Message]));
SendRawHTTPStatus(LContext, E.HTTPErrorCode, Format('[%s] %s', [E.Classname, E.Message]), E.ClassName);
end;
end;
on E: EInvalidOp do
@ -1907,7 +1906,7 @@ begin
else
begin
SendRawHTTPStatus(LContext, HTTP_STATUS.InternalServerError,
Format('[%s] %s', [E.Classname, E.Message]));
Format('[%s] %s', [E.Classname, E.Message]), E.Classname);
end;
end;
on E: Exception do
@ -1922,7 +1921,7 @@ begin
else
begin
SendRawHTTPStatus(LContext, HTTP_STATUS.InternalServerError,
Format('[%s] %s', [E.Classname, E.Message]));
Format('[%s] %s', [E.Classname, E.Message]), E.Classname);
end;
end;
end;
@ -2177,7 +2176,7 @@ begin
end;
procedure TMVCEngine.SendRawHTTPStatus(const AContext: TWebContext; const HTTPStatusCode: Integer;
const AReasonString: string);
const AReasonString: string; const AClassName: String);
var
lSer: IMVCSerializer;
lError: TMVCErrorResponse;
@ -2188,7 +2187,7 @@ begin
begin
lError := TMVCErrorResponse.Create;
try
lError.Classname := '';
lError.Classname := AClassName;
lError.StatusCode := HTTPStatusCode;
lError.Message := AReasonString;
AContext.Response.SetContent(lSer.SerializeObject(lError));
@ -2201,7 +2200,6 @@ begin
begin
AContext.Response.SetContentType(BuildContentType(TMVCMediaType.TEXT_PLAIN,
AContext.Config[TMVCConfigKey.DefaultContentCharset]));
AContext.Response.SetContent(GetServerSignature(AContext) + sLineBreak + 'HTTP ' + HTTPStatusCode.ToString + ': ' +
AReasonString);
end;
@ -2702,15 +2700,27 @@ begin
GetContext.Response.RawWebResponse.FreeContentStream := True;
end;
function TMVCRenderer.Serializer(const AContentType: string): IMVCSerializer;
function TMVCRenderer.Serializer(const AContentType: string; const ARaiseExceptionIfNotExists: Boolean): IMVCSerializer;
var
lContentMediaType: string;
lContentCharSet: string;
begin
SplitContentMediaTypeAndCharset(AContentType.ToLower, lContentMediaType, lContentCharSet);
if not Engine.Serializers.ContainsKey(lContentMediaType) then
raise EMVCException.CreateFmt('The serializer for %s could not be found.', [lContentMediaType]);
Result := Engine.Serializers.Items[lContentMediaType];
if Engine.Serializers.ContainsKey(lContentMediaType) then
begin
Result := Engine.Serializers.Items[lContentMediaType];
end
else
begin
if ARaiseExceptionIfNotExists then
begin
raise EMVCException.CreateFmt('The serializer for %s could not be found.', [lContentMediaType]);
end
else
begin
Result := nil;
end;
end;
end;
function TMVCController.SessionAs<T>: T;
@ -2973,6 +2983,10 @@ begin
R.Items.Add(I);
end;
end;
if Serializer(GetContentType, False) = nil then
begin
GetContext.Response.ContentType := GetConfig[TMVCConfigKey.DefaultContentType];
end;
Render(R, False);
finally
R.Free;

View File

@ -42,8 +42,13 @@ uses
Vcl.Grids,
Vcl.ValEdit,
FireDAC.Phys.MySQLDef,
FireDAC.Phys.MySQL, FireDAC.Phys.PGDef, FireDAC.Phys.PG, FireDAC.Phys.IBDef,
FireDAC.Phys.IB, FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteDef,
FireDAC.Phys.MySQL,
FireDAC.Phys.PGDef,
FireDAC.Phys.PG,
FireDAC.Phys.IBDef,
FireDAC.Phys.IB,
FireDAC.Stan.ExprFuncs,
FireDAC.Phys.SQLiteDef,
FireDAC.Phys.SQLite;
type
@ -153,7 +158,8 @@ begin
fImplBuff.WriteString(' inherited Create;' + sLineBreak);
for F := low(lFieldsName) to high(lFieldsName) do
begin
fImplBuff.WriteString(' ' + lFieldsName[F] + ' := ' + lTypesName[F] + '.Create;' + sLineBreak);
fImplBuff.WriteString(' ' + lFieldsName[F] + ' := ' + lTypesName[F] + '.Create;' +
sLineBreak);
end;
fImplBuff.WriteString('end;' + sLineBreak + sLineBreak);
@ -237,46 +243,81 @@ begin
end;
procedure TMainForm.EmitField(F: TField);
var
lAttrib, lField: String;
begin
fIntfBuff.WriteString(Format(' [MVCTableField(''%s'')]', [F.FieldName]) + sLineBreak + ' ' + GetFieldName(F.FieldName) + ': ' +
GetDelphiType(F.DataType) + ';' + sLineBreak);
lAttrib := Format(' [MVCTableField(''%s'')]', [F.FieldName]);
lField := GetFieldName(F.FieldName) + ': ' + GetDelphiType(F.DataType) + ';' + sLineBreak;
if GetDelphiType(F.DataType).ToUpper.Contains('UNSUPPORTED TYPE') then
begin
lAttrib := ' //' + lAttrib;
lField := ' //' + lField;
end
else
begin
lField := ' ' + lField;
lAttrib := ' ' + lAttrib;
end;
fIntfBuff.WriteString(lAttrib + sLineBreak + lField);
end;
procedure TMainForm.EmitHeaderComments;
begin
fIntfBuff.WriteString('// *************************************************************************** }' + sLineBreak);
fIntfBuff.WriteString
('// *************************************************************************** }' +
sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Delphi MVC Framework' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Copyright (c) 2010-2019 Daniele Teti and the DMVCFramework Team' + sLineBreak);
fIntfBuff.WriteString('// Copyright (c) 2010-2019 Daniele Teti and the DMVCFramework Team' +
sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// https://github.com/danieleteti/delphimvcframework' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString
('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Licensed under the Apache License, Version 2.0 (the "License");' + sLineBreak);
fIntfBuff.WriteString('// you may not use this file except in compliance with the License.' + sLineBreak);
fIntfBuff.WriteString('// Licensed under the Apache License, Version 2.0 (the "License");' +
sLineBreak);
fIntfBuff.WriteString('// you may not use this file except in compliance with the License.' +
sLineBreak);
fIntfBuff.WriteString('// You may obtain a copy of the License at' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// http://www.apache.org/licenses/LICENSE-2.0' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// Unless required by applicable law or agreed to in writing, software' + sLineBreak);
fIntfBuff.WriteString('// distributed under the License is distributed on an "AS IS" BASIS,' + sLineBreak);
fIntfBuff.WriteString('// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' + sLineBreak);
fIntfBuff.WriteString('// See the License for the specific language governing permissions and' + sLineBreak);
fIntfBuff.WriteString('// Unless required by applicable law or agreed to in writing, software' +
sLineBreak);
fIntfBuff.WriteString('// distributed under the License is distributed on an "AS IS" BASIS,' +
sLineBreak);
fIntfBuff.WriteString
('// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.' + sLineBreak);
fIntfBuff.WriteString('// See the License for the specific language governing permissions and' +
sLineBreak);
fIntfBuff.WriteString('// limitations under the License.' + sLineBreak);
fIntfBuff.WriteString('//' + sLineBreak);
fIntfBuff.WriteString('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString
('// ***************************************************************************' + sLineBreak);
fIntfBuff.WriteString(sLineBreak);
end;
procedure TMainForm.EmitProperty(F: TField);
var
lProp: String;
begin
// Buff.WriteString(Format(' [TableField(''%s'')]', [F.FieldName]) + sLineBreak + ' property ' + GetProperCase(F.FieldName) + ': ' +
// GetDelphiType(F.DataType) + ';' + sLineBreak);
fIntfBuff.WriteString(' property ' + GetFieldName(F.FieldName).Substring(1) { remove f } + ': ' + GetDelphiType(F.DataType));
fIntfBuff.WriteString(' read ' + GetFieldName(F.FieldName) + ' write ' + GetFieldName(F.FieldName));
fIntfBuff.WriteString(';' + sLineBreak);
lProp := 'property ' + GetFieldName(F.FieldName).Substring(1) { remove f } + ': ' +
GetDelphiType(F.DataType) +
' read ' + GetFieldName(F.FieldName) + ' write ' + GetFieldName(F.FieldName) + ';' + sLineBreak;
if GetDelphiType(F.DataType).ToUpper.Contains('UNSUPPORTED TYPE') then
begin
lProp := ' //' + lProp
end
else
begin
lProp := ' ' + lProp;
end;
fIntfBuff.WriteString(lProp)
end;
procedure TMainForm.EmitUnit;
@ -359,7 +400,7 @@ begin
Result := 'Boolean';
ftFloat, ftSingle, ftExtended:
Result := 'Double';
ftCurrency, ftBCD:
ftCurrency, ftBCD, ftFMTBcd:
Result := 'Currency';
ftDate:
Result := 'TDate';