.NET Based OPC UA Client/Server SDK  3.0.7.484
Lesson 1: Setting up a Basic OPC UA Server Console Application

The first lesson starts with an empty OPC UA server describing the code for integration of an OPC UA server component into a .NET application and the different server configuration options.

Create an Empty Server

The product specific information integration must be registered with the OPC UA server SDK. This is done by deriving a project specific class form the SDK class ServerManager. In the first step this derived class GettingStartedServerManager in the file GettingStartedServerManager.cs is empty.

internal class GettingStartedServerManager : ServerManager
{
}

The main integration code for adding the OPC UA server to the console application can be found in Program.cs.

The license for the server SDK must be loaded first from the embedded resource.

To start the server an instance of the GettingStartedServerManager is created and passed to the start method of the default application instance object.

The configuration of the server is done through the App.config file for the .NET framework version of the sdk. For the .NET Core version of the sdk, the configuration is set in code. The configuration options are described later in this lesson.

public static void Main(string[] args)
{
try
{
System.Reflection.Assembly assembly;
#if NETFX
assembly = System.Reflection.Assembly.GetExecutingAssembly();
#else
assembly = PlatformUtils.GetAssembly(typeof(Program));
#endif
// The license file must be loaded from an embedded resource.
ApplicationLicenseManager.AddProcessLicenses(assembly, "License.lic");
// Start the server.
Console.WriteLine("Starting Server.");
GettingStartedServerManager server = new GettingStartedServerManager();
//***********************************************************************
// The following function can be called to configure the server from code
// This will disable the configuration settings from app.config file
//ConfigureOpcUaApplicationFromCode();
//***********************************************************************
ApplicationInstanceBase application;
#if NETFX
application = ApplicationInstance.Default;
#else
application = ApplicationInstanceBase.Default;
ConfigureOpcUaApplicationFromCode();
application.SecurityProvider = new BouncyCastleSecurityProvider();
#endif
application.AutoCreateCertificate = true;
application.UntrustedCertificate += Application_UntrustedCertificate;
application.Start(server, null, server);
// Print endpoints for information.
PrintEndpoints(server);
// Block until the server exits.
Console.WriteLine("Press <enter> to exit the program.");
Console.ReadLine();
// Stop the server.
Console.WriteLine("Stopping Server.");
server.Stop();
}
catch (Exception e)
{
Console.WriteLine("ERROR: {0}", e.Message);
Console.WriteLine("Press <enter> to exit the program.");
Console.ReadLine();
}
}

The server can be started and a client is able to connect. All information in the server address space is defined by the OPC UA specification. The NamespaceArray contains only two namespaces, the OPC UA defined namespace and the local server namespace.

The method PrintEndpoints is used to print the available endpoints to the command line (just as an information for the server developer).

static void PrintEndpoints(GettingStartedServerManager server)
{
// print the endpoints.
Console.WriteLine(string.Empty);
Console.WriteLine("Listening at the following endpoints:");
foreach (EndpointDescription endpoint in server.Application.Endpoints)
{
StatusCode error = server.Application.GetEndpointStatus(endpoint);
Console.WriteLine(" {0}: Status={1}", endpoint, error.ToString(true));
}
Console.WriteLine(string.Empty);
}

Prepare Integration of Product Specific Information

A product specific NodeManager can be loaded by overwriting OnRootNodeManagerStarted in GettingStartedServerManager.cs.

protected override void OnRootNodeManagerStarted(RootNodeManager nodeManager)
{
Console.WriteLine("Creating Node Managers.");
Lesson01NodeManager lession1 = new Lesson01NodeManager(this);
lession1.Startup();
}

The class Lesson1NodeManager is derived from the BaseNodeManager class which forms the Toolkit API. It overloads the methods Startup and Shutdown.

In Lesson1NodeManager.cs, the namespace URI is set in Startup.

