# Konfiguration

> Anleitung: Den Client konfigurieren: Anwendung, Verbindungsüberwachung, Grenzen der Datenübertragung, Zertifikat und XML-Konfiguration.

**Beispielanwendungen:**

- Client.ConfiguredViaCode ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Configuration/Client.ConfiguredViaCode), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Configuration/Client.ConfiguredViaCode)): Zeigt verschiedene Wege, einen Client im Code zu konfigurieren, von der Standardkonfiguration bis zu eigenen Einstellungen.
- Client.ConfiguredViaXml ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Configuration/Client.ConfiguredViaXml), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Configuration/Client.ConfiguredViaXml)): Lädt die Konfiguration eines Clients aus einer XML-Datei.

## Anwendung und Sitzung konfigurieren

Beteiligte Typen: `OpcClient`, `OpcApplicationConfiguration`, `OpcCertificateStores`, `OpcCertificateStoreInfo`

Alle Codeausschnitte auf dieser Seite konfigurieren den Client im Code, sofern er nicht mit seiner Standardkonfiguration arbeitet. Zentrale Stelle für die Konfiguration der Clientanwendung, der Sitzungsparameter und der Verbindungsparameter ist die Instanz von `OpcClient`. Alle Sicherheitseinstellungen liefert die Eigenschaft `Security` des Clients als Instanz der Klasse `OpcClientSecurity`. Alle Einstellungen der Zertifikatspeicher liefert die Eigenschaft `CertificateStores` des Clients als Instanz der Klasse `OpcCertificateStores`.

