Migrating a Connector from v5.3 to v6
This document explains how to update a connector from v5.3 to v6
Update Controllers and Factories Registrations
Update the connector and agent controllers and factories registration in the connector plugin constructor
Agent
v5.3
// Register agent API controllers
agentEngine.AddAgentController<ExampleConnectorApiController, ExampleConnectorApiInformation, ExampleConnectorExtendedApiInformation>(
VersionConstants.Version1_0,
() => new ExampleAgentApiController(agentEngine));
// Register agent factories
agentEngine.AddAgentFactory(new ExampleAgentFactory());2
3
4
5
6
7
v6
To update to v6, when registering the agent factory, we need to pass a legacy extended configuration adapter as a second parameter.
// Register agent API controllers
agentEngine.AddAgentController<ExampleConnectorApiController, ExampleConnectorApiInformation, ExampleConnectorExtendedApiInformation>(
VersionConstants.Version1_0,
new Dictionary<Type, object> { [typeof(IAgentEngine)] = agentEngine });
// Register agent factories
agentEngine.AddAgentFactory(new ExampleAgentFactory(), new ExampleAgentLegacyExtendedConfigurationAdapter());2
3
4
5
6
7
Connector
v5.3
// Register connector API controllers
connectorEngine.AddConnectorController<ExampleConnectorApiController, ExampleConnectorApiInformation, ExampleConnectorExtendedApiInformation>(
VersionConstants.Version1_0,
() => new ExampleConnectorApiController(connectorEngine));
// Register connector factories
connectorEngine.AddConnectorFactory(new ExampleConnectorFactory(), new ExampleConnectorLegacyExtendedConfigurationAdapter());2
3
4
5
6
7
v6
To update to v6, when registering the connector factory, we need to pass a legacy extended configuration adapter as a second parameter.
// Register connector API controllers
connectorEngine.AddConnectorController<ExampleAgentApiController, ExampleAgentApiInformation, ExampleAgentExtendedApiInformation>
VersionConstants.Version1_0,
new Dictionary<Type, object> { [typeof(IConnectorEngine)] = connectorEngine });
// Register connector factories
connectorEngine.AddConnectorFactory(new ExampleConnectorFactory(), new ExampleConnectorLegacyExtendedConfigurationAdapter());2
3
4
5
6
7
Conversion from ConfigObject to Information Objects
classes responsible for converting the extended XML configuration to extended Information objects, will be replaced by classes to convert from ConfigObject to extended Information objects.In the new classes, the extraction of values from XML is replaced with code that extracts the config values from the IConfigObject/IConfigArray structure. Be mindful of values that could be null or missing and use the MaybeGet___ methods instead of the Get___ methods.
Also, be mindful of any special value conversion done here. This will need to be moved so either comment it out or cut and paste it to a safe location.
Next, open the information class created by the factory code and decide how it needs to represent the config values. Possibilities are:
- As the raw values. This will not allow that field to support external value referencing except in cases where the value is not used to recreate the config object (ie extended configuration)
- As config values (ie
IConfigValue<>,IConfigEnum<>) and config options (ieConfigValueOption<>,ConfigEnumOption<>). If in doubt, choose this.
Update the property types on the information class, its interfaces, constructor, etc as needed. Like with the factory code, if there is any special value conversion performed by the information class comment out or remove this to be moved for later use.
Secure string values do not need any special handling.
Agent
v5.3
public class ExampleAgentExtendedApiInformationFactory: IConfigElementToAgentExtendedApiInformation<ExampleAgentExtendedApiInformation>
{
public ExampleAgentExtendedApiInformation Transform(XElement sourceValue)
{
if (sourceValue == null) throw new ArgumentNullException(nameof(sourceValue));
XElement agentElement = sourceValue.Element(ExampleConfigConstants.AgentConfigurationElementName);
string thingValue= agentElement.AttributeValue(ExampleConfigConstants.ThingAttribute);
string password= agentElement.GetAttributeSecureString(ExampleConfigConstants.PasswordAttribute);
return new ExampleAgentExtendedApiInformation (thingValue, password);
}
}2
3
4
5
6
7
8
9
10
11
12
v6
Create a class that implements IAgentExtendedApiInformationFactory<TExtended> that converts from ConfigObject to Information Object. This should replace the usage of old class implementation of IConfigElementToAgentExtendedApiInformation<TExtended>
public class ExampleAgentExtendedApiInformationFactory : IAgentExtendedApiInformationFactory<exampleagentextendedapiinformation>
{
public ExampleAgentExtendedApiInformation Transform(IConfigObject sourceValue)
{
IConfigValue<string> thingValue = sourceValue.GetString(ExampleConfigConstants.ThingValue);
IConfigValue<string> password= sourceValue.GetString(ExampleConfigConstants.ThingValue);</string>
return new ExampleAgentExtendedApiInformation(thingValue.Value, password);
}
}2
3
4
5
6
7
8
9
Connector
v5.3
public class ExampleConnectorExtendedApiInformationFactory : IConfigElementToConnectorExtendedApiInformation<ExampleConnectorExtendedApiInformation >
{
public ExampleConnectorExtendedApiInformation Transform(XElement sourceValue)
{
if (sourceValue == null) throw new ArgumentNullException(nameof(sourceValue));
XElement connectorElement = sourceValue.Element(ExampleConfigConstants.ConnectorConfigurationElementName);
int countValue = connectorElement.AttributeIntegerValue(ExampleConfigConstants.CountAttribute);
return new ExampleConnectorExtendedApiInformation ();
}
}2
3
4
5
6
7
8
9
10
11
v6
Create a class that implements IConnectorExtendedApiInformationFactory<TExtended> that converts from ConfigObject to Information Object. This should replace the usage of old class implementation of IConfigElementToConnectorExtendedApiInformation<TExtended>
public class ExampleConnectorExtendedApiInformationFactory : IConnectorExtendedApiInformationFactory<ExampleConnectorExtendedApiInformation >
{
public ExampleConnectorExtendedApiInformation Transform(IConfigObject sourceValue)
{
IConfigValue<long> countValue = sourceValue.GetInteger(ExampleConfigConstants.CountValue);
return new ExampleConnectorExtendedApiInformation(countValue.GetInt32Value());
}
}2
3
4
5
6
7
8
9
Conversion from Extended Information Objects to ConfigObject
A class implementation of IValueAdapter<XElement,T> is needed to convert from the extended information object to ConfigObject.
Create the configuration structure, starting with a ConfigObject, from the values contained in the information object passed to the Transform method. ConfigObject and ConfigArray have all the required Set and Add methods needed to accept any config value, option type, or raw value. These methods also handle null values appropriately, so raw values do not need to be checked.
Refer back to the legacy extensibility adapter, for any conditional value setting or similar handling, and as a reference of the correct config keys to use. The target of both of the adapters should be the same.
When creating objects, a version will need to be provided. Create a static version for each type object type in the static constants class, along with the ConfigKeys. The value for this should be 1.0, to be incremented for changes made after the release of v6.0.
Agents
v5.3
public class ExampleAgentExtendedApiInformationAdapter: IAgentExtendedApiInformationToConfigElement<ExampleAgentExtendedApiInformation>
{
public XElement Transform(ExampleAgentExtendedApiInformation sourceValue)
{
var agentElement = new XElement(
ExampleConstants.AgentConfigurationElementName,
new XAttribute(ExampleConstants.ClientIdAttribute, sourceValue.Thing),
new XAttribute(ExampleConstants.ClientSecretAttribute, sourceValue.Password.WorkerEncryptString()));
return new XElement(ExampleConstants.ExtendedConfigurationElementName, agentElement);
}
}2
3
4
5
6
7
8
9
10
11
v6
Create a class that implements IAgentExtendedApiInformationAdapter<TExtended> to convert from the agent extended information object to ConfigObject. This should replace the usage of old class implementation of IAgentExtendedApiInformationToConfigElement<TExtended>
public class ExampleAgentExtendedApiInformationAdapter : IAgentExtendedApiInformationAdapter<ExampleAgentExtendedApiInformation>
{
public IConfigObject Transform(ExampleAgentExtendedApiInformation sourceValue)
{
IConfigObject configObject = new ConfigObject(ExampleConfigConstants.LatestItemObjectVersion );
configObject.Set(ExampleConfigConstants.ThingValue, sourceValue.Thing);
return configObject;
}
}
public static ExampleConfigConstants
{
/// Latest version for the item object.
public static readonly Version LatestItemObjectVersion = new Version(1, 0);
...
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Connectors
v5.3
public class ExampleConnectorExtendedApiInformationAdapter : IConnectorExtendedApiInformationToConfigElement<microsoft365groupconnectorextendedapiinformation>
{
public XElement Transform(Microsoft365GroupConnectorExtendedApiInformation sourceValue)
{
var connectorElement = new XElement(
ExampleConstants.CountValueElementName);
return new XElement(ExampleConstants.ExtendedConfigurationElementName, connectorElement);
}
}2
3
4
5
6
7
8
9
v6
Create a class that implements IConnectorExtendedApiInformationAdapter<TExtended> to convert from the connector extended information object to ConfigObject. This should replace the usage of old class implementation of IConnectorExtendedApiInformationToConfigElement<TExtended>
public class ExampleConnectorExtendedApiInformationAdapter : IConnectorExtendedApiInformationAdapter<ExampleConnectorExtendedApiInformation>
{
public IConfigObject Transform(ExampleConnectorExtendedApiInformation sourceValue)
{
IConfigObject configObject = new ConfigObject(ExampleConfigConstants.ConnectorExtendedVersion);
configObject.Set(ExampleConfigConstants.CountValue, sourceValue.Count);
return configObject;
}
}
public static ExampleConfigConstants
{
/// Latest version for the item object.
public static readonly Version LatestItemObjectVersion = new Version(1, 0);
...
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Legacy Extended Configuration Adapter
This class will be responsible for converting the legacy XML configuration to ConfigObject format that is used in v6
Agent
To create a legacy extended configuration adapter for converting legacy XML agent extended configuration to config object, create a new class that implements the IAgentLegacyExtendedConfigurationAdapter
public class ExampleAgentLegacyExtendedConfigurationAdapter : IAgentLegacyExtendedConfigurationAdapter
{
private const string DefaultThing = "abc";
public IConfigObject Transform(XElement sourceValue)
{
XElement? thingElement = sourceValue.Element(ExampleConfigConstants.Legacy.ThingElementName);
string thingValue = thingElement is not null
? thingElement.AttributeValue(ExampleConfigConstants.Legacy.ValueAttributeName, DefaultThing)
: DefaultThing;
// secure string values extraction
string encryptedPassword = thingElement.AttributeValue(ExampleConstants.PasswordAttribute);
IConfigValue<string> passwordValue = SecureConfigString.Create(encryptedPassword, alreadySecure: true);</string>
// Objects created by legacy configuration adapters should always use this version property.
var configObject = new ConfigObject(ExtensibilityHelper.ExtensibilityAdapterObjectVersion);
configObject.Set(ExampleConfigConstants.ThingValue, thingValue);
configObject.Set(ExampleConfigConstants.PasswordValue , passwordValue);
return configObject;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Connector
To create a legacy extended configuration adapter for converting legacy XML connector extended configuration to ConfigObject, create a new class that implements the IConnectorLegacyExtendedConfigurationAdapter
public class ExampleConnectorLegacyExtendedConfigurationAdapter : IConnectorLegacyExtendedConfigurationAdapter
{
public IConfigObject Transform(XElement sourceValue)
{
int count = sourceValue.AttributeIntegerValue(ExampleConfigConstants.Legacy.CountAttributeName);
var configObject = new ConfigObject(ExtensibilityHelper.ExtensibilityAdapterObjectVersion);
configObject.Set(ExampleConfigConstants.CountValue, count);
return configObject;
}
}2
3
4
5
6
7
8
9
10
11
12
13