Custom processors for response visualizations.

Using the "Scripts" option in the post processor settings allows the user to inject custom C# code that will process the incoming data.

These custom C# routines should be relatively short and execute quickly.

The C# you provide will be compiled on the fly and loaded into a separate Application Domain for security reasons. These domains are stored and not destroyed after use, as creating and destroying them is a very costly operation. As such, compilation is not performed every time a consumer asks for processed data.

On this page:

External code framework

Any code you write will be put inside a hard coded execution framework. This means that the script you write isn't a full blown C# application, but simply a body for one of the methods.

External code framework
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Tachyon.Server.Data.Models;
public class Processor
	public static string Process(IEnumerable<Response> responses)
		// your code goes here

Script code

Whatever you put in the script field will be used as a body of the Process method as seen above.

This method is fed a collection of response objects. Each response, amongst other fields, has a Values dictionary where you can find all the columns defined in the instruction definition's schema.

Response Class (other properties omitted for brevity)
namespace Tachyon.Server.Common.Models
    using System;
    using System.Collections.Generic;
    public class Response
        public Dictionary<string, object> Values { get; set; }


You can use basic .NET libraries to do the processing but any resource-intensive or lengthy operations are strongly discouraged.

Your code should return a string that contains JSON that your chosen visualization uses to take the data in, as no further processing will happen. What your code return will be sent to the external consumer, which is most likely to be Javascript charting / visualization engine in Explorer.

Loaded Assemblies

Following assemblies are loaded into the script execution AppDomain

  • mscorlib.dll

  • System.dll

  • System.Core.dll

  • Microsoft.Csharp.dll

  • System.Data.dll

  • System.Xml.dll

  • System.Data.DataSetExtensions.dll

  • Newtonsoft.Json.dll
  • Tachyon.Server.Common.dll
  • Tachyon.Server.Data.dll

Using Types

The template class comes with a number using statements to import namespaces. If any type defined in those namespaces is used, they do not need to be addressed with fully qualified name. For example, if someone is trying to use Convert  class defined in System namespace, this can be addressed just with Convert (Convert.ToString(....)). However, if someone wants to use a type defined in the loaded assemblies but not defined in imported namespaces they need to be referenced with a fully qualified name. For example, any reference to XmlTextReader would have to be System.Xml.XmlTextReader.

Sample processor

Below you'll find JSON configuration for a processor that uses custom processor on results gathered from an instruction that has aggregation schema with 3 columns: "Sum", "Count" and "ProcessName".

Example configuration
    "Name": "default",
    "TemplateConfigurations": [{
        "Id": "leftpie",
        "Title": "Average CPU percentage usage across devices",
        "Type": "Column",
        "X": "ProcessName",
        "Y": "Average",
        "PostProcessor": "processingFunction",
        "Size": 1,
        "Row": 1
    "PostProcessors": [{
        "Name": "processingFunction",
        "Script": "var xaxis = \"ProcessName\";
                var yaxis = \"Average\";
                var items = responses.Select(r => { var obj = new JObject(); obj.Add(xaxis, Convert.ToString(r.Values[\"ProcessName\"])); obj.Add(yaxis, (Convert.ToInt64(r.Values[\"Sum\"]) / Convert.ToInt64(r.Values[\"Count\"]))); return obj; }).ToList();
                var result = new JObject();
                result.Add(\"Name\", \"Average CPU Usage (%)\");
                result.Add(\"Total\", 0);
                result.Add(\"Items\", JToken.FromObject(items));
                var cake = new List<JObject>();
                return JsonConvert.SerializeObject(cake);"