OAS Data API Examples

The following examples demonstrate how to read and write Tag values using the Data class. The examples include both an asynchronous (non-blocking) and a synchronous approach.

Asynchronous

The asynchronous approach allows you to read and write Tag values without blocking.

Tag reading is performed using an observer style pattern where you subscribe to the Tags you want to monitor and the ValuesChangedAll event will fire to let you know when a Tag value has changed.

Note that you should not block the ValuesChangedAll event for long periods. If you are processing a continuous stream of Tag value changes it may be beneficial to add a queue to the client side and queue the Tag value changes to minimize the work performed in the ValuesChangedAll event handler.

When writing Tags asynchronously your writes will be queued in the OAS engine and the write function will return. This does not guarantee that the write has completed or that it was successful, but it will be retried and handled by OAS automatically.

Read Tag values

This example shows how to subscribe to the ValuesChangedAll event and then use the AddTag and AddTags methods to add Tags to be monitored. The event handler will be called each time a Tag value update is received.

using OASData;

class Program
{
    private static readonly ManualResetEventSlim ExitEvent = new(false);

    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Subscribe to OAS value change events
        oasData.ValuesChangedAll += OasData_ValuesChangedAll;

        // Start monitoring the Random Tag value
        oasData.AddTag("Random.Value");
        
        // Add multiple Tags at the same time to be monitored
        oasData.AddTags(["Ramp.Value", "Sine.Value"]);

        // Handle Ctrl-C or SIGTERM gracefully
        Console.CancelKeyPress += (sender, e) =>
        {
            Console.WriteLine("Ctrl-C pressed. Exiting...");
            e.Cancel = true;
            ExitEvent.Set();
        };
        
        Console.WriteLine("Listening for data changes. Press Ctrl-C to exit.");

        // Wait here until Ctrl-C is pressed
        ExitEvent.Wait();

        // Cleanup
        oasData.Dispose();
        Console.WriteLine("Application stopped.");
    }

    static void OasData_ValuesChangedAll(string[] Tags, object[] Values, bool[] Qualities, DateTime[] TimeStamps)
    {
        Console.WriteLine("Values Changed Event Triggered:");
        for (int i = 0; i < Tags.Length; i++)
        {
            Console.WriteLine($"Tag: {Tags[i]}, Value: {Values[i]}, Quality: {Qualities[i]}, Timestamp: {TimeStamps[i]}");
        }
    }
}

Output:

Listening for data changes. Press Ctrl-C to exit.
Values Changed Event Triggered:
Tag: Sine.Value, Value: 0.9510565162951535, Quality: True, Timestamp: 10/22/2025 10:46:48 AM
Tag: Random.Value, Value: 99, Quality: True, Timestamp: 10/22/2025 10:46:48 AM
Tag: Ramp.Value, Value: 8, Quality: True, Timestamp: 10/22/2025 10:46:48 AM
Values Changed Event Triggered:
Tag: Ramp.Value, Value: 9, Quality: True, Timestamp: 10/22/2025 10:46:49 AM
Tag: Random.Value, Value: 29, Quality: True, Timestamp: 10/22/2025 10:46:49 AM
Tag: Sine.Value, Value: 0.913545457642601, Quality: True, Timestamp: 10/22/2025 10:46:49 AM
Values Changed Event Triggered:
Tag: Ramp.Value, Value: 10, Quality: True, Timestamp: 10/22/2025 10:46:50 AM
Tag: Random.Value, Value: 84, Quality: True, Timestamp: 10/22/2025 10:46:50 AM
Tag: Sine.Value, Value: 0.8660254037844386, Quality: True, Timestamp: 10/22/2025 10:46:50 AM
Values Changed Event Triggered:
Tag: Ramp.Value, Value: 11, Quality: True, Timestamp: 10/22/2025 10:46:51 AM
Tag: Random.Value, Value: 90, Quality: True, Timestamp: 10/22/2025 10:46:51 AM
Tag: Sine.Value, Value: 0.8090169943749475, Quality: True, Timestamp: 10/22/2025 10:46:51 AM

Write Tag values

This example shows how to write a Tag value asynchronously. The OAS Data API will automatically queue the Tag values to be written so this is a non-blocking call.

Tag value updates will be sent via the ValuesChangedAll event.

using OASData;

class Program
{
    private static readonly ManualResetEventSlim ExitEvent = new(false);

    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Subscribe to OAS value change events
        oasData.ValuesChangedAll += OasData_ValuesChangedAll;

