Building Connectors
Last updated
Last updated
To start developing a new Connector, create a new C# library project in Visual Studio and import the XMPro.Integration.Framework NuGet package. When writing the code for a Connector, you will have to implement one or more interfaces:
Optional
Allows the Connector to send notifications to the App Page to notify the change of entity.
Optional
Allows the Connector to advise the Time Series Analysis that the data is pre-processed and returned in buckets.
IConnector is the primary interface that all Connectors must implement as it provides the structure for the workings of the Connector. There are several methods required to implement this interface.
Some Connectors need to be provided with configurations by the user. For example, for a SQL Connector to get records from a SQL Database, it needs the following:
Server Instance
User Name
Password
Database
Each of these settings should be referenced in the code and must correspond to the settings template created when packaging your Connector.
A template is a JSON representation of all the controls and their layout that will be used to capture the settings from a user.
An example of the settings template (generated using the XMPro Package Manager) is shown in the image below. The settings in this example consist of the following controls:
Group (Server)
Textbox
Checkbox
Group (Database)
DropDown
ScriptBox
Each control has a Key, which uniquely identifies it in the template and allows the Connector code to access its value at any time. To get the value contained in a setting, use the following code:
Before a template is rendered on the screen, or if a postback occurs on any control in the template, the method below would be called to allow the Connector an opportunity to make any necessary runtime changes to the template, for example, verifying user credentials, displaying all tables of a selected database in a drop-down list, etc. In this example, no changes are being made to the template, but they can be added to the todo section if needed.
For a postback to occur after a user navigates out of a setting field, the Postback property needs to be set to true when packaging the Connector.
Each Connector must inform the Engine about the Entities that will be produced by the Connector. To do this, implement the following method:
This method returns a collection of Entities, which represent an object or a function of the Connector. For example, an Entity can be a Table within the configured Database in the SQL Connector.
Each Entity contains the following:
The Connector must provide a list of the Entity's properties, which describe its key, output schema, and optional inputs. To achieve this, implement the following method:
This method returns the Entity with a collection of properties for the selected Entity's entityId, which is passed as a parameter to this method.
Most properties will be Output properties, which describe the Entity's data, and are indicated by setting key and isParameter to false. For example, this String property named OutputString:
At least one property should be marked as the Entity's Key, indicated by setting key to true. The key uniquely identifies records when performing Update or Delete tasks, and for Application Blocks such as Grids that require a unique key per record. For example, this Long property named Id:
Finally, we have the optional Parameter properties, indicated by setting isParameter to true. They are included in the output schema, but also exposed to the App Page as optional input to the Read operation - retrieved from its options parameter to modify the results. For example, this Int property named Input:
Few Connectors need Parameter properties - they are used when the desired outcome is not achievable through the regular Configuration settings or the data source filter.
For example, the Azure Digital Twins Connector's Time Series entity includes an optional input parameter, "$ts", which shows up in the output as well as a Timestamp for that specific record/event.
The Connector must implement a method called Create, which is invoked when your Connector is hosted. User-defined configuration is passed as a parameter to this method and should be stored in a class variable for later use. This is a good point to provide any resources needed for the working of your Connector.
The Read method is one of the Entities' operations and is expected to return a JToken back to the Engine. This method is invoked when a Read/Refresh Action is called from a Block within an App Page.
This method contains a list of parameters being passed from the Engine.
entityId
A unique identifier for the Entity
OperationOptions
The operation options as configured by a user:
Parameters: a JObject containing the input parameters' value
Filter: the data filter criteria
TransactionName: the name of the transaction
count
The number of records
extraOptions
A JObject contains the following:
Sort: the data sorting criteria
Skip: the number of records to skip
Take: the number of records to return
The Insert method is one of the Entities' operations and is expected to return a JObject back to the Engine with the inserted record Id. This method will be invoked when an Insert Action is called from a Block within an App Page.
entityId
A unique identifier for the Entity
values
A JObject of values to be inserted
OperationOptions
The operation options as configured by a user:
Parameters: a JObject containing the input parameters' value
Filter: the data filter criteria
TransactionName: the name of the transaction
The Update method is one of the Entities' operations and is expected to return a JObject back to the Engine with the updated record Id. This method will be invoked when an Update Action is called from a Block within an App Page.
entityId
A unique identifier for the Entity
key
A JObject containing the primary key of the record to be updated
values
A JObject of values to be updated
OperationOptions
The operation options as configured by a user:
Parameter: a JObject containing the input parameters' value
Filter: the data filter criteria.
TransactionName: the name of the transaction
The Delete method is one of the Entities' operations and is expected to return back to the Engine with the number of records deleted. This method will be invoked when a Delete Action is called from a Block within an App Page.
entityId
A unique identifier for the Entity
key
A JObject containing the primary key of the record to be deleted
OperationOptions
The operation options as configured by a user:
Parameters: a JObject containing the input parameters' value
Filter: the data filter criteria
TransactionName: the name of the transaction
Each Connector must implement a Destroy method, which will be invoked when an App Page is closed. Use this method to release any resources or memory that your Connector may have acquired during its lifetime.
If a Connector’s configuration contains a Secure/Password Textbox, its value will automatically be encrypted. To decrypt the value, use the following set of instructions:
While building your Connector, you may need to use external libraries or third-party event subscriptions to handle custom events. If these are used, you must catch any exceptions from the event handlers yourself, to prevent uncaught exceptions that could possibly crash the App Page if they get through.
The ILiveConnector interface allows the Connector to send notifications to an App Page to notify of a change to the entity. There are several methods required to implement this interface.
Subscribe is called by the Engine to inform the Connector that an App Page has been opened that uses Live Data from a given Entity (IsLive property set to true), and should be used to begin listening for changes to that entity. The Subscribe method has two overloads and can be used in the following ways:
Use the first overload if you only want to pass the entity ID to the method.
Use the second overload if you want to use filtering.
The second overload is supported on App Designer v4.3.5 and XMPro.Integration.Framework v4.2 and above.
Unsubscribe is called by the Engine to inform the Connector that all AppPages that use Live Data from a given Entity have been closed, and should be used to stop listening for changes to that entity.
This method can be used to allow external changes to be passed to the Connector's internal entity tracking.
To push the changes of entities to an App Page that subscribed to the live update, your Connector should invoke the OnChange event with the values of changes as arguments:
A Connector can publish messages to the Connector Logs by implementing the IConnectorError interface.
To log the error, your Connector should invoke the OnConnectorError event with the error information passed as arguments:
v4.4.12: replaced the ITSCConnector interface, which is now deprecated.
The ITSAConnector interface notifies the Time Series Analysis to use optimized client-side querying to increase its performance. The Connector will pre-process the large volumes of data and return it in buckets.
When a Connector that implements the ITSAConnector interface is used with a Time Series Analysis Block, the Block expects the Connector to implement a specialized structure for data inputs and outputs:
Implement Date Buckets by organizing the data into separate partitions based on specific time intervals, such as days, weeks, or months. Below is a of sample bucketed data with an interval of 2 hours:
2024-03-28 08:00:00
25.4
18.2
32.7
2024-03-28 05:36:17
2024-03-28 08:00:00
24.8
18.5
33.2
2024-03-28 07:12:45
2024-03-28 08:00:00
25.1
18.9
34.0
2024-03-28 08:58:21
2024-03-28 10:00:00
25.6
19.2
34.5
2024-03-28 09:27:54
2024-03-28 10:00:00
26.2
19.6
34.8
2024-03-28 10:44:30
2024-03-28 10:00:00
26.5
19.8
35.1
2024-03-28 11:15:01
2024-03-28 12:00:00
27.0
20.1
35.3
2024-03-28 12:21:59
2024-03-28 12:00:00
27.3
20.5
35.7
2024-03-28 13:33:42
2024-03-28 12:00:00
27.7
20.8
36.0
2024-03-28 14:07:29
2024-03-28 14:00:00
27.9
21.2
36.3
2024-03-28 15:08:11
Replace the Original Timestamp with the Bucketed Timestamp value for final results. For example:
2024-03-28 08:00:00
25.4
18.2
32.7
2024-03-28 08:00:00
24.8
18.5
33.2
2024-03-28 08:00:00
25.1
18.9
34.0
2024-03-28 10:00:00
25.6
19.2
34.5
2024-03-28 10:00:00
26.2
19.6
34.8
2024-03-28 10:00:00
26.5
19.8
35.1
2024-03-28 12:00:00
27.0
20.1
35.3
2024-03-28 12:00:00
27.3
20.5
35.7
2024-03-28 12:00:00
27.7
20.8
36.0
2024-03-28 14:00:00
27.9
21.2
36.3
SQL and ADX have a native function to achieve this, DATE_BUCKET() for SQL and bin() for ADX.
Use the interface and implement buckets on any Connector to access the Time Series Analysis Block optimizations for your Data Source.
The code below is an example of an empty connector. Take note of how the interfaces and methods have been implemented.