Commerce Connector Custom Processor Developer Guide

TABLE OF CONTENTS

1. Overview

Custom Processor Extensibility allows developers to execute custom business logic during Commerce Connector transmission execution.

Custom processors are developed externally in a Custom API project by referencing the Commerce Connector SDK and implementing the IBaseProcessor interface. A processor can execute custom logic before or after a transmission step, validate data, enrich execution results, modify output data, and integrate with platform services through Dependency Injection.

Once developed, the processor assembly is deployed using the CLI deploy extension command. After deployment, the processor can be configured and used within Commerce Connector transmission workflows.


2. How to Use Custom Processor Extensibility

2.1 Create a New Custom Processor Class

Custom processors should be created in a separate class library project within the Custom API solution. This keeps custom processing logic isolated from the main application code.

A suitable project name can be used based on the implementation or client requirement.

Examples

  • Custom.Libraries.DataExchange
  • Znode.Libraries.DataExchange.Custom
  • <ClientName>.DataExchange.Custom

The custom processor project must reference the Commerce Connector SDK package.

To create a new processor, add a new class and implement the IBaseProcessor interface.

Example

using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Znode.Libraries.CommerceConnector.SDK;
using Znode.Libraries.Common.Logger;

namespace Custom.Libraries.DataExchange
{
    public class DummyMultiStepProcessor : IBaseProcessor
    {
        protected readonly IServiceProvider _serviceProvider;
        private readonly IZnodeLogging _znodeLogging;

        public DummyMultiStepProcessor(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            _znodeLogging = _serviceProvider.GetService<IZnodeLogging>();
        }

        public async Task BeforeStepAsync(
            List<TransmissionStepModel> context,
            TransmissionStepModel step,
            List<TransmissionStepExecutionOutput> executionOutputs)
        {
            await Task.CompletedTask;
        }

        public async Task AfterStepAsync(
            List<TransmissionStepModel> context,
            TransmissionStepModel step,
            List<TransmissionStepExecutionOutput> executionOutputs)
        {
            await Task.CompletedTask;
        }
    }
}

2.2 Add Logging in a Custom Processor

Custom processors can write logs using IZnodeLogging.

The logger can be resolved using Dependency Injection through the provided IServiceProvider.

Example

public DummyMultiStepProcessor(IServiceProvider serviceProvider)
{
    _serviceProvider = serviceProvider;
    _znodeLogging = _serviceProvider.GetService<IZnodeLogging>();
}

Writing logs

_znodeLogging.LogMessage(
    "DummyMultiStepProcessor called",
    "DummyMultiStepProcessor",
    TraceLevel.Info);

Logs can be written for:

  • Before step execution
  • After step execution
  • Validation events
  • Exception handling
  • External integrations

Example

public async Task BeforeStepAsync(
    List<TransmissionStepModel> context,
    TransmissionStepModel step,
    List<TransmissionStepExecutionOutput> executionOutputs)
{
    _znodeLogging.LogMessage(
        "Before step execution",
        "DummyMultiStepProcessor",
        TraceLevel.Info);

    await Task.CompletedTask;
}

2.3 Writing Your Processor Class

The following example demonstrates the minimum implementation required for a custom processor.

Example

public class DummyMultiStepProcessor : IBaseProcessor
{
    public async Task BeforeStepAsync(
        List<TransmissionStepModel> context,
        TransmissionStepModel step,
        List<TransmissionStepExecutionOutput> executionOutputs)
    {
        await Task.CompletedTask;
    }

    public async Task AfterStepAsync(
        List<TransmissionStepModel> context,
        TransmissionStepModel step,
        List<TransmissionStepExecutionOutput> executionOutputs)
    {
        await Task.CompletedTask;
    }
}

Rules that are non-negotiable

RuleWhy
Implement IBaseProcessorRequired for Commerce Connector to recognize the processor.
Implement BeforeStepAsync()Executed before a transmission step.
Implement AfterStepAsync()Executed after a transmission step.
Always return completed tasksEnsures the execution pipeline continues correctly.
Handle null data safelyPrevents unexpected runtime failures.
Use Dependency Injection for servicesProvides access to platform services.

2.4 Processor Lifecycle

