Connector Development
Connector PlugIn API
For UNIFYConnect v6+, the service provides a self-documenting REST endpoint for the web UI and other external actors to use. This API is extensible and this article details process of implementing support for connector plugins. The following components are required for a standard connector plugin:
- Shared API Project
Agent API Information
Agent Extended Information
Connector API Information
Connector Extended Information
- API Project
- Agent Controller
- Connector Controller
- Web Project
- API Client
API Project Components
Agent and Connector Controllers
Controllers contain methods which are exposed via the API. Controllers must feature the following:
Agent
Implements PluggedAgentControllerBase<TApiConfig,TExtended> | Base controller class which contains standard agent controller functions. tapiconfig is AgentApiInformation<TExtended> and TExtended is IAgentExtendedInformation, both described below. |
Class has AgentPlugInVersionRouteAttribute set | Describes the route the controller and its methods should take on in the API. |
AgentPlugInVersionRouteAttribute argument agentFactoryName | Factory name for the agent. |
AgentPlugInVersionRouteAttribute argument agentPathElement | Name of the agent for use in the path. IE a value of 'Example' results in the path 'api/version/Agent/Example/AgentMethod' |
AgentPlugInVersionRouteAttribute argument version | Version of the API the controller is associated with. Should be in the format of 'x.x'. |
| Factory name passed to base constructor | Factory name for the agent. |
| Path element passed to base constructor | Name of the agent for use in the path. |
IAgentExtendedApiInformationAdapter<TExtended> | Agent extended information adapter passed to base constructor |
IAgentExtendedApiInformationFactory<TExtended> | Agent extended information factory passed to base constructor |
[AgentPlugInVersionedRoute(ExampleConstants.AgentName, ExampleConstants.AgentApiPath, ControllerVersion)]
public class ExampleAgentApiController : PluggedAgentControllerBase<ExampleAgentApiInformation, ExampleAgentExtendedApiInformation>
{
private const string ControllerVersion = VersionConstants.v1_0;
private static readonly ExampleAgentExtendedApiInformationAdapter _InformationAdapter = new();
private static readonly ExampleAgentExtendedApiInformationFactory _InformationFactory = new();
/// <summary>
/// Constructor for this controller.
/// </summary>
/// <param name="agentEngine">The agent engine.
public ExampleAgentApiController(IAgentEngine agentEngine)
: base(agentEngine, ExampleConstants.AgentName, ExampleConstants.AgentApiPath, _InformationAdapter, _InformationFactory)
{
}
// Any additional, custom API methods can be added here.
}Connector
Implements PluggedConnectorControllerBase<TApiConfig,TExtended> | Base controller class which contains standard connector controller functions. TApiConfig is ConnectorApiInformation<TExtended> and TExtended is IConnectorExtendedInformation, both described below. |
Class has ConnectorPlugInVersionRouteAttribute set | Describes the route the controller and its methods should take on in the API. |
ConnectorPlugInVersionRouteAttribute argument connectorFactoryName | Factory name for the connector. |
ConnectorPlugInVersionRouteAttribute argument connectorPathElement | Name of the connector for use in the path. IE a value of 'Example' results in the path 'api/version/Connector/Example/ConnectorMethod' |
ConnectorPlugInVersionRouteAttribute argument version | Version of the API the controller is associated with. Should be in the format of 'x.x'. |
| Factory name passed to base constructor | Factory name for the connector. |
| Path element passed to base constructor | Name of the connector for use in the path. |
IConnectorExtendedApiInformationAdapter<TExtended> | Connector extended information adapter passed to base constructor |
IConnectorExtendedApiInformationFactory<TExtended> | Connector extended information factory passed to base constructor |
[ConnectorPlugInVersionedRoute(ExampleConstants.ConnectorName, ExampleConstants.ConnectorApiPath, ControllerVersion)]
public class ExampleConnectorApiController : PluggedConnectorControllerBase<ExampleConnectorApiInformation, ExampleConnectorExtendedApiInformation>
{
private const string ControllerVersion = VersionConstants.v1_0;
private static readonly ExampleConnectorExtendedApiInformationAdapter _InformationAdapter = new();
private static readonly ExampleConnectorExtendedApiInformationFactory _InformationFactory = new();
/// <summary>
/// Constructor for this controller.
/// </summary>
/// <param name="connectorEngine">The connector engine.
public ExampleConnectorApiController(IConnectorEngine connectorEngine)
: base(connectorEngine, ExampleConstants.ConnectorName, ExampleConstants.ConnectorApiPath, _InformationAdapter, _InformationFactory)
{
}
// Any additional, custom API methods can be added here.
}:::
Custom Controller Functions
If additional API methods are required on the plugin API controller they can be implemented by adding them to the API controllers with the appropriate attributes set.
| Http method attribute | Attribute which dictates the HTTP method used. Options include HttpPostAttribute, HttpGetAttribute, HttpDeleteAttribute, HttpPutAttribute and HttpPatchAttribute. |
ActionNameAttribute | Give the API method a name different to the controller functions name. |
ApiMethodDescriptionAttribute | Sets a description for the method to be used in the APIs self-documentation. |
ApiMethodParamDescriptionAttribute | Sets a description for the specified method parameter to be used in the APIs self-documentation. Add this attribute once for each parameter. |
[HttpPost]
[ActionName("FuctionName")]
[ApiMethodDescription("A custom function which does something")]
[ApiMethodParamDescription("argument1", "The first argument, part of the query string")]
[ApiMethodParamDescription("argument2", "The second argument, the post body.")]
public TReturn CustomFunction(string argument1, CustomDataObject argument2)
{
// Do something
}Controller, Factories and Schema Providers Registration
To register a controller, use the appropriate method on the engine. This should be performed in the connector plugin constructor.When registering connector and agent factories, the second parameter passed is the legacy extended configuration adapter. This is responsible for converting a legacy XML connector extended configuration to the new config object.When developing a new connector, a null can be passed, but when updating a connector from v5.3 to v6, a legacy extended configuration adapter is needed.
Agent
// Register agent API controllers
agentEngine.AddAgentController<ExampleAgentApiController, ExampleAgentApiInformation, ExampleAgentExtendedApiInformation>(
VersionConstants.Version1_0,
new Dictionary<Type, object> { [typeof(IAgentEngine)] = agentEngine });
// Register agent factories
agentEngine.AddAgentFactory(new ExampleAgentFactory(), null);Connector
// Register connector API controllers
connectorEngine.AddConnectorController<ExampleConnectorApiController, ExampleConnectorApiInformation, ExampleConnectorExtendedApiInformation>(
VersionConstants.Version1_0,
new Dictionary<Type, object> { [typeof(IConnectorEngine)] = connectorEngine });
// Register connector factories
connectorEngine.AddConnectorFactory(new ExampleConnectorFactory(), null);// Get connector component repositories and register schema providers
IConnectorComponentRepository componentRepository = connectorEngine.ComponentRepository(ExampleConstants.ConnectorName);
componentRepository.AddSchemaProvider(new ExampleConnectorSchemaProvider());Shared API Project Components
It is recommended to create a shared API project for the components described in the section as they are referenced by the API controllers and the client in the Web project.
Agent Extended Information and Connector Extended Information
These are the API information classes which contain properties specific to the agent/connector type it is implemented for. They should feature the following:
Agent
Implements IAgentExtendedInformation | Interface type for the extended information. |
Type property | Should be set to the same value as the agent factory name. |
JsonIgnoreAttribute | An attribute that could be used with properties to exclude them from serialization.This attribute should be added to Type property |
DataContractAttribute and DataMemberAttribute | Legacy attributes used to include specific properties in data contract and serialization.the DataContractAttribute is used with the class and DataMemberAttribute is used with the properties (Type excluded) should have these attributes set. |
RequiredAttribute | Required properties should have this attribute set. |
ApiPropertyDescriptionAttribute | All properties (Type excluded) should have this attribute set with a description of the property. |
public class ExampleAgentExtendedInformation : IAgentExtendedInformation
{
public string Type => ExampleAgentAttributes.AgentFactoryName; // ie: Unify.Agent.Example
[Required]
[ApiPropertyDescription("The first value.")]
public string Value1
{
get; set;
}
[ApiPropertyDescription("The second value.")]
public string Value2
{
get; set;
}
}Connector
Implements IConnectorExtendedInformation | Interface type for the extended information. |
ConnectorType property | Should be set to the same value as the connector factory name. |
JsonIgnoreAttribute | An attribute that could be used with properties to exclude them from serialization.This attribute should be added to ConnectorType property |
DataContractAttribute and DataMemberAttribute | Legacy attributes used to include specific properties in data contract and serialization.the DataContractAttribute is used with the class and DataMemberAttribute is used with the properties (ConnectorType excluded) should have these attributes set. |
RequiredAttribute | Required properties should have this attribute set. |
ApiPropertyDescriptionAttribute | All properties (ConnectorType excluded) should have this attribute set with a description of the property. |
public class ExampleConnectorExtendedInformation : IConnectorExtendedInformation
{
[JsonIgnore]
public string Type => ExampleConnectorAttributes.ConnectorFactoryName; // ie: Unify.Connector.Example
[Required]
[ApiPropertyDescription("The first value.")]
public string Value1
{
get; set;
}
[ApiPropertyDescription("The second value.")]
public string Value2
{
get; set;
}
}Agent API Information and Connector API Information
Information objects sent via the API cannot be generic types so these classes are needed to provide non-generic versions of ConnectorApiInformation<TExtended>. Each connector and agent type should have a corresponding API information class created using that agent/connectors extended information type.
Agent
public class ExampleAgentApiInformation : AgentApiInformation<ExampleAgentExtendedInformation>
{
}Connector
public class ExampleConnectorApiInformation : ConnectorApiInformation<ExampleConnectorExtendedInformation>
{
}Web Project Components
API Client
To generate the Web API Client code (to allow communication from the user interface back to the service):
- Install nSwagStudio
- Install or deploy new pluggable API
- Start UNIFYConnect
- Create a new Web API endpoint, with a white-list filter including only the new API
- Open this nswag file in NSwag Studio, target the new API endpoint, and update the namespace. Excluded files may also need to be added to.
- Generate the client and make available to the user interface code
_SomethingClient = new SomethingClient {BaseUrl = ApiAddress};