Skip to content

Supporting External Configuration References

Connectors and agents require some additional steps to support external configuration references. If these guidelines are not followed, references will not be persisted and the benefit of the external configuration value store will be lost.

References

An external value is referenced by it's unique string key. When configuration referencing an external value is deserialised, the resulting object representing that value contains this key, rather than the value itself, and accessing the configuration value's Value property returns the value from the external store.

References within UNIFYConnect Service

When using configuration values within the UNIFYConnect service, such as reading configuration values for use in the connector or agent, whether a configuration value is a referenced value or not is opaque and irrelevant to it's consumption. Additionally, both connectors and agents support automatic reloading when updated external values are updated, so that within the connector or agent, no consideration needs to be given to when a configuration value is passed around as a IConfigValue or as a simple value accessed with .Value.

References across API boundary

When configuration values are transferred across the API boundary, in either direction, the a values reference key needs to be included. This is of particular importance when editing a connector/agent, as without the capacity to transfer reference keys to the web component, and accept them back, they would not be able to be persisted.

To do allow for this, the reference key for configuration values must be manually added API and web models, and special controls used in the create/edit web views to allow a external value to be selected. Note this is only required for configuration values that need it; a configuration value that has no need to reference an external value can be handled normally.

API Models

On API model that implement IAgentExtendedInformation or IConnectorExtendedInformation a reference key property must be added for each configuration value that needs to support external configuration references. Both value and reference key properties need to be optional fields, as when one is set, the other will not be.

C#
public string? UserName { get; set; }

public string? UserNameRefKey { get; set; }

For required configuration values, in place of [Required] implement the interface System.ComponentModel.DataAnnotations.IValidatableObject like so, which ensures that the required fields are either set by value, or by reference key.

C#
var validator = ModelValidator.CreateValidator(this, validationContext);
yield return validator.Required(static m => m.UserName, static m => m.UserNameKey);

To convert between a configuration value and the separate value/reference key of the model, a set of helper methods is available.

C#
// Decomposing configuration value into separate value or reference key 
// (one will be set, other will be null)
IConfigValue<string> userNameValue = sourceValue.GetString("userName");
var (userName, userNameRefKey) = userNameValue.DecomposeConfigValue();

// Composing value and reference key to a configuration value.
// Reference key takes precedence if neither are null.
ConfigValueOption<string> userNameValue = ExtensibilityHelper.ComposeConfigValue(
    userName,
    userNameRefKey,
    _ExternalConfigValueStore,                // From configuration engine
    value => new ConfigString(value));        // Construct desired value type, transform value, etc

WARNING

Secure strings are decrypted during decompose. It is recommended that sensitive fields like passwords or tokens not be populated on API models, and these fields be write only.

Web Models

For web view models that implement IAgentViewInformation or IConnectorViewInformation should follow a similar pattern to the API models, with the separate reference key property for configuration values that need them.

The method of marking required fields differs, however, as reference aware required attributes are available.

C#
// Use instead of [Required]
[ReferenceAwareRequired(nameof(ThingRefKey))]

// Conditional required attributes, have the `ReferenceKeyProperty` property.
[RequiredIfEquals(nameof(CodeNumber), 0, ReferenceKeyProperty = nameof(RefKey))]
[RequiredIfTrue(nameof(Enabled), ReferenceKeyProperty = nameof(RefKey))]

TIP

Ensure that in the web controllers all reference keys are properly transferred from API model to web models, and vise versa.

Create/Edit Web View

For configuration that supports external references, users need to be able to input values directly or select an external value. Input templates are available for text box, text area and password input types.

C#
@Html.TextBoxOrExternalRefFor(model => model.UserName, model => model.UserNameRefKey);
@Html.TextAreaOrExternalRefFor(model => model.ConnectionString, model => model.ConnectionStringRefKey);
@Html.PasswordOrExternalRefFor(model => model.Secret, model => model.SecretRefKey);

Views which use these input templates must also include the external value selection modal.

C#
@Html.RenderSelectExternalConfigValueModal()

In situations where a model value is not displayed but still needs to be submitted, that value's reference key must also be handled in the same way.

C#
@Html.HiddenFor(model => model.UserName);<br>@Html.HiddenFor(model => model.UserNameRefKey);

Display Web Views

A display value template is also available, similar to the input templates, that allows users to clearly identify whether a configuration value is set directly or is referencing a value, as well as displaying the value from the external store.

C#
@Html.DisplayValueOrExternalRefFor(model => model.UserName, model => model.UserNameRefKey)