Commerce Connector executes the custom processor as part of the transmission workflow. For every configured transmission step, the processor is invoked before and after the step execution.

Execution Flow

Transmission Execution
        │
        ▼
BeforeStepAsync()
        │
        ▼
Transmission Step Execution
        │
        ▼
AfterStepAsync()
        │
        ▼
Next Step

For every transmission step:

  1. The processor's BeforeStepAsync() method executes.
  2. The configured transmission step executes.
  3. The processor's AfterStepAsync() method executes.
  4. Execution proceeds to the next configured step.

2.5 Available Data

When a processor executes, the following information is available.

Transmission Context

The context parameter contains all transmission steps involved in the current execution.

List<TransmissionStepModel> context

Example

var totalSteps = context.Count;

Current Step

The step parameter represents the currently executing transmission step.

TransmissionStepModel step

Example

var stepCode = step.StepCode;

A common use case is to execute custom logic only for a specific transmission step.

Example

if (step.StepCode == "step13")
{
    // custom logic
}

Execution Outputs

The executionOutputs parameter contains the execution results generated during transmission processing.

List<TransmissionStepExecutionOutput> executionOutputs

Execution outputs can be:

  • Read
  • Modified
  • Extended

These outputs can be used by subsequent transmission steps during the execution workflow.


2.6 Conditional Step Processing

A custom processor can execute logic for a specific transmission step by evaluating the StepCode of the currently executing step.

Example

if (step.StepCode == "step13")
{
    Console.WriteLine("Dummy processor executed successfully.");
}

This approach allows step-specific behavior during workflow execution. Common scenarios include:

  • Product Export
  • Inventory Synchronization
  • Order Import
  • Catalog Update
  • Customer Synchronization

2.7 Modifying Step Outputs

A custom processor can add or modify execution outputs after a transmission step completes. These outputs can then be consumed by subsequent transmission steps.

Example

public async Task AfterStepAsync(
    List<TransmissionStepModel> context,
    TransmissionStepModel step,
    List<TransmissionStepExecutionOutput> executionOutputs)
{
    if (step.StepCode == "step134")
    {
        executionOutputs.Add(
            new TransmissionStepExecutionOutput
            {
                StepCode = step.StepCode,
                OutputData = "Modified after execution",
                DataFormat = "Text"
            });
    }

    await Task.CompletedTask;
}

The TransmissionStepExecutionOutput object contains the following properties:

PropertyDescription
StepCodeIdentifies the transmission step that produced the output.
OutputDataStores the output generated by the processor.
DataFormatSpecifies the format of the output data.

Example

new TransmissionStepExecutionOutput
{
    StepCode = step.StepCode,
    OutputData = "Modified after execution",
    DataFormat = "Text"
}

2.8 Using Dependency Injection

Commerce Connector supports Dependency Injection, allowing custom processors to access platform services during execution.

The IServiceProvider instance is provided through the processor constructor and can be used to resolve services as required.

Example

protected readonly IServiceProvider _serviceProvider;

public DummyMultiStepProcessor(IServiceProvider serviceProvider)
{
    _serviceProvider = serviceProvider;
}

Resolve a service using the service provider:

var logger =
    _serviceProvider.GetService<IZnodeLogging>();

Common platform services include:

  • Logging
  • Configuration access
  • Database services
  • External integrations
  • Platform services

2.9 Deploying the Extension

After developing the custom processor, deploy the extension using the Znode CLI.

Before deployment, connect to the Znode CLI using the provided authentication token.

Connect to the CLI

znode connect <token>

Deploy a specific processor project by specifying the project (.csproj) path.

Syntax

znode deploy extension "<path-to-project-csproj>"

Example

znode deploy extension
"D:\Extensions\Custom.Libraries.DataExchange\Custom.Libraries.DataExchange.csproj"

To deploy multiple extension projects, specify the parent folder that contains the projects.

Example

znode deploy extension "D:\Extensions"

The CLI automatically builds the project and uploads the generated assemblies for execution.


2.10 Registering the Processor

After deploying the custom processor, register it in the Commerce Connector configuration before using it in a transmission workflow.

Provide the following information while registering the processor:

