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
ApplicationLicenseManager.AddProcessLicenses(assembly, "License.lic");
Console.WriteLine("Starting Server.");
GettingStartedServerManager server = new GettingStartedServerManager();
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);
PrintEndpoints(server);
Console.WriteLine("Press <enter> to exit the program.");
Console.ReadLine();
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)
{
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/");
}
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:
- The value of the /configFile command line parameter;
- The value of the ConfigurationFilePath property;
- The UaApplicationConfiguration configuration section in the App.config file;
- 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()
{
var application = new ConfigurationInMemory();
application.ApplicationName = "UnifiedAutomation GettingStartedServer";
application.ApplicationUri = "urn:localhost:UnifiedAutomation:GettingStartedServer";
application.ProductName = "UnifiedAutomation GettingStartedServer";
application.ApplicationCertificate.StoreType = "Directory";
application.ApplicationCertificate.StorePath = @"%CommonApplicationData%\unifiedautomation\UaSdkNet\pki\own";
application.ApplicationCertificate.SubjectName = "CN=GettingStartedServer/O=UnifiedAutomation/DC=localhost";
application.TrustedCertificateStore.StoreType = "Directory";
application.TrustedCertificateStore.StorePath = @"%CommonApplicationData%\unifiedautomation\UaSdkNet\pki\trusted";
application.IssuerCertificateStore.StoreType = "Directory";
application.IssuerCertificateStore.StorePath = @"%CommonApplicationData%\unifiedautomation\UaSdkNet\pki\issuers";
application.RejectedCertificatesStore.StoreType = "Directory";
application.RejectedCertificatesStore.StorePath = @"%CommonApplicationData%\unifiedautomation\UaSdkNet\pki\rejected";
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 });
TraceSettings trace = new TraceSettings();
trace.MasterTraceEnabled = false;
trace.TraceFile = @"%CommonApplicationData%\unifiedautomation\logs\UaSdkNet\UaGettingStartedServerNet.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);
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
}
};
ApplicationInstanceBase.Default.SetApplicationSettings(application);
}