Custom Code Device

Custom Code Device

The Custom Code Device is a wrapper around the Custom Code Control with an API for message processing. It is best suited for prototyping and one-off solutions, and can be converted into a Compiled Custom Device.

The Custom Code Control and Custom Devices/Plugins is covered in depth in the Extensibility section.

The API exposed by the Custom Code Device is also used when building fully compiled devices - with some minor exceptions. The four main functions are:

Start(): Called when the device and channel start. You can initialize any class-level variables and perform quick operations (No long-running operations should be called).

Stop(): Called when the device and channel stop. Clean up any variables and resources.

ProcessMessageAsync(IMessageContext context): Add your message processing logic here. Access the current message and metadata via the context parameter. Use async/await wherever possible.

OnError(…): Handle any exceptions thrown during message processing, and optionally specify a retry policy and log output. Generally, you should only retry if the error is transient (ie, a temporarily unavailable resource).

Here is a contrived example of a custom code class which takes a URI (a string) as the inbound message and downloads the content as the outbound message. In this example, we’re simply using an HttpClient to demonstrate initialization in Start() and cleanup in Stop(). Note that Stop() can be called without a corresponding Start - so you must check for null in Stop.

using System; using System.Threading; using Connexion.Core; using System.Threading.Tasks; using System.Net.Http; namespace Connexion.Device { [ClientRunnable(true)] public partial class CustomDevice : BaseCustomDevice { private HttpClient _HttpClient; public override void Start() { _HttpClient = new HttpClient(); } public override void Stop() { _HttpClient?.Dispose(); } public override async Task ProcessMessageAsync(IMessageContext context, CancellationToken token) { if(context.Message is not string url) throw new Exception($"Only string messages are supported (received {context.Message.GetType().FullName})"); if(!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uriToDownload)) throw new Exception($"Couldn't parse '{url}' into a Uri"); if(uriToDownload.IsFile || uriToDownload.IsLoopback || uriToDownload.IsUnc) throw new Exception("Unsupported Uri type"); var content = await _HttpClient.GetStringAsync(uriToDownload).ConfigureAwait(false); context.Message = content; } public override void OnError(IMessageContext context, Connexion.Core.ErrorEventArgs args) { if(args.Exception is not HttpRequestException httpException) { // don't retry anything that isn't an HTTP exception args.ShouldRetry = false; return; } if (args.TotalRetries > 0 && args.TotalRetries % 2 == 0) Logger.Write(EventSeverity.Error, "Unable to download (retry {0}): {1}", args.TotalRetries, args.Exception.Message); // wait before trying to process again args.SleepTime = TimeSpan.FromSeconds(args.TotalRetries > 2 ? 30 : 5); } } }

The ProcessMessageAsync method does a few sanity checks on the incoming string, and then downloads the content and sets the context.Message to the downloaded content.

The OnError method determines the error behavior. In this case, we’re only retrying if the exception is an HttpRequestException. In reality, you’d need to narrow the exceptions down to only retryable ones - network connectivity or invalid certificates, for example.

image-20250916-003110.png

The Custom Code Device adds a Run Transform tab to the bottom of the Custom Code Control. Like many other devices, this tab displays the currently selected message from the upstream queue on the left.

If your device class is marked with the [ClientRunnable(true)] attribute, you can run your custom code from directly within the UI, and see the result in the Out window. This can be dangerous as your code will be executed - any writing of files, database access, etc. will occur. You should only use this attribute if running your custom code device does not have any ill effects.

image-20250916-003715.png

As covered in the Extensibility sections, there is much more functionality available to you within the Custom Code Device as well as fully compiled devices.