---
id: scripting-csharp
title: "C# script"
summary: "Write a step in C#. The class body you write, Next and NextAsync, singleton and async options, NuGet packages, the C# shared script for code used across the flow, and debugging."
audience: user
keywords: "c#, csharp, script, Execute, ExecuteAsync, Next, NextAsync, singleton, async, nuget, shared script, ViaServices, roslyn"
---
# C# script

The **C# script** component runs your C# code for every record that reaches it. The code is compiled into the flow
with the rest of the flow's code, so it runs at the speed of compiled .NET and can use any NuGet package.

## What you write

You write the body of a class. Connect the input and output first, then open the editor: the template is generated
from the connections and already has the right types.

```csharp
public override void Execute(IMetaData metaDataInstance, IViaType inputDataInstance)
{
    var metaData = (viauser.FlowMetaData)metaDataInstance;
    var input = (Customer)inputDataInstance;
    var output = new CustomerDto();
    Next(metaData, output);
}
```

`viauser` is the flow's namespace, `Customer` the type of the input connection and `CustomerDto` the type of the
output connection. Add fields, properties and helper methods next to `Execute` as you need them.

`using` statements can go anywhere in the script; they are moved to the top before compiling. `System`, `System.Linq`,
`System.Text`, the collections and tasks namespaces, the Viaducta type system and the flow's namespace are already
imported.

## Sending records on

`Next(metaData, output)` sends a record to the components connected to `Output`.

- Call it once to transform a record.
- Call it several times to split one record into many.
- Don't call it to filter the record out.

Pass an object of the output connection's type. Every flow type is a C# class, so `new CustomerDto()` creates one.

## Options

| Option | Default | What it does |
|---|---|---|
| **Singleton** | on | One instance of your class serves all records, so fields keep their values between records. Turn it off to get a new instance per record. |
| **Async/Await** | off | Your class implements `ExecuteAsync` and sends records with `await NextAsync(...)`. Use it when the script calls asynchronous APIs. |

A singleton instance serves records in parallel. Keep its fields thread-safe (`Interlocked`, `ConcurrentDictionary`) or
use local variables.

When you switch **Async/Await**, change the method yourself or clear the script to regenerate the template:

```csharp
public override async Task ExecuteAsync(IMetaData metaDataInstance, IViaType inputDataInstance)
{
    var metaData = (viauser.FlowMetaData)metaDataInstance;
    var input = (Customer)inputDataInstance;
    await Task.Delay(100, Services.CancellationToken);
    await NextAsync(metaData, input);
}
```

## Flow services

The `Services` property gives your code logging, settings, storage, assets, batches and the rest of the
[flow services](./services):

```csharp
var apiUrl = Services.Settings.Get("Crm", "ApiUrl");
Services.Log.Information($"Calling {apiUrl}", metaData);
Services.Messaging.UpdateStatusMessage($"Last: {input.Email}");
```

Keep secrets out of the script. Store them in an expression settings package and read them with `Services.Settings`.

## NuGet packages

Add packages in the flow properties: **References** → **Add** → **Nuget package (C#)**. Every C# script, shared script
and decision condition of the flow can use them.

## Editor and debugger

The C# editor gives you completion, hover help and compile errors as you type. Press **F6** to compile the whole flow.

To debug, start the flow with **Debug** (Ctrl+F5), then click the margin of a line to set a breakpoint. When a record
reaches it the flow pauses and the watch window shows the variables. Step with F10, F11 and Shift+F11; continue with
F5.

## Errors

An exception goes to the flow's error handling, like an error in any other component. To report an error and carry on
with the next record, catch it and call `await Services.HandleExceptionAsync(metaData, input, ex)`.

## C# shared script

The **C# shared script** component holds code the whole flow uses: helper classes, extension methods, clients. It
has no pins and processes no records. Place it anywhere on the canvas.

You write a complete C# file. The template has the flow's namespace and a class marked with the component's
`[ViaScript]` attribute:

```csharp
using System;
using System.Linq;
using Viaducta.Plugin.Design;
using Viaducta.Plugin.Design.Scripting;

namespace viauser
{
    [ViaScript("3f1d...")]
    public class MySharedScript_1
    {
        [ViaServices]
        public static IFlowService Services { get; set; }

        public static string NormalizePhone(string phone)
        {
            var digits = new string((phone ?? "").Where(char.IsDigit).ToArray());
            Services?.Log.Verbose($"Normalized {phone} to {digits}");
            return digits;
        }
    }
}
```

Call it from any C# script of the flow:

```csharp
output.Phone = MySharedScript_1.NormalizePhone(input.Phone);
```

- To use the flow services, declare a `public static IFlowService` property marked `[ViaServices]` or named
  `Services` in the class with the `[ViaScript]` attribute. The flow fills it at start.
- Static members are shared by every component that uses them; keep them thread-safe.
- When you copy a shared script component, rename the class so the flow doesn't get the same class twice.
