Implementing New Connection Interceptor
Connection interceptor extension point allows to modify every ERP request and response:
add, remove or replace incoming parameters or result XML nodes. Sana defines two base classes for this:
synchronous ConnectionExtension (covered in more detail in this article) and its asynchronous version AsyncConnectionExtension
(see an example in Async connection extension listing).
From this article you will learn how to create custom connection interceptor extension. As example, we will create (simplified) extension which classify products on Sana side.
Start with a new project
Create a new add-on project named "Sana.ProductClassifier" as described in the add-on development tutorial.
Create the extension class
Create a new class ProductClassifierExtension inherited from ConnectionExtension.
public class ProductClassifierExtension : ConnectionExtension
{
}
Implement ExecuteRequest method
ExecuteRequest is the only required method of ConnectionExtension class.
It is a proxy method between Sana and ERP (or another connection extension).
The simplest implementation will looks like this:
/// <param name="operation">The ERP operation name.</param>
/// <param name="parameters">The request parameters.</param>
/// <param name="execute">The original request execution method which can be called to send the request to the ERP.</param>
public override XDocument ExecuteRequest(string operation, IList<XElement> parameters, ExecuteRequestMethod execute)
{
return execute(operation, parameters);
}
In this implementation we just pass request parameters further through pipeline (by calling execute(operation, parameters))
and return result from ERP/extension.
Modify 'GetEntityFields' response
In order to be able to use new product field Sana should previously receive information about this field
from the 'GetEntityFields' request with <Table>Product</Table> parameter.
You can find more information about all ERP requests (including those used in this tutorial) in our eBusiness Connector documentation.
public override XDocument ExecuteRequest(string operation, IList<XElement> parameters, ExecuteRequestMethod execute)
{
if (operation.Equals("GetEntityFields", StringComparison.Ordinal) && parameters.Any(param => param.Name.LocalName == "Table" && param.Value == "Product"))
return InterceptGetEntityFields(parameters, execute);
return execute(operation, parameters);
}
Here we will process GetEntityFields request called to get fields of the 'Product' entity.
Now lets check InterceptGetEntityFields method implementation where we will add new "Custom_Class" field to the response.
const string ClassFieldName = "Custom_Class";
const string EntityField = "<Field>" +
"<field name=\"Name\" value=\"" + ClassFieldName + "\"/>" +
"<field name=\"Caption\" value=\"Discovered class\"/>" +
"<field name=\"Type\" value=\"String\"/>" +
"</Field>";
protected virtual XDocument InterceptGetEntityFields(IList<XElement> parameters, ExecuteRequestMethod execute)
{
var document = execute("GetEntityFields", parameters);
XElement resultNode = GetResultNode(document);
// Add our new field only in case of successful ERP response.
if (resultNode != null && resultNode.HasElements)
resultNode.Add(XElement.Parse(EntityField));
return document;
}
XElement GetResultNode(XDocument document) => document.Root.Element("Result");
Now, after 'General information import' run Sana administrator can choose added "Discovered class" field on the 'Keyword fields' page.

Note
Adding it to keyword/filter fields will fail product import since ERP doesn't know anything about our "Custom_Class". To prevent this you should also now intercept 'GetProducts' ERP calls.
Intercept 'GetProducts' request
It is time to extend out ExecuteRequest method to intercept 'GetProducts' request to remove "Custom_Class" from request parameters.
public override XDocument ExecuteRequest(string operation, IList<XElement> parameters, ExecuteRequestMethod execute)
{
if (operation.Equals("GetEntityFields") && parameters.Any(param => param.Name.LocalName == "Table" && param.Value == "Product"))
return InterceptGetEntityFields(parameters, execute);
// Add the 2 following lines
if (operation.Equals("GetProducts", StringComparison.Ordinal))
return InterceptGetProducts(parameters, execute);
return execute(operation, parameters);
}
protected virtual XDocument InterceptGetProducts(IList<XElement> parameters, ExecuteRequestMethod execute)
{
var fieldsNode = parameters.FirstOrDefault(e => e.Name.LocalName == "ExtraFields");
var classField = fieldsNode?.XPathSelectElement(ClassFieldXPath);
if (classField == null)
return execute("GetProducts", parameters);
// Prevent ERP error on not found field.
classField.Remove();
var document = execute("GetProducts", parameters);
// [Optional step] Restore original parameters state.
fieldsNode.Add(classField);
return document;
}
We've added interceptor method which removes our field (if it is present) from list of <ExtraFields>
nodes before calling execute("GetProducts", parameters).
Add custom field to 'GetProducts' response
The last thing which we should implement in our example is to iterate over <Product> result nodes and add "Custom_Class" field:
protected virtual XDocument InterceptGetProducts(IList<XElement> parameters, ExecuteRequestMethod execute)
{
...
var document = execute("GetProducts", parameters);
XElement resultNode = GetResultNode(document);
if (resultNode != null && resultNode.HasElements)
{
foreach (var product in resultNode.Elements("Product"))
{
// Assume GetClass method is some ML-based algorithm or advanced text search function.
var classText = GetClass(product);
var txt = "<field name=\"" + ClassFieldName + "\" value=\"" + classText + "\"/>";
product.Add(XElement.Parse(txt));
}
}
fieldsNode.Add(classField);
return document;
}
Complete listing
You can check full listing of ProductClassifierExtension including primitive implementation of GetClass method in
this listing.
Check the result
Now when *"Custom_Class" is configured as filter field and products are re-indexed Sana can use this new field to create product set, for example.

Next steps
After the extension is implemented, follow the regular add-on development guides:
- Test the implemented extension
- Assemble the add-on package
- Ensure that the package has been correctly assembled
See also
- Extension configuration - To make your extension more flexible, set-up some credentials or parameters.
- How-to develop an add-on
- Extension.Api reference
- NextAction reference