Renders

Renders are the mechanism used by DMVCFramework to serialize your data (objects, strings, dataset, JSON structure) into a format suitable for the network transfer as a string. This process is called "Serialization" while the opposite process (create an objects from a string rapresentation) is called "Deserialization". For instance if you want to serialize a dataset you can call withing a controller Render(LMyDataset) and your client will get a serialized version of dataset data. By default the serialization format is JSON but this can be changed and customized according to your needs. Remember, all the serialization/deserialization activities should be happens within the controller actions.

Rendering JSON data

Here's a controller action which returns JSON data string serializing a native Delphi JSON object.

procedure TRenderSampleController.GetPerson(CTX: TWebContext);
var
  LPerson: TJSONObject;
begin
  LPerson := TJSONObject.Create;
  try
    LPerson.AddPair('FirstName', 'Daniele');
    LPerson.AddPair('LastName', 'Teti');
    LPerson.AddPair('DOB', ISODateToString(EncodeDate(1975, 5, 2)));
    LPerson.AddPair('Married', TJSONTrue.Create);
    Render(LPerson);
  except
    LPerson.Free; //in case of exception, avoid memory leaks
    raise; //re-raise the exception
  end;  
end;

Rendering TDataSet

Here's a controller action which returns JSON data string serializing a TDataSet descendant.

procedure TRenderSampleController.GetCustomers_AsDataSet(CTX: TWebContext);
var
  wm: TWebModule1;
begin
  //On the WebModule there is a TFDConnection connected to a 
  //database and a TFDQuery with the corresponding select SQL 
  wm := GetCurrentWebModule as TWebModule1;
  wm.qryCustomers.Open;
  Render(wm.qryCustomers); //Renders all columns and all rows of the Query
end;

Rendering objects and list of objects

Here's a controller action which returns JSON data string serializing a native Delphi object.

procedure TRenderSampleController.GetCustomerByID(CTX: TWebContext);
var
  Cust: TCustomer;
begin
  Cust := TCustomer.Create;  
  try
    Cust.Name := 'bit Time Professionals';
    Cust.ContactFirst := 'Daniele';
    Cust.ContactLast := 'Teti';
    Cust.AddressLine1 := 'Rome Street 12';
    Cust.AddressLine2 := '00100';
    Cust.City := 'ROME';
{The following line renders a TObject descendant as JSON. 
The object memory is automatically freed however, 
you can override this behaviour using other parameters}    
    Render(Cust);
  except
    Cust.Free; //in case of exception, avoid memory leaks
    raise; //re-raise the exception
  end;
end;

Here's a type declaration of a native Delphi object containing a nested object and a nested object list.

uses
  Generics.Collections;

type
  TNested = class
  private
    FNestedString: String;
    FNestedInteger: Integer;
  public
    property NestedString: String read FNestedString write FNestedString;
    property NestedInteger: Integer read FNestedInteger write FNestedInteger;
  end;

  TParent = class
  private
    FParentString: String;
    FNestedProperty: TNested;
    FNestedList: TObjectList<TNested>;
    procedure SetNestedList(const Value: TObjectList<TNested>);
  public
    property ParentString: String read FParentString write FParentString;
    property NestedProperty: TNested read FNestedProperty write FNestedProperty;
    [MapperListOf(TNested)]
    property NestedList: TObjectList<TNested> read FNestedList write SetNestedList;

    constructor Create; virtual;
    destructor Destroy; override;
   end;

The [MapperListOf(TNested)] attribute is important. This tells the DMVC Framework which class is in the list and can be auto created by the deserialization. If this attribute is missing the items of the object list would not be created even if there is data in the JSON string.

For serialization and deserialization nested objects and object lists must be created. But can be freed at runtime as we can see further down.

constructor TParent.Create; 
begin
  inherited;
  FNestedProperty := TNested.Create;
  FNestedList := TObjectList<TNested>.Create;
end;

destructor TParent.Destroy; 
begin
  FNestedProperty.Free;
  FNestedList.Free;
  inherited;
end;

procedure TParent.SetNestedList(const Value: TObjectList<TNested>);
begin
  if (Value <> FNestedList) then
  begin
    FNestedList.Free;
    FNestedList := Value;
  end;
end;

Here's a controller action which returns JSON data string serializing the object from above:

procedure TRenderSampleController.GetParent(CTX: TWebContext);
var
  Data: TParent;
  NestedData: TNested;
begin
  Data := TParent.Create;  
  try
    Data.ParentString := 'ParentString';
    Data.NestedProperty.NestedString := 'NestedString';
    Data.NestedProperty.NestedInteger := 42;

    //in case of an ampty NestedProperty You can do
    //Data.NestedProperty.Free;
    //Data.NestedProperty := nil;

    NestedData := TNested.Create;
    NestedData.NestedString := 'one more NestedString';
    NestedData.NestedInteger := 21;
    Data.NestedList.Add(NestedData);

  {The following line renders a TObject descendant as JSON. 
The object memory is automatically freed however, 
you can override this behaviour using other parameters}    
    Render(Data);
  except
    Data.Free; //in case of exception, avoid memory leaks
    raise; //re-raise the exception
  end;
end;

The returning JSON string:

{
    "ParentString" : "ParentString",
    "NestedProperty" : {
        "NestedString" : "NestedString",
        "NestedInteger" : 42
    },
    "NestedList" : [{
            "NestedString" : "one more NestedString",
            "NestedInteger" : 21
        }
    ]
}

If You want to allow "null" or "nil" of FNestedProperty You can free and nil it at runtime. If FNestedProperty is nil the srialization produces a JSON string which contains the name NestedProperty with the value null. For deserialization FNestedProperty must be created within TParent.Create. The deserialization make the free and nil. NestedProperty can't have a setter in this case.

The returning JSON string with the null value:

{
    "ParentString" : "ParentString",
    "NestedProperty" : null,
    "NestedList" : [{
            "NestedString" : "one more NestedString",
            "NestedInteger" : 21
        }
    ]
}

Attributes

[MapperJSONNaming(JSONNameLowerCase)] / [MapperJSONNaming(JSONNameUpperCase)]

This is a class level attribute which tells the DMVC serialization to lower case or upper case JSON names. Example:

type
  [MapperJSONNaming(JSONNameLowerCase)]
  TNested = class
  private
    FNestedString: String;
  public
    property NestedString: String read FNestedString write FNestedString;
  end;

Output:

{
    "nestedstring" : "one more NestedString",
}

[MapperTransient]

This is a property level attribute which tells the DMVC serialization do not serialize this property. Example:

type
  TNested = class
  private
    FNestedString: String;
    FTransient: String;
  public
    [MapperTransient]
    property Transient: String read FTransient write FTransient;
    property NestedString: String read FNestedString write FNestedString;
  end;

Output:

{
    "NestedString" : "one more NestedString",
}

[MapperListOf(TObject)]

This is a property level attribute for TList/TObjectList properties which tells the DMVC deserialization which class is in the list and should be deserialized. This attribute did not have any impact on serialization but is important for deserialization. Example:

type
  TNested = class
  private
    FNestedString: String;
  public
    property NestedString: String read FNestedString write FNestedString;
  end;

  TParent = class
  private
    FNestedList: TObjectList<TNested>;
  public
    [MapperListOf(TNested)]
    property NestedList: TObjectList<TNested> read FNestedList write FNestedList;
   end;

[MapperJSONSer('json_name')]

This is a property level attribute which tells the DMVC serialization do use the given string as JSON name. Example:

type
  TNested = class
  private
    FNestedString: String;
  public
    [MapperJSONSer('new_name')]
    property NestedString: String read FNestedString write FNestedString;
  end;

Output:

{
    "new_name" : "one more NestedString",
}

Rendering raw data as streams

Here's a controller action which returns an image serializing a TStream descendant.

procedure TRenderSampleController.GetPersonPhotoAsStream(CTX: TWebContext);
var
  LPhoto: TFileStream;
begin
  LPhoto := TFileStream.Create('..\..\..\_\customer.png', fmOpenRead or fmShareDenyWrite);
  ContentType := 'image/png'; // you can also use MVCProduces attribute
  // LPhoto is a plain TStream descendant, so it can be rendered as usual
  Render(LPhoto, True);
end;

With this method You can render all kind of data (images, pdf files, word documents, binary data ...). It is important to set the content type so the client (browser) can handle the data correctly.

results matching ""

    No results matching ""