FieldDescription
Processor NameEnter a descriptive name for the custom processor.
Class NameSpecify the fully qualified class name of the deployed processor.
DescriptionProvide a brief description of the processor.

Example

DummyMultiStepProcessor

Note: The Class Name must exactly match the deployed processor class. If the class name does not match, Commerce Connector will not be able to locate and execute the processor.


2.11 Supported Mapping Types

The Mapping Engine supports the following mapping types.

Mapping TypeDescription
Direct MappingMaps a source field directly to a destination field.
Fixed/Static Value MappingAssigns a constant value.
Default Value MappingApplies a value when the source field is empty.
Formula MappingPerforms calculations and expressions.
Conditional MappingApplies mappings based on configured conditions.
Lookup MappingMaps values using lookup definitions.
Transformation MappingTransforms data before assignment.
Processor-Based MappingUses custom processor logic during mapping.
Object MappingMaps complete object structures.
Collection MappingMaps arrays and collections.

Any mapping behavior that is not supported by the standard Mapping Engine can be implemented using a custom processor.


2.12 Best Practices

Follow these best practices when developing custom processors.

Keep Processors Lightweight

Processors execute as part of the transmission workflow. Avoid unnecessary processing to minimize execution time.

Handle Exceptions Properly

Wrap custom logic in exception handling blocks and log any exceptions using IZnodeLogging.

Example

try
{
    // custom logic
}
catch (Exception ex)
{
    _znodeLogging.LogMessage(
        ex.Message,
        "DummyMultiStepProcessor",
        TraceLevel.Error);
}

Use Step Codes for Specific Logic

Execute custom logic only for the required transmission steps by evaluating the StepCode.

Example

if(step.StepCode == "ProductExport")
{
    // execute product export logic
}

Minimize External Calls

Avoid expensive API calls or database operations inside frequently executed processors to improve overall execution performance.

Maintain Stateless Design

Processors should not depend on static variables or shared state between executions.


2.13 Limitations

The current implementation of Custom Processor Extensibility does not support the following capabilities:

  • Extension Observability Screen (custom processor administration logs are not visible)
  • Extension Sync Functionality
  • Execution Log Viewer
  • Runtime Processor Diagnostics
  • Processor Health Dashboard
  • Dedicated Troubleshooting Screen

Logging and debugging should be performed using one or more of the following:

  • Application logs
  • Platform logs written through IZnodeLogging
  • Local debugging
  • Transmission execution results

This approach keeps the current Custom Processor implementation lightweight while still providing extensibility hooks before and after Commerce Connector transmission step execution.


3. Supported Mapping Expressions

The Mapping Engine supports functions, arithmetic operations, boolean expressions, ternary operators, constants, direct field mappings, and nested JSON mappings. These expressions can be used to dynamically transform and map data during transmission execution.


3.1 Supported Expression Types

The Mapping Engine supports a rich set of expressions that enable dynamic data transformations during mapping. These expressions can be used individually or combined to build complex mapping logic.

The following expression types are supported:

  • Functions
  • Arithmetic operations
  • Boolean expressions
  • Ternary expressions
  • Constants
  • Direct field mappings
  • Nested object mappings
  • Collection mappings

3.2 Functions, Arithmetic, Boolean Logic, and Ternary Expressions

The following examples demonstrate the supported expression syntax that can be used within mappings.

# Functions, arithmetic, boolean logic, and ternary expressions.

dataAreaId: usmf

CustomerNameUpper:
{{Upper($Step2.FirstName)}}

CustomerNameLower:
{{Lower($Step2.LastName)}}

FullName:
{{Concat($Step2.FirstName," ",$Step2.LastName)}}

FirstAddressCity:
{{$Step2.AlternateAddresses[0].City}}

RoundedAmount:
{{Math.Round($Step1.Amount,2)}}

DiscountedPrice:
{{Math.Max($Step1.Price,100)}}

MappedOnDate:
{{DateTime.Today}}

CorrelationId:
{{Guid.NewGuid()}}

LineTotal:
{{$Step1.Qty * $Step1.Price}}

IsHighValue:
{{$Step1.Amount > 1000}}

CustomerTier:
{{$Step1.Amount > 1000 ? "Premium" : "Normal"}}