        string[] tags = ["MyTag.Value"];
        object[] values = [123];

        // Start monitoring a Tag value
        oasData.AddTags(tags);
        
        // Handle Ctrl-C or SIGTERM gracefully
        Console.CancelKeyPress += (sender, e) =>
        {
            Console.WriteLine("Ctrl-C pressed. Exiting...");
            e.Cancel = true;
            ExitEvent.Set();
        };

        Console.WriteLine("Listening for data changes. Press Ctrl-C to exit.");
        Console.WriteLine();

        Thread.Sleep(2000);
        
        Console.WriteLine("Writing Tag values");

        for (var i = 0; i < tags.Length; i++)
            Console.WriteLine($"{tags[i]}={values[i]}");

        // Write tag values
        oasData.WriteTags(tags, values);

        Console.WriteLine();

        // Wait here until Ctrl-C is pressed
        ExitEvent.Wait();

        // Cleanup
        oasData.Dispose();
        Console.WriteLine("Application stopped.");
    }

    static void OasData_ValuesChangedAll(string[] Tags, object[] Values, bool[] Qualities, DateTime[] TimeStamps)
    {
        Console.WriteLine("Values Changed Event Triggered:");
        for (int i = 0; i < Tags.Length; i++)
        {
            Console.WriteLine($"Tag: {Tags[i]}, Value: {Values[i]}, Quality: {Qualities[i]}, Timestamp: {TimeStamps[i]}");
        }
        Console.WriteLine();
    }
}

Output:

Listening for data changes. Press Ctrl-C to exit.

Values Changed Event Triggered:
Tag: MyTag.Value, Value: 0, Quality: True, Timestamp: 10/23/2025 2:31:57 PM

Writing Tag values
MyTag.Value=123

Values Changed Event Triggered:
Tag: MyTag.Value, Value: 123, Quality: True, Timestamp: 10/23/2025 2:32:04 PM

Ctrl-C pressed. Exiting...
Application stopped.

Synchronous

In the synchronous approach, the read and write methods will not return until all reads from and writes to the Tag and associated connectors has been completed. This is useful when you want to ensure that the operation has been completed and you cannot continue until it has.

This API also supports read after write confirmation to check that a write operation has been successful.

Read Tag values

This example shows how to perform a synchronous read to read multiple tag values. It also demonstrates how an invalid Tag will return a different error result code.

using OASData;

class Program
{
    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Define Tags to be read
        string[] tags = ["Random.Value", "Ramp.Value", "Sine.Value", "InvalidTag"];

        // Define result message variables
        int[] errorResults = new int[tags.Length];

        // Read Tag values
        var values = oasData.SyncReadTags(tags, ref errorResults);

        Console.WriteLine("Received Tag Values:");
        for (var i = 0; i < tags.Length; i++)
        {
            if (errorResults[i] == 0)
            {
                Console.WriteLine($"Tag: {tags[i]}, Value: {values[i]}, Result: {errorResults[i]}");
            }
            else
            {
                Console.WriteLine($"Tag: {tags[i]}, Error reading tag, Result: {errorResults[i]}");
            }
        }

        Console.WriteLine();
        Console.WriteLine("Press Return key to continue...");
        Console.ReadLine();

        oasData.Dispose();
    }
}

Output:

Received Tag Values:
Tag: Random.Value, Value: 79, Result: 0
Tag: Ramp.Value, Value: 58, Result: 0
Tag: Sine.Value, Value: 0.20791169081775931, Result: 0
Tag: InvalidTag, Error reading tag, Result: 1

Press Return key to continue...

Write Tag values

This example shows how you can write a single Tag value. To write multiple Tag values simply add more Tags to the tags array and corresponding values to the values array.

To demonstrate that the write was successful, this example first reads and outputs the values of the tags, then writes the new values and finally reads and outputs the values again.

Note that the OAS engine will return a result once a write has been successfully queued internally, but if you read a value immediately after calling SyncWriteTags the value may not yet have stabilized. Use a short Thread.Sleep to ensure the new value will be available or use the SyncWriteTagsWithConfirmation method shown in the next example.

using OASData;

class Program
{
    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Define Tags to be read and written
        string[] tags = ["MyTag.Value"];
        object[] values = [123];

        // Define result message variables
        var errorResults = new int[tags.Length];

        // Read Tag values
        Console.WriteLine("Reading Tag Values:");
        var result = oasData.SyncReadTags(tags, ref errorResults);
        for (var i = 0; i < tags.Length; i++)
            Console.WriteLine($"{tags[i]}={result[i]}");

