# Anwendung ausliefern

> Anleitung: Eine Serveranwendung ausliefern: Dateien und Abhängigkeiten, Anwendungszertifikat, XML-Konfiguration, Ports, Discovery Server und Lizenzierung.

So bereiten Sie Ihre Serveranwendung für den Einsatz in produktiven Umgebungen vor.

## Dateien mitliefern

Das OPC UA .NET SDK besteht je Zielframework aus einer einzigen Assembly. Der OPC UA Stack und die weiteren Bibliotheken des SDK sind darin enthalten. Welche Zielframeworks es gibt, nennt die Seite [Voraussetzungen](https://www.traeger.de/docs/development/opcua/requirements#zielframeworks). Eine Installation oder Registrierung des SDK auf dem Zielrechner ist nicht nötig.

Je nach Zielframework hängt das Paket `Opc.UaFx.Advanced` von weiteren NuGet-Paketen ab, zum Beispiel von `Newtonsoft.Json`, `BouncyCastle.Cryptography` und den Paketen des eingebetteten Webservers Kestrel. Ab Version 2.59 ersetzt `BouncyCastle.Cryptography` (Version 2.7.0) das Paket `Portable.BouncyCastle`. Wenn Ihre Anwendung die Assemblies selbst verteilt, liefern Sie deshalb `BouncyCastle.Cryptography.dll` statt `BouncyCastle.Crypto.dll` aus. Beim Zielframework `netcoreapp3.1` verweist es statt auf die Kestrel-Pakete auf `Microsoft.AspNetCore.App`. Die vollständige Liste je Zielframework steht auf der [Paketseite bei nuget.org](https://www.nuget.org/packages/Opc.UaFx.Advanced/). Diese Pakete gehören zur Anwendung: `dotnet publish` und das Build-Verzeichnis enthalten sie automatisch. Liefern Sie deshalb das vollständige Ausgabeverzeichnis aus, nicht nur Ihre eigene Assembly und die des SDK.

Die Zertifikatspeicher legt das SDK standardmäßig als Verzeichnisse unter dem Pfad der Anwendung an (Ordner `CertificateStores`, siehe [Anwendungszertifikat](https://www.traeger.de/docs/development/opcua/server/configuration#anwendungszertifikat)).

Nur unter Windows verfügbar sind:

- **OPC Classic:** Der Zugriff auf OPC Classic Server über COM und DCOM setzt die auf dem Zielrechner installierte [OPC Classic Runtime](https://www.traeger.de/docs/development/opcua/downloads#opc-classic-runtime) voraus.
- **Windows-Dienst:** Eine Serveranwendung als Windows-Dienst betreiben (Klasse `OpcServerServiceApplication`) können Sie nur mit dem Zielframework `net472`.
- **Zertifikatspeicher von Windows:** Das SDK verwendet sie nur, wenn der Pfad eines Zertifikatspeichers mit `CurrentUser\` oder `LocalMachine\` beginnt.

## Eigenes Anwendungszertifikat verwenden

Verwenden Sie im produktiven Einsatz kein Zertifikat, das vom OPC UA .NET SDK automatisch erzeugt wurde.

**Wenn Sie bereits ein passendes Zertifikat haben**, laden Sie Ihr PFX-basiertes Zertifikat mit dem `OpcCertificateManager` von einem beliebigen Speicherort und weisen Sie es der Serverinstanz zu. Wenn das Zertifikat durch ein Passwort geschützt ist, verwenden Sie die Überladung der Methode `LoadCertificate` mit dem Passwort (siehe [Anwendungszertifikat](https://www.traeger.de/docs/development/opcua/server/configuration#anwendungszertifikat)):

```csharp
var certificate = OpcCertificateManager.LoadCertificate("MyServerCertificate.pfx");
server.Certificate = certificate;
```

```vbnet
Dim certificate = OpcCertificateManager.LoadCertificate("MyServerCertificate.pfx")
server.Certificate = certificate
```

Der Name der Anwendung muss im Zertifikat als „Common Name“ (CN) enthalten sein. Er muss mit dem Wert des Attributs `AssemblyTitle` der Anwendung übereinstimmen:

```csharp
[assembly: AssemblyTitle("<Common Name (CN) in Certificate>")]

```

```vbnet
' The AssemblyTitle attribute declaration is used in the AssemblyInfo.vb file of a VB.NET project:
' <Assembly: AssemblyTitle("<Common Name (CN) in Certificate>")> 

```

Wenn das nicht der Fall ist, legen Sie den im Zertifikat verwendeten Namen über die Eigenschaft `ApplicationName` der Serverinstanz fest. Wenn Sie das Zertifikat wie oben direkt über die Eigenschaft `Certificate` zuweisen, entfällt die Suche anhand des Namens:

```csharp
server.ApplicationName = "<Common Name (CN) in Certificate>";
```

```vbnet
server.ApplicationName = "<Common Name (CN) in Certificate>"
```

Die Eigenschaft `ApplicationUri` müssen Sie nicht festlegen: Der Server übernimmt den Wert beim Start aus dem Subject Alternative Name des Zertifikats.

**Wenn Sie noch kein passendes Zertifikat haben**, das Sie als Anwendungszertifikat für Ihren Server verwenden können, sollten Sie mindestens ein selbstsigniertes (engl. self-signed) Zertifikat erzeugen. Liefern Sie es mit der Anwendung aus und laden Sie es wie oben gezeigt. Das Zertifikat erzeugen Sie mit der Klasse `OpcCertificateManager`. Die Eigenschaften des Zertifikats legen Sie über eine Instanz von `OpcCertificateSettings` fest, zum Beispiel den Namen der Anwendung, die `ApplicationUri`, die Gültigkeit in Monaten oder die Namen der Domänen, unter denen der Server erreichbar ist:

```csharp
// Lifetime in months, default: 600.
var settings = new OpcCertificateSettings("MyServerAppName") {
    ApplicationUri = new Uri("urn:localhost:MyServerAppName"),
    Lifetime = 60
};
 
settings.DomainNames.Add("localhost");
settings.DomainNames.Add("myserver.mydomain.com");
 
var certificate = OpcCertificateManager.CreateCertificate(settings);
OpcCertificateManager.SaveCertificate("MyServerCertificate.pfx", certificate);
```

```vbnet
'Lifetime in months, default: 600.
Dim settings = New OpcCertificateSettings("MyServerAppName") With { _
    .ApplicationUri = New Uri("urn:localhost:MyServerAppName"), _
    .Lifetime = 60 _
}

settings.DomainNames.Add("localhost")
settings.DomainNames.Add("myserver.mydomain.com")

Dim certificate = OpcCertificateManager.CreateCertificate(settings)
OpcCertificateManager.SaveCertificate("MyServerCertificate.pfx", certificate)
```

Verwenden Sie als Namen der Anwendung den Wert des Attributs `AssemblyTitle`, oder legen Sie denselben Wert über die Eigenschaft `ApplicationName` der Serverinstanz fest. Wenn der Server das Zertifikat nicht direkt laden, sondern aus dem Speicher für Anwendungszertifikate nehmen soll, speichern Sie es im `ApplicationStore`. Standardmäßig ist das der Ordner `CertificateStores\App` neben der Anwendung (siehe [Anwendungszertifikat](https://www.traeger.de/docs/development/opcua/server/configuration#anwendungszertifikat)).

## Dateien der XML-Konfiguration mitliefern

Wenn Sie die Anwendung über eine XML-Datei konfigurieren, liefern Sie diese Datei mit der Anwendung aus. Die Anwendung muss die Datei erreichen können:

- Wenn die Anwendung die Konfiguration mit `LoadServerConfigFile` lädt, muss die Datei unter dem dort angegebenen Pfad liegen.
- Wenn die Anwendung die Konfiguration mit `LoadServerConfig` lädt, muss die Datei `<Name>.Config.xml` (zum Beispiel `Opc.UaFx.Server.Config.xml`) im Arbeitsverzeichnis der Anwendung liegen. Das Arbeitsverzeichnis ist nicht immer das Verzeichnis der Anwendung, zum Beispiel wenn die Anwendung als Dienst läuft.

Die `App.config` der Anwendung wertet der Server für seine Konfiguration nicht aus (siehe [Konfiguration per XML-Datei](https://www.traeger.de/docs/development/opcua/server/configuration#konfiguration-per-xml-datei)).

## Ports und Rechte einrichten

Der Server öffnet für jede Basis-Adresse einen eigenen Port, für `https` mit einem eingebetteten Webserver (Kestrel). Unter Windows braucht er dafür weder eine Reservierung der Adresse (URL ACL = URL Access Control List) noch Administratorrechte. Unter Linux benötigt eine Anwendung für Ports unterhalb von 1024 (zum Beispiel 443) erweiterte Rechte. Stellen Sie außerdem sicher, dass die verwendeten Ports in der Firewall des Zielsystems freigegeben sind.

## Eigenen Discovery Server betreiben

Beteiligte Typen: `OpcDiscoveryServer`, `OpcDiscoveryClient`, `OpcApplicationDescription`, `OpcServer`, `OpcServerDiscovery`

Wenn Clients die Server eines Netzwerks über eine zentrale Adresse finden sollen, können Sie einen eigenen Discovery Server betreiben. Ein Discovery Server stellt keinen Adressraum bereit. Er nimmt die Registrierungen anderer Server entgegen (Services `RegisterServer` und `RegisterServer2`) und beantwortet die Anfragen der Clients nach den registrierten Servern (Service `FindServers`). Standardmäßig bietet er je Basis-Adresse einen Endpunkt mit dem Modus `SignAndEncrypt` und dem Algorithmus `Basic256Sha256` an, aber keinen Endpunkt mit dem Modus `None`. Sie erzeugen und starten ihn wie einen `OpcServer`:

```csharp
using (var discoveryServer = new OpcDiscoveryServer("opc.tcp://localhost:4840/")) {
    discoveryServer.Start();
 
    Console.WriteLine("Press any key to stop the discovery server.");
    Console.ReadKey(intercept: true);
}
```

```vbnet
Using discoveryServer = New OpcDiscoveryServer("opc.tcp://localhost:4840/")
    discoveryServer.Start()

    Console.WriteLine("Press any key to stop the discovery server.")
    Console.ReadKey(intercept:=True)
End Using
```

Ein Client ermittelt die beim Discovery Server registrierten Server mit der Methode `DiscoverServers` einer Instanz von `OpcDiscoveryClient`:

```csharp
using (var discovery = new OpcDiscoveryClient("opc.tcp://localhost:4840/")) {
    foreach (var application in discovery.DiscoverServers())
        Console.WriteLine("{0}: {1}", application.Name, application.Uri);
}

```

```vbnet
Using discovery = New OpcDiscoveryClient("opc.tcp://localhost:4840/")
    For Each application In discovery.DiscoverServers()
        Console.WriteLine("{0}: {1}", application.Name, application.Uri)
    Next
End Using
```

Ein `OpcServer` registriert sich selbst regelmäßig beim Discovery Server auf seinem Rechner, standardmäßig unter `opc.tcp://localhost:4840` und alle 30000 Millisekunden. Den Abstand legt die Eigenschaft `Discovery.RegistrationInterval` fest, der Wert 0 schaltet die Registrierung ab. Eine Änderung gilt ab dem nächsten Start des Servers.

## Lizenz eintragen

Tragen Sie den Lizenzschlüssel in der Anwendung ein, bevor Sie die Serveranwendung ausliefern. Ohne Lizenzschlüssel läuft sie je Anwendungsstart nur 30 Minuten. Wie Sie den Schlüssel eintragen, die verwendete Lizenz abfragen und die Lizenz beim Start prüfen, beschreibt die Seite [Lizenz einrichten](https://www.traeger.de/docs/development/opcua/license-setup).