Greeting:
Hello {{$Step2.FirstName}}, your order total is {{Math.Round($Step1.Qty * $Step1.Price,2)}}!

3.3 Nested JSON Mapping

The Mapping Engine also supports nested JSON object mappings. This allows developers to generate structured request payloads while referencing values from previous transmission steps.

Example

{
  "dataAreaId": "usmf",
  "salesOrder": {
    "name": "{{$Step1.ClassNumber}}",
    "orderDate": "{{FormatDate(DateTime.Today,"yyyy-MM-dd")}}"
  }
}

3.4 Constants and Direct Field Mapping

Constants and direct field mappings can be combined to construct request payloads without requiring additional transformations.

Example

dataAreaId: usmf

SalesOrderName:
{{$Step1.ClassNumber}}

CustomerFirstName:
{{$Step2.FirstName}}

CustomerCity:
{{$Step2.Address.City}}

Summary

Custom Processor Extensibility enables developers to extend Commerce Connector by executing custom business logic before and after transmission step execution. By implementing the IBaseProcessor interface, developers can validate data, modify execution outputs, integrate with external systems, and leverage platform services through Dependency Injection.

The Mapping Engine complements custom processors by supporting direct mappings, transformation functions, arithmetic expressions, conditional logic, nested JSON mappings, and processor-based extensibility, enabling the implementation of complex integration scenarios with minimal customization.


3.1 Supported Expression Types

The Mapping Engine supports a rich set of expressions that enable dynamic data transformations during mapping. These expressions can be used individually or combined to build complex mapping logic.

The following expression types are supported:

  • Functions
  • Arithmetic operations
  • Boolean expressions
  • Ternary expressions
  • Constants
  • Direct field mappings
  • Nested object mappings
  • Collection mappings

3.2 Functions, Arithmetic, Boolean Logic, and Ternary Expressions

The following examples demonstrate the supported expression syntax that can be used within mappings.

# Functions, arithmetic, boolean logic, and ternary expressions.

dataAreaId: usmf

CustomerNameUpper:
{{Upper($Step2.FirstName)}}

CustomerNameLower:
{{Lower($Step2.LastName)}}

FullName:
{{Concat($Step2.FirstName," ",$Step2.LastName)}}

FirstAddressCity:
{{$Step2.AlternateAddresses[0].City}}

RoundedAmount:
{{Math.Round($Step1.Amount,2)}}

DiscountedPrice:
{{Math.Max($Step1.Price,100)}}

MappedOnDate:
{{DateTime.Today}}

CorrelationId:
{{Guid.NewGuid()}}

LineTotal:
{{$Step1.Qty * $Step1.Price}}

IsHighValue:
{{$Step1.Amount > 1000}}

CustomerTier:
{{$Step1.Amount > 1000 ? "Premium" : "Normal"}}

Greeting:
Hello {{$Step2.FirstName}}, your order total is {{Math.Round($Step1.Qty * $Step1.Price,2)}}!

3.3 Nested JSON Mapping

The Mapping Engine also supports nested JSON object mappings. This allows developers to generate structured request payloads while referencing values from previous transmission steps.

Example

{
  "dataAreaId": "usmf",
  "salesOrder": {
    "name": "{{$Step1.ClassNumber}}",
    "orderDate": "{{FormatDate(DateTime.Today,"yyyy-MM-dd")}}"
  }
}

3.4 Constants and Direct Field Mapping

Constants and direct field mappings can be combined to construct request payloads without requiring additional transformations.

Example

dataAreaId: usmf

SalesOrderName:
{{$Step1.ClassNumber}}

CustomerFirstName:
{{$Step2.FirstName}}

CustomerCity:
{{$Step2.Address.City}}

Summary

Custom Processor Extensibility enables developers to extend Commerce Connector by executing custom business logic before and after transmission step execution. By implementing the IBaseProcessor interface, developers can validate data, modify execution outputs, integrate with external systems, and leverage platform services through Dependency Injection.

The Mapping Engine complements custom processors by supporting direct mappings, transformation functions, arithmetic expressions, conditional logic, nested JSON mappings, and processor-based extensibility, enabling the implementation of complex integration scenarios with minimal customization.

Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.