public override void Startup()
{
try
{
Console.WriteLine("Starting Lesson01NodeManager.");
base.Startup();
AddNamespaceUri("http://yourorganisation.com/lesson01/");
// TBD
}

The server NamespaceArray does now contain a third namespace.

Options for Loading Configuration Settings

The configuration settings are managed by the class ApplicationInstanceBase. The settings have to be set in code. The derived class ApplicationInstance in UaBase.Windows provides options to load the settings from XML in addition.

The Base Library Overview provides more details regarding Application Instance, the Configuration Schema for the configuration options and the Installation Process.

When started and the configuration is not set already, the application instance looks in the following locations for a configuration file:

  1. The value of the /configFile command line parameter;
  2. The value of the ConfigurationFilePath property;
  3. The UaApplicationConfiguration configuration section in the App.config file;
  4. An embedded resource in the entry Assembly with a file name ‘ApplicationSettings.xml’.

The file Program.cs of this lesson contains the following function ConfigureOpcUaApplicationFromCode with sample code to set the configuration settings from code before starting the application instance. The default option used in the server getting started lessons is the App.config file for .NET framework. But ConfigureOpcUaApplicationFromCode can be called instead before starting the application instance. This is also the default for the .NET Core version.

The standard configuration options can be set directly on the class SecuredApplication.

Additional configuration options like Trace Settings, Server Settings, User Identity Settings, Session Settings and Subscription Settings can be set as extension to the SecuredApplication.

This code requires an assembly reference to System.Runtime.Serialization.

static void ConfigureOpcUaApplicationFromCode()
{
// fill in the application settings in code
// The configuration settings are typically provided by another module
// of the application or loaded from a data base. In this example the
// settings are hardcoded
var application = new ConfigurationInMemory();
// ***********************************************************************
// standard configuration options
// general application identification settings
application.ApplicationName = "UnifiedAutomation GettingStartedServer";
application.ApplicationUri = "urn:localhost:UnifiedAutomation:GettingStartedServer";
application.ApplicationType = UnifiedAutomation.UaSchema.ApplicationType.Server_0;
application.ProductName = "UnifiedAutomation GettingStartedServer";
// configure application certificate and paths to the certificate stores
application.SetSecurity(PlatformUtils.CombinePath("%CommonApplicationData%", "UnifiedAutomation", "pki"), "CN=GettingStartedServer/O=UnifiedAutomation/DC=localhost");
// configure endpoints
application.BaseAddresses = new UnifiedAutomation.UaSchema.ListOfBaseAddresses();
application.BaseAddresses.Add("opc.tcp://localhost:48030");
application.SecurityProfiles = new ListOfSecurityProfiles();
application.SecurityProfiles.Add(new SecurityProfile() { ProfileUri = SecurityProfiles.Basic256Sha256, Enabled = true });
application.SecurityProfiles.Add(new SecurityProfile() { ProfileUri = SecurityProfiles.Aes128Sha256RsaOaep, Enabled = true });
application.SecurityProfiles.Add(new SecurityProfile() { ProfileUri = SecurityProfiles.Aes256Sha256RsaPss, Enabled = true });
application.SecurityProfiles.Add(new SecurityProfile() { ProfileUri = SecurityProfiles.None, Enabled = true });
// ***********************************************************************
// ***********************************************************************
// extended configuration options
// trace settings
TraceSettings trace = new TraceSettings();
trace.MasterTraceEnabled = false;
trace.DefaultTraceLevel = UnifiedAutomation.UaSchema.TraceLevel.Info;
trace.TraceFile = PlatformUtils.CombinePath("%CommonApplicationData%", "UnifiedAutomation", "Logs", FilePathUtils.MakeValidFileName(application.ApplicationName) + ".log.txt");
trace.MaxLogFileBackups = 3;
trace.ModuleSettings = new ModuleTraceSettings[]
{
new ModuleTraceSettings() { ModuleName = "UnifiedAutomation.Stack", TraceEnabled = true },
new ModuleTraceSettings() { ModuleName = "UnifiedAutomation.Server", TraceEnabled = true },
};
application.Set<TraceSettings>(trace);
// Installation settings
InstallationSettings installation = new InstallationSettings();
installation.GenerateCertificateIfNone = true;
installation.DeleteCertificateOnUninstall = true;
application.Set<InstallationSettings>(installation);
application.ServerSettings = new ServerSettings()
{
ProductName = "UnifiedAutomation GettingStartedServer",
DiscoveryRegistration = new DiscoveryRegistrationSettings()
{
Enabled = false
}
};
// ***********************************************************************
// set the configuration for the application (must be called before start to have any effect).
// these settings are discarded if the /configFile flag is specified on the command line.
ApplicationInstanceBase.Default.SetApplicationSettings(application);
}