OPC Studio User's Guide and Reference
Hosting OPC Wizard Servers
Concepts > OPC Wizard Concepts > Hosting OPC Wizard Servers
In This Topic

The code that implements the OPC server (using OPC Wizard) cannot just be written and built - it ultimately needs to be run, and for it it needs to be hosted in some kind of executable application. There are many hosting options; the OPC Wizard does no artificially limit them, but some are more common and practical than others. This article will specifically address certain typical hosting scenarios. However, other hosting options exist as well.

In all cases, your code needs to create an instance of the EasyUAServer Class and define its properties and populate the node space. It then needs to call the Start Method on the server object. When this happens depends on the hosting scenario. The OPC server is started, and it keeps running. At some later moment, when the server needs to be shut down, your code should call the Stop Method. The host may require additional code in order to integrate it with your server.

Console Host

Hosting the OPC Server in a console application is probably the easiest option in terms of coding effort needed to implement it; and the same time, it is also very easy to debug. There is almost no extra code necessary to make the server work inside the console application. 

If you enable Unsolicited User Interaction in the console (as in the example below), make sure that your application does not prompt for any user input of its own at the console while the server is running. The unsolicited input requests from the OPC Wizard may collide with those from your application.

The following example illustrates a fully functional OPC Wizard-based server, hosted in a console application. The server also outputs information related to the state of its endpoints, and client connections and disconnections.

// A fully functional OPC UA demo server running in a console host.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.Services;
using UAServerDemoLibrary;

namespace UAServerConsoleDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("OPC Wizard Server Console Demo");
            Console.WriteLine();

            // Enable the console interaction by the server.
            EasyUAServer.SharedParameters.PluginSetups.FindName("UAConsoleInteraction").Enabled = true;

            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            using (var server = new EasyUAServer())
            {
                // Define various nodes.
                ConsoleNodes.AddToParent(server.Objects);
                DataNodes.AddToParent(server.Objects);
                DemoNodes.AddToParent(server.Objects);

                // Hook events to the server object.
                server.EndpointStateChanged += (sender, eventArgs) =>
                    Console.WriteLine($"{nameof(server.EndpointStateChanged)}: {eventArgs}");
                server.Starting += (sender, eventArgs) => Console.WriteLine(nameof(server.Starting));
                server.Stopped += (sender, eventArgs) => Console.WriteLine(nameof(server.Stopped));

                // Obtain the server connection monitoring service.
                IEasyUAServerConnectionMonitoring serverConnectionMonitoring = server.GetService<IEasyUAServerConnectionMonitoring>();
                if (!(serverConnectionMonitoring is null))
                {
                    // Hook events to the connection monitoring service.
                    serverConnectionMonitoring.ClientSessionConnected += (sender, eventArgs) =>
                        Console.WriteLine($"{nameof(serverConnectionMonitoring.ClientSessionConnected)}: {eventArgs}");
                    serverConnectionMonitoring.ClientSessionDisconnected += (sender, eventArgs) =>
                        Console.WriteLine($"{nameof(serverConnectionMonitoring.ClientSessionDisconnected)}: {eventArgs}");
                }

                // Start the server.
                server.Start();

                // Let the user decide when to stop.
                var cancelled = new ManualResetEvent(initialState: false);
                Console.CancelKeyPress += (sender, eventArgs) =>
                {
                    // Signal the main thread to exit.
                    cancelled.Set();

                    // Prevent the process from terminating immediately.
                    eventArgs.Cancel = true;
                };

                Console.WriteLine("Press Ctrl+C to stop the server...");
                cancelled.WaitOne();

                // Stop the server.
                server.Stop();
            }
        }
    }
}

Windows Forms Host

OPC servers developed with OPC Wizard can be hosted inside a Windows desktop application developed using Windows Forms (and in fact, the application can also be developed using WPF or other tools). This hosting option provides a possibility of integrating the OPC server with rich user interface, inside the same process.

One advantage of hosting the OPC server in Windows Forms application is that it can be easily integrated with the Administer OPC UA Application Dialog.

Example: Installed Examples - Server Windows Forms - UAServerWindowsFormsDemo

Windows Service Host

Hosting your OPC server in a Windows service is meant mainly for "head-less", fully automated operations. The service has several advantages over other hosting options, The service can be started and stopped in various ways provided by the operating system, and it can even start together with the operating system. The service can operate without any interactive user being logged in, and it can be configured to run under a specific user account. See e.g. the ServiceBase Class documentation for more information on developing Windows Services in this way.

Windows Services developed in this way, i.e. with the use of ServiceBase Class, represent the "old" way of developing service-like applications in .NET. This approach is available in .NET Framework. In new projects and in .NET 6+, it is recommended to use the Worker Service approach, described further below.

Example: Installed Examples - Server Windows Service - UAServerWindowsServiceDemo

Worker Service Host

The "worker service" (Worker services in .NET) is a basically a modern way of creating a service-like application in .NET - not just Windows service, but eventually also a Linux daemon, etc.

The following example illustrates how an OPC server hosted in a worker service can be created.

// UAServerWorkerServiceDemo: Shows how to use the component to create an OPC UA server hosted in a worker service. It
// provides readable and writable nodes of various types.
// See also: https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Logging.EventLog;

namespace UAServerWorkerServiceDemo
{
    public class Program
    {
        public static void Main(string[] args)
        {
            HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
            builder.Services.AddWindowsService(options =>
            {
                options.ServiceName = "OpcWizardDemo";
            });

            LoggerProviderOptions.RegisterProviderOptions<
                EventLogSettings, EventLogLoggerProvider>(builder.Services);

            builder.Services.AddHostedService<ServerDemoBackgroundService>();

            IHost host = builder.Build();
            host.Run();
        }
    }
}
// UAServerWorkerServiceDemo: Shows how to use the component to create an OPC UA server hosted in a worker service. It
// provides readable and writable nodes of various types.
// See also: https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using OpcLabs.EasyOpc.UA;
using UAServerDemoLibrary;

namespace UAServerWorkerServiceDemo
{
    public class ServerDemoBackgroundService : BackgroundService
    {
        private readonly ILogger<ServerDemoBackgroundService> _logger;

        // The server object.
        // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
        private readonly EasyUAServer _server = new();

        public ServerDemoBackgroundService(ILogger<ServerDemoBackgroundService> logger)
        {
            _logger = logger;

            // Define various nodes.
            ConsoleNodes.AddToParent(_server.Objects);
            DataNodes.AddToParent(_server.Objects);
            DemoNodes.AddToParent(_server.Objects);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                // Start the server.
                _server.Start();

                while (!stoppingToken.IsCancellationRequested)
                {
                    await Task.Delay(1000, stoppingToken);
                }

                // Stop the server.
                _server.Stop();
            }
            catch (OperationCanceledException)
            {
                // When the stopping token is canceled, for example, a call made from services.msc,
                // we shouldn't exit with a non-zero exit code. In other words, this is expected...
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "{Message}", ex.Message);

                // Terminates this process and returns an exit code to the operating system.
                // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
                // performs one of two scenarios:
                // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
                // 2. When set to "StopHost": will cleanly stop the host, and log errors.
                //
                // In order for the Windows Service Management system to leverage configured
                // recovery options, we need to terminate the process with a non-zero exit code.
                Environment.Exit(1);
            }
        }
    }
}
See Also

Installed Examples - Server Console

Installed Examples - Server Windows Forms

Installed Examples - Server Windows Service

Installed Examples - Server Worker Service

Reference

External