2012-04-12

Custom JSON serialization of any dynamic array content

One nice feature of the TDynArray wrapper and its associated methods, as defined and used in our framework, is the ability to serialize any dynamic array as JSON content.

By default, only "standard" dynamic arrays (like TIntegerDynArray) are serialized as true JSON array: other not known kind of arrays are serialized as binary content, within a Base64 encoding.

This is a very efficient solution for a pure Delphi application, since it will be fast and always works, but won't be easy to deal with from an AJAX client.

Applications can now supply a custom JSON serialization for any other dynamic array, via the TTextWriter.RegisterCustomJSONSerializer() class method.
Two callbacks are to be supplied for a dynamic array type information, in order to handle proper serialization and un-serialization of the JSON array.

Continue reading

2012-04-10

How function results are allocated

One potential issue with Delphi coding, is about how the result of a functions are implemented.

If you forget to set a result value to a function, you'll get a compiler warning.
Never underestimate such warning: IMHO this is not a warning, but an error.

And you should better be aware of the handling of reference-counted types (e.g. string) in a function results: those are passed the stack as var parameters, so the result of a function may be set even if an exception is raised during function execution!

Continue reading

2012-03-28

Return custom content from an interface-based service

As stated by this previous article, the default answer format is a valid JSON object.

In some cases, it may be useful to have a service operation (i.e. an interface method) returning any content, e.g. some plain TEXT, HTML or binary data (like a picture).

Continue reading

2012-03-07

Interface based services - sample code

In addition to the other related blog articles, you can find in the "SQLite3/Samples/14 - Interface based services" folder of the supplied source code distribution, a dedicated sample about this feature.

Purpose of this code is to show how to create a client-server service, using interfaces, over named pipe communication.

Continue reading

Interface based services - Implementation details

You will find out in SQLite3Commons.pas all classes implementing this interface communication.

There are two levels of implementation:
- A services catalog, available in TSQLRest.Services property, declared as TServiceContainer (with two inherited versions, for each side);
- A service factory for each interface, declared as TServiceFactory (also with two inherited versions, for each side).

In fact, TServiceFactory.Create constructor will retrieve all needed RTTI information of the given interface, i.e. GUID, name and all methods (with their arguments). It will compute the low-level stack memory layout needed at execution. And the corresponding "contract" will be computed, to validate that both client and server expect the exact same interface.

On the server side, TServiceFactoryServer.ExecuteMethod method (and then a nested TServiceMethod.InternalExecute call) is used to prepare a valid call to the implementation class code from a remote JSON request.

On the client side, a TInterfacedObjectFake class will be created, and will emulate a regular Delphi interface call using some on-the-fly asm code generated in the TServiceFactoryClient.Create constructor.

Continue reading

Interface based services - Using services on the Client or Server sides

Once the service is registered on the server side, it is very easy to use it in your code.

In a complex Service Oriented Architecture, it is pretty common to have services calling each other. Code re-usability is a key here. So you'll have to consume services on the server side. According to the SOLID design principles, you'd better rely on abstraction in your code, i.e. not call the service implementation, but the service abstract interface.

You can use the following method of your TSQLRest.Services instance (note that this method is available on both client and server sides, so is the right access point to all services):

 function TServiceFactory.Get(out Obj): Boolean;

Continue reading

Interface based services - Server side

In order to have an operating service, you'll need to implement a Delphi class which matches the expected interface.

Continue reading

Interface based services - defining a data contract

In a Service Oriented Architecture, services tend to create a huge list of operations.
In order to facilitate implementation and maintenance, operations shall be grouped within common services.

The data contract is to be defined as a plain Delphi interface type.
In fact, the sample type as stated in a previous blog article can be used directly:

type
  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
    /// add two signed 32 bit integers
    function Add(n1,n2: integer): integer;
  end;

This ICalculator.Add method will define one "Add" operation, under the "ICalculator" service (which will be named internally 'Calculator' by convention).
This operation will expect two numbers as input, and then return the sum of those numbers.

Continue reading

- page 35 of 52 -