        Console.WriteLine();

        Console.WriteLine("Writing Tag Values:");
        // Write new Tag value
        for (var i = 0; i < tags.Length; i++)
            Console.WriteLine($"{tags[i]}={values[i]}");

        oasData.SyncWriteTags(tags, values);

        // Allow the OAS engine values to stabilize
        Thread.Sleep(50);

        Console.WriteLine();

        Console.WriteLine("Reading Tag Values:");
        // Read Tag value again to confirm
        result = oasData.SyncReadTags(tags, ref errorResults);
        for (var i = 0; i < tags.Length; i++)
            Console.WriteLine($"{tags[i]}={result[i]}");

        Console.WriteLine();
        Console.WriteLine("Press Return key to continue...");
        Console.ReadLine();

        oasData.Dispose();
    }
}

Output:

Reading Tag Values:
MyTag.Value=123

Writing Tag Values:
MyTag.Value=123

Reading Tag Values:
MyTag.Value=123

Press Return key to continue...

Write Tag values with confirmation

In this example the OAS Data API will write a Tag value and the perform a read to check that the value was successfully written.

By default, the confirmation must succeed within 10 seconds and if the value is a floating point number it must be within a deadband of 0.0001. To customize the timeout and deadband you can provide the Timeout and FloatDeadband arguments.

using OASData;

class Program
{
    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Define Tags to be read and written
        string[] tags = ["MyTag.Value", "InvalidTag"];
        object[] values = [123, 0];
        
        // Write new Tag value
        var results = oasData.SyncWriteTagsWithConfirmation(tags, values);

        for (var i = 0; i < tags.Length; i++)
        {
            var resultMessage = results[i] switch
            {
                0 => "Success",
                1 => "OAS not reachable",
                2 => "Failed to write Tag",
                3 => "Tags and Values array must be the same length",
                _ => "Unknown error",
            };
            Console.WriteLine($"Tag: {tags[i]}, Value: {values[i]}, Result: {resultMessage}");
        }

        Console.WriteLine();
        Console.WriteLine("Press Return key to continue...");
        Console.ReadLine();

        oasData.Dispose();
    }
}

Output:

Tag: MyTag.Value, Value: 123, Result: Success
Tag: InvalidTag, Value: 0, Result: Failed to write Tag

Press Return key to continue...

Write Tag values with result

This example demonstrates the WriteTagsWithResults method for writing Tag values synchronously and waiting for a result for each Tag value. If there is a failure, the result provides a detailed reason for the failure.

This method also supports passing timestamps as a DateTime array.

using OASData;

class Program
{
    static void Main()
    {
        var oasData = new Data();

        // Login to OAS
        oasData.LogIn("api", "api_password");

        // Define Tags to be read and written
        string[] tags = ["MyTag.Value"];
        object[] values = [123];

        // Write new Tag value
        var results = oasData.WriteTagsWithResults(tags, values);

        for (var i = 0; i < tags.Length; i++)
        {
            var resultMessage = results[i] switch
            {
                0 => "Success",
                1 => "Service Not Reachable",
                2 => "OAS Version Needs to be Updated",
                3 => "Function Not Supported with Legacy .NET Remoting",
                4 => "Function Not Supported with Classic TCP",
                5 => "OAS Engine Not in Runtime",
                6 => "Timeout",
                7 => "Invalid Security",
                8 => "Tag Does Not Exist",
                9 => "Invalid Tag Parameter",
                10 => "Internal Exception",
                11 => "Tag is Read Only",
                12 => "Out of Range",
                13 => "Bad Quality",
                14 => "Skipped Due To Write Latest Value Only",
                15 => "Write to Driver Interface Invalid Source",
                16 => "Null Value Not Allowed",
                17 => "Previous Value of Integer Not Available for Bit Write",
                18 => "Memory Type Not Writable",
                19 => "Value of False Disabled Write",
                20 => "Failure",
                21 => "Invalid Address",
                22 => "Invalid License",
                23 => "Offline or Not In Runtime",
                24 => "Tag Parameter Not Writable",
                25 => "Invalid Driver Interface",
                _ => "Unknown error",
            };
            Console.WriteLine($"Tag: {tags[i]}, Value: {values[i]}, Result: {resultMessage}");
        }

        Console.WriteLine();
        Console.WriteLine("Press Return key to continue...");
        Console.ReadLine();

        oasData.Dispose();
    }
}

Output:

Tag: MyTag.Value, Value: 123, Result: Success

Press Return key to continue...