Wenn der Client auch per XML konfigurierbar sein soll, laden Sie seine Konfiguration aus einer XML-Datei. Wie die Datei aufgebaut ist, zeigt der Abschnitt [Konfiguration per XML-Datei](https://www.traeger.de/docs/development/opcua/client/configuration#konfiguration-per-xml-datei). So laden Sie die Einstellungen:

**Konfigurationsdatei über den Namen der Konfiguration laden**: Die Methode `LoadClientConfig` sucht im Arbeitsverzeichnis der Anwendung die Datei `<Name>.Config.xml`, im folgenden Beispiel also `Opc.UaFx.Client.Config.xml`.

```csharp
client.Configuration = OpcApplicationConfiguration.LoadClientConfig("Opc.UaFx.Client");

```

```vbnet
client.Configuration = OpcApplicationConfiguration.LoadClientConfig("Opc.UaFx.Client")

```

**Konfigurationsdatei über den Pfad zur XML-Datei laden**: Wenn die Datei fehlt oder nicht lesbar ist, lösen `LoadClientConfig` und `LoadClientConfigFile` keine Ausnahme aus, sondern liefern `null`. Prüfen Sie deshalb den Rückgabewert:

```csharp
var configuration = OpcApplicationConfiguration.LoadClientConfigFile("MyClientAppNameConfig.xml");
 
// The method returns a null reference in case the file could not be loaded.
if (configuration == null)
    throw new InvalidOperationException("The client configuration could not be loaded.");
 
client.Configuration = configuration;

```

```vbnet
Dim configuration = OpcApplicationConfiguration.LoadClientConfigFile("MyClientAppNameConfig.xml")

'The method returns Nothing in case the file could not be loaded.
If configuration Is Nothing Then
    Throw New InvalidOperationException("The client configuration could not be loaded.")
End If

client.Configuration = configuration
```

Für die Konfiguration der Clientanwendung gibt es unter anderem die folgenden Einstellungen:

**Anwendung konfigurieren** (per Code): Ohne Angabe verwendet der Client als `ApplicationName` den Wert des Attributs `AssemblyTitle`, ersatzweise den des Attributs `AssemblyProduct` und sonst `OPC Application`. Die `ApplicationUri` übernimmt der Client aus dem Anwendungszertifikat (Subject Alternative Name) und überschreibt dabei einen im Code festgelegten Wert. Den Wert aus dem Code verwendet er nur, wenn er ein neues Anwendungszertifikat erzeugt. Fehlt auch dieser Wert, gilt `urn:<Hostname>:<ApplicationName>`.

```csharp
// Default: Value of AssemblyTitleAttribute of entry assembly.
client.ApplicationName = "MyClientAppName";
 
// Default: A null reference to use the URI of the application certificate.
// The value is used to create a new application certificate.
client.ApplicationUri = new Uri("urn:localhost:MyClientAppName");
```

```vbnet
'Default: Value of AssemblyTitleAttribute of entry assembly.
client.ApplicationName = "MyClientAppName"

'Default: Nothing to use the URI of the application certificate.
'The value is used to create a new application certificate.
client.ApplicationUri = New Uri("urn:localhost:MyClientAppName")
```

Per XML (unterhalb des Elements `OpcApplicationConfiguration`):

```xml
  <ApplicationName>MyClient Configured via XML</ApplicationName>
  <ApplicationUri>http://myclient/application</ApplicationUri>
```

**Sitzungsparameter konfigurieren** (per Code): Ohne `SessionName` erhält die Sitzung den Namen der Anwendung (`ApplicationName`).

```csharp
client.SessionTimeout = 30000;          // Default: 60000
client.SessionName = "My Session Name"; // Default: Value of ApplicationName
```

```vbnet
client.SessionTimeout = 30000           'Default: 60000
client.SessionName = "My Session Name"  'Default: Value of ApplicationName
```

Per XML (unterhalb des Elements `OpcApplicationConfiguration`). Der Client verwendet den Wert aus der XML-Datei nur, wenn seine Eigenschaft `SessionTimeout` auf `0` gesetzt ist:

```xml
    <DefaultSessionTimeout>600000</DefaultSessionTimeout>
```

**Verbindungsparameter konfigurieren** (per Code): Die Eigenschaft `OperationTimeout` legt fest, wie lange der Client höchstens auf die Antwort einer Anfrage wartet (standardmäßig 120000 Millisekunden).

```csharp
client.OperationTimeout = 10000;        // Default: 120000
client.DisconnectTimeout = 5000;        // Default: 10000
client.ReconnectInterval = 5000;        // Default: 10000
```

```vbnet
client.OperationTimeout = 10000         'Default: 120000
client.DisconnectTimeout = 5000         'Default: 10000
client.ReconnectInterval = 5000         'Default: 10000
```

Per XML (unterhalb des Elements `OpcApplicationConfiguration`):

```xml
    <OperationTimeout>120000</OperationTimeout>
```

**Zertifikatspeicher konfigurieren** (per Code): Standardmäßig liegen die Zertifikatspeicher im Ordner `CertificateStores` im Verzeichnis der Anwendung. Wenn dieses Verzeichnis nicht beschreibbar ist, verwendet der Client den Ordner `OPC Foundation\CertificateStores` unterhalb von `%ProgramData%` beziehungsweise `%AppData%`. Die Reihenfolge der geprüften Pfade lässt sich über die Eigenschaft `OpcCertificateStores.PathProbings` anpassen.

```csharp
// Default: ".\CertificateStores\App"
client.CertificateStores.ApplicationStore.Path
        = @"%LocalApplicationData%\MyClientAppName\App Certificates";
 
// Default: ".\CertificateStores\Rejected"
client.CertificateStores.RejectedStore.Path
        = @"%LocalApplicationData%\MyClientAppName\Rejected Certificates";
 
// Default: ".\CertificateStores\Trusted"
client.CertificateStores.TrustedIssuerStore.Path
        = @"%LocalApplicationData%\MyClientAppName\Trusted Issuer Certificates";
 
// Default: ".\CertificateStores\Trusted"
client.CertificateStores.TrustedPeerStore.Path
        = @"%LocalApplicationData%\MyClientAppName\Trusted Peer Certificates";
```

```vbnet
'Default: ".\CertificateStores\App"
client.CertificateStores.ApplicationStore.Path _
        = "%LocalApplicationData%\MyClientAppName\App Certificates"

'Default: ".\CertificateStores\Rejected"
client.CertificateStores.RejectedStore.Path _
        = "%LocalApplicationData%\MyClientAppName\Rejected Certificates"

'Default: ".\CertificateStores\Trusted"
client.CertificateStores.TrustedIssuerStore.Path _
        = "%LocalApplicationData%\MyClientAppName\Trusted Issuer Certificates"

'Default: ".\CertificateStores\Trusted"
client.CertificateStores.TrustedPeerStore.Path _
        = "%LocalApplicationData%\MyClientAppName\Trusted Peer Certificates"
```

Per XML (unterhalb des Elements `OpcApplicationConfiguration`):

```xml
<SecurityConfiguration>
  <ApplicationCertificate>
    <StoreType>Directory</StoreType>
    <StorePath>.\CertificateStores\App</StorePath>
    <SubjectName>CN=MyClient, C=US, S=Arizona, O=YourCompany, DC=localhost</SubjectName>
    <!-- <Thumbprint>3a35fb798fc6dee8a7e7e4652b0e28fc14c6ee0f</Thumbprint> -->
  </ApplicationCertificate>

  <TrustedIssuerCertificates>
    <StoreType>Directory</StoreType>
    <StorePath>.\CertificateStores\Trusted</StorePath>
  </TrustedIssuerCertificates>

  <TrustedPeerCertificates>
    <StoreType>Directory</StoreType>
    <StorePath>.\CertificateStores\Trusted</StorePath>
  </TrustedPeerCertificates>

  <RejectedCertificateStore>
    <StoreType>Directory</StoreType>
    <StorePath>.\CertificateStores\Rejected</StorePath>
  </RejectedCertificateStore>
</SecurityConfiguration>
```

**Bevorzugte Sprachen der Sitzung festlegen**: Über `Locales` teilt der Client dem Server mit, in welchen Sprachen er Texte wie DisplayName, Description und Ereignismeldungen bevorzugt erhalten möchte. Der Client übergibt die Sprachen beim Erstellen der Sitzung. Ohne Angabe liefert der Server seine Standardsprache.

```csharp
client.Locales.Add("de-DE");
client.Locales.Add("en-US");
 
client.Connect();
 
OpcValue displayName = client.ReadNode("ns=2;s=Machine", OpcAttribute.DisplayName);
```

```vbnet
client.Locales.Add("de-DE")
client.Locales.Add("en-US")

client.Connect()

Dim displayName As OpcValue = client.ReadNode("ns=2;s=Machine", OpcAttribute.DisplayName)
```

## Verbindungsüberwachung

Beteiligte Typen: `OpcClient`, `OpcClientKeepAlive`

Wie der Client Verbindungsabbrüche erkennt und die Verbindung wiederherstellt, beschreibt der Abschnitt [Verbindungsabbrüche erkennen](https://www.traeger.de/docs/development/opcua/client/introduction#verbindungsabbruche-erkennen) der Einführung. Die folgenden Eigenschaften legen das Verhalten fest. Wenn die Eigenschaft `ReconnectInterval` den Wert `0` hat, stellt der Client die Verbindung nicht wieder her, sondern löst das Ereignis `BreakDetected` aus. Die Eigenschaft `MaxReconnectDuration` begrenzt, wie lange der Client es versucht (standardmäßig `0`, unbegrenzt):

```csharp
client.UseBreakDetection = true;    // Default: true
client.KeepAlive.Interval = 2000;   // Default: 5000
client.ReconnectInterval = 5000;    // Default: 10000
client.MaxReconnectDuration = 0;    // Default: 0 (unlimited)
```

```vbnet
client.UseBreakDetection = True     'Default: True
client.KeepAlive.Interval = 2000    'Default: 5000
client.ReconnectInterval = 5000     'Default: 10000
client.MaxReconnectDuration = 0     'Default: 0 (unlimited)
```

**Auf Verbindungsabbrüche reagieren**: Wenn der Client nach einem Abbruch eine neue Sitzung erstellt hat, löst er statt `Reconnected` das Ereignis `Connected` aus.

```csharp
client.Reconnecting += HandleReconnecting;
client.Reconnected += HandleReconnected;
client.BreakDetected += HandleBreakDetected;
...
private static void HandleReconnecting(object sender, EventArgs e)
{
    Console.WriteLine("Connection lost, trying to reconnect.");
}
 
private static void HandleReconnected(object sender, EventArgs e)
{
    Console.WriteLine("Connection restored using the existing session.");
}
 
private static void HandleBreakDetected(object sender, EventArgs e)
{
    Console.WriteLine("Connection lost, no automatic reconnect.");
}
```

```vbnet
AddHandler client.Reconnecting, AddressOf HandleReconnecting
AddHandler client.Reconnected, AddressOf HandleReconnected
AddHandler client.BreakDetected, AddressOf HandleBreakDetected
...
Private Shared Sub HandleReconnecting(ByVal sender As Object, ByVal e As EventArgs)
    Console.WriteLine("Connection lost, trying to reconnect.")
End Sub

Private Shared Sub HandleReconnected(ByVal sender As Object, ByVal e As EventArgs)
    Console.WriteLine("Connection restored using the existing session.")
End Sub

Private Shared Sub HandleBreakDetected(ByVal sender As Object, ByVal e As EventArgs)
    Console.WriteLine("Connection lost, no automatic reconnect.")
End Sub

```

**Das Ergebnis der KeepAlive-Anfragen auswerten**:

```csharp
client.KeepAlive.Updated += HandleKeepAliveUpdated;
...
private static void HandleKeepAliveUpdated(object sender, EventArgs e)
{
    OpcClientKeepAlive keepAlive = (OpcClientKeepAlive)sender;
 
    if (keepAlive.IsActive) {
        Console.WriteLine(
                "Server state: {0}, server time: {1}",
                keepAlive.ServerState,
                keepAlive.Time);
    }
    else {
        Console.WriteLine("Keep alive failed: {0}", keepAlive.Status);
    }
}
```

```vbnet
AddHandler client.KeepAlive.Updated, AddressOf HandleKeepAliveUpdated
...
Private Shared Sub HandleKeepAliveUpdated(ByVal sender As Object, ByVal e As EventArgs)
    Dim keepAlive As OpcClientKeepAlive = CType(sender, OpcClientKeepAlive)

    If keepAlive.IsActive Then
        Console.WriteLine( _
                "Server state: {0}, server time: {1}", _
                keepAlive.ServerState, _
                keepAlive.Time)
    Else
        Console.WriteLine("Keep alive failed: {0}", keepAlive.Status)
    End If
End Sub

```

Was der Client bei einem Abbruch selbst übernimmt und was die Anwendung im Dauerbetrieb beachten sollte, beschreibt die Seite [Clients für den Dauerbetrieb](https://www.traeger.de/docs/development/opcua/client/long-running-clients).

## Grenzen der Datenübertragung

Beteiligte Typen: `OpcClient`, `OpcTransport`

Der Client begrenzt die Größe der Daten, die er mit dem Server austauscht. Wenn ein Wert eine dieser Grenzen überschreitet, schlägt das Dekodieren fehl, zum Beispiel mit dem Status `BadEncodingLimitsExceeded`. Wenn Sie große Zeichenketten, Arrays oder Strukturen übertragen, erhöhen Sie die Grenzen über die Eigenschaft `Transport` des Clients:

```csharp
client.Transport.MaxStringLength = 1048576;      // Default: 65535
client.Transport.MaxByteStringLength = 10485760; // Default: 5242880
client.Transport.MaxArrayLength = 1000000;       // Default: 65535
client.Transport.MaxMessageSize = 20971520;      // Default: 10485760
```

```vbnet
client.Transport.MaxStringLength = 1048576       'Default: 65535
client.Transport.MaxByteStringLength = 10485760  'Default: 5242880
client.Transport.MaxArrayLength = 1000000        'Default: 65535
client.Transport.MaxMessageSize = 20971520       'Default: 10485760
```

Die Werte entsprechen den Einträgen unterhalb des Elements `TransportQuotas` der XML-Konfiguration. Ebenso teilt der Client große Lese- und Schreibanfragen anhand der vom Server gemeldeten Grenzen automatisch auf mehrere Anfragen auf.

Wie das geschieht und wie sich die Aufteilung beeinflussen lässt, beschreibt der Abschnitt [Wie das SDK große Anfragen aufteilt](https://www.traeger.de/docs/development/opcua/client/bulk-access#wie-das-sdk-gro%C3%9Fe-anfragen-aufteilt).

## Anwendungszertifikat

Beteiligte Typen: `OpcClient`, `OpcCertificateManager`, `OpcCertificateSettings`, `OpcClientSecurity`, `OpcCertificateStores`, `OpcCertificateStoreInfo`

Der Client lädt Zertifikate der Typen `.der` und `.cer` (nur der öffentliche Teil) sowie `.pfx` und `.p12` (mit privatem Schlüssel). Wenn der Client einen sicheren Serverendpunkt verwenden soll, muss das Zertifikat einen privaten Schlüssel haben. Sicher ist ein Endpunkt, dessen `OpcSecurityMode` gleich `Sign` oder `SignAndEncrypt` ist.

**Ein vorhandenes Zertifikat** von einem beliebigen Pfad laden:

```csharp
var certificate = OpcCertificateManager.LoadCertificate("MyClientCertificate.pfx");

```

```vbnet
Dim certificate = OpcCertificateManager.LoadCertificate("MyClientCertificate.pfx")

```

**Ein passwortgeschütztes Zertifikat** mit Angabe des Passworts laden:

```csharp
var certificate = OpcCertificateManager.LoadCertificate(
        "MyClientCertificate.pfx",
        password: "password");
```

```vbnet
Dim certificate = OpcCertificateManager.LoadCertificate( _
        "MyClientCertificate.pfx", _
        password:="password")
```

**Ein neues Zertifikat** im Speicher erzeugen. Wenn Sie dabei Eigenschaften wie die Gültigkeit oder die Domänen festlegen, verwenden Sie die Klasse `OpcCertificateSettings` (Abschnitt [Eigenes Anwendungszertifikat verwenden](https://www.traeger.de/docs/development/opcua/client/deployment#eigenes-anwendungszertifikat-verwenden)):

```csharp
var certificate = OpcCertificateManager.CreateCertificate(client);

```

```vbnet
Dim certificate = OpcCertificateManager.CreateCertificate(client)

```

**Das Zertifikat speichern** (unter einem beliebigen Pfad):

```csharp
OpcCertificateManager.SaveCertificate("MyClientCertificate.pfx", certificate);

```

```vbnet
OpcCertificateManager.SaveCertificate("MyClientCertificate.pfx", certificate)

```

**Das Clientzertifikat festlegen**:

```csharp
client.Certificate = certificate;

```

```vbnet
client.Certificate = certificate

```

Das Zertifikat muss im Zertifikatspeicher für **Anwendungszertifikate** (`ApplicationStore`) gespeichert sein:

```csharp
if (!client.CertificateStores.ApplicationStore.Contains(certificate))
    client.CertificateStores.ApplicationStore.Add(certificate);

```

```vbnet
If Not client.CertificateStores.ApplicationStore.Contains(certificate) Then
    client.CertificateStores.ApplicationStore.Add(certificate)
End If
```

Wenn Sie **kein Zertifikat** festlegen, sucht der Client im `ApplicationStore` ein Zertifikat, dessen Name dem `ApplicationName` entspricht. Zuvor löst er das Ereignis `CertificateRequested` aus, über das die Anwendung selbst ein Zertifikat bereitstellen kann. Wenn der Client kein Zertifikat findet, erzeugt und verwendet er standardmäßig automatisch ein neues Zertifikat. Bis Version 2.58 gilt das auch für ein ungültiges Zertifikat. Ab Version 2.59 behält der Client ein vorhandenes, aber ungültiges Zertifikat und löst das Ereignis `CertificateRequested` mit dem Grund aus (siehe [Eigenes Zertifikat schützen](https://www.traeger.de/docs/development/opcua/security/client#eigenes-zertifikat-schutzen)). Wenn auch das fehlschlägt, verwendet er ein temporäres Zertifikat im Speicher. Wenn der Client nur das angegebene Zertifikat verwenden soll, deaktivieren Sie diese Funktion. Setzen Sie dazu die Eigenschaft `AutoCreateCertificate` auf `false`:

```csharp
client.CertificateStores.AutoCreateCertificate = false;

```

```vbnet
client.CertificateStores.AutoCreateCertificate = False

```

Wie der Client einen sicheren Endpunkt wählt, Serverzertifikate prüft und sich mit einer Benutzeridentität anmeldet, beschreibt die Seite [Clients absichern](https://www.traeger.de/docs/development/opcua/security/client). Dort steht auch, wie Sie den Client für den Produktivbetrieb härten.

## Konfiguration per XML-Datei

Wenn der Client auch per XML konfigurierbar sein soll, laden Sie seine Konfiguration aus einer XML-Datei. Die Datei muss dazu den folgenden Standard-XML-Baum aufweisen:

```xml
<?xml version="1.0" encoding="utf-8" ?>
<OpcApplicationConfiguration
    xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
    schemaLocation="AppConfig.xsd">
```

Unterhalb des Elements `OpcApplicationConfiguration` folgen die Einstellungen aus den vorherigen Abschnitten. Sie laden die Datei auf einem der folgenden Wege:

- **über den Pfad zur XML-Datei** mit der Methode `LoadClientConfigFile`. Die Datei kann einen beliebigen Namen tragen und an einem beliebigen Ort liegen.
- **über den Namen der Konfiguration** mit der Methode `LoadClientConfig`. Die Datei muss dann den Namen `<Name>.Config.xml` tragen (zum Beispiel `Opc.UaFx.Client.Config.xml`) und im Arbeitsverzeichnis der Anwendung liegen.

Beide Methoden liefern `null`, wenn die Datei fehlt oder nicht lesbar ist (Abschnitt [Anwendung und Sitzung konfigurieren](https://www.traeger.de/docs/development/opcua/client/configuration#anwendung-und-sitzung-konfigurieren)). Eine Konfiguration über die `App.config` der Anwendung (`configSections` mit einem Verweis auf die XML-Datei) unterstützt das SDK nicht.
