# Erste Schritte

> Tutorial: Den ersten Client mit dem OPC UA .NET SDK aufsetzen: Namespace einbinden, Verbindung aufbauen und wieder trennen, auch für OPC Classic Server.

**Beispielanwendungen:**

- Client.Temperature ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Scenarios/Client.Temperature), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Scenarios/Client.Temperature)): Verbindet sich mit einem Server und liest einmal je Sekunde den Wert eines Temperatur-Nodes.
- Server.Temperature ([C#](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/cs/Scenarios/Server.Temperature), [VB.NET](https://github.com/Traeger-GmbH/opcuanet-samples/tree/master/vb/Scenarios/Server.Temperature)): Stellt einen Temperatur-Node bereit und ändert seinen Wert einmal je Sekunde.

## Voraussetzungen

- **Zielframework:** .NET oder .NET Framework ab 4.7.2, alle unterstützten unter [Zielframeworks](https://www.traeger.de/docs/development/opcua/requirements#zielframeworks)
- **NuGet-Paket:** `Opc.UaFx.Client`, für OPC Classic `Opc.UaFx.Advanced` ([Downloads](https://www.traeger.de/docs/development/opcua/downloads))
- **OPC UA Server:** ein erreichbarer Server, für erste Tests etwa der Server aus dem [vollständigen Beispiel](https://www.traeger.de/docs/development/opcua/server/getting-started#vollstandiges-beispiel) der Server-Entwicklung
- **Lizenz:** für die Evaluation nicht erforderlich. Ohne Lizenzschlüssel läuft das SDK je Anwendungsstart 30 Minuten uneingeschränkt ([Lizenz einrichten](https://www.traeger.de/docs/development/opcua/license-setup#evaluation))

## Mit einem OPC UA Server verbinden

**1.** Verweis auf den Client-Namespace `Opc.UaFx.Client` hinzufügen:

```csharp
using Opc.UaFx.Client;
```

```vbnet
Imports Opc.UaFx.Client
```

**2.** Eine Instanz der Klasse `OpcClient` mit der Adresse des Servers erzeugen:

```csharp
var client = new OpcClient("opc.tcp://localhost:4840/");
```

```vbnet
Dim client = New OpcClient("opc.tcp://localhost:4840/")
```

**3.** Verbindung zum Server aufbauen und Sitzung starten:

```csharp
client.Connect();
```

```vbnet
client.Connect()
```

**4.** Mit dem Server arbeiten (Ihr Code):

```csharp
// Your code to interact with the server.
```

```vbnet
'Your code to interact with the server.
```

**5.** Vor dem Beenden der Anwendung die Verbindung wieder trennen:

```csharp
client.Disconnect();
```

```vbnet
client.Disconnect()
```

**6.** Mit einem `using`-Block sieht das so aus:

```csharp
using (var client = new OpcClient("opc.tcp://localhost:4840/")) {
    client.Connect();
    // Your code to interact with the server.
}
```

```vbnet
Using client As New OpcClient("opc.tcp://localhost:4840/")
    client.Connect()
    'Your code to interact with the server.
End Using
```

Wie es weitergeht, hängt davon ab, ob Sie die Nodes und NodeIds des Servers kennen:

- **unbekannt:** Welche Nodes der Server bereitstellt, zeigt der Abschnitt [Adressraum erkunden](https://www.traeger.de/docs/development/opcua/client/browse#adressraum-erkunden).
- **bekannt:** [Werte lesen](https://www.traeger.de/docs/development/opcua/client/read-write-values#werte-lesen) oder [Werte schreiben](https://www.traeger.de/docs/development/opcua/client/read-write-values#werte-schreiben)

## Server finden

Beteiligte Typen: `OpcDiscoveryClient`, `OpcApplicationDescription`

Wenn die Adresse eines Servers nicht bekannt ist, liefert ein Discovery Server (zum Beispiel der Local Discovery Server auf Port 4840) die bei ihm registrierten Server samt ihrer Discovery-Adressen. `DiscoverServers` liefert je Server seinen Namen, seinen Typ und seine Adressen. Eine Überladung von `DiscoverServers` beschränkt das Ergebnis auf Server mit bestimmten Anwendungs-URIs, eine Überladung von `DiscoverEndpoints` auf Endpunkte mit bestimmten Transportprofilen. Welche Endpunkte ein Server anbietet, zeigt danach der Abschnitt [Endpunkt sicher wählen](https://www.traeger.de/docs/development/opcua/security/client#endpunkt-sicher-wahlen):

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

```

```vbnet
Using discovery = New OpcDiscoveryClient("opc.tcp://localhost:4840/")
    For Each server As OpcApplicationDescription In discovery.DiscoverServers()
        Console.WriteLine("{0} ({1})", server.Name, server.Type)

        For Each url As Uri In server.DiscoveryUrls
            Console.WriteLine("  {0}", url)
        Next
    Next
End Using
```

## Mit einem OPC Classic Server verbinden

Für die Verbindung zu einem *OPC Classic Server* muss der Client unter Windows laufen, und die [OPC Classic Runtime](https://www.traeger.de/docs/development/opcua/downloads#opc-classic-runtime) muss auf dem Rechner installiert sein. Die Unterstützung von OPC Classic ist nur im Paket `Opc.UaFx.Advanced` enthalten.

Was nach dem Verbinden mit einem Classic-Server möglich ist (DA, AE und HDA mit derselben API), beschreibt die Seite [OPC Classic](https://www.traeger.de/docs/development/opcua/client/opc-classic).

**1.** Verweise auf den Classic- und den Client-Namespace hinzufügen:

```csharp
using Opc.UaFx.Client;
using Opc.UaFx.Client.Classic;
```

```vbnet
Imports Opc.UaFx.Client
Imports Opc.UaFx.Client.Classic
```

**2.** Eine Instanz der Klasse `OpcClient` mit der Adresse des Servers erzeugen:

```csharp
var client = new OpcClient("opc.com://localhost:48410/<progId>/<classId>");
```

```vbnet
Dim client As New OpcClient("opc.com://localhost:48410/<progId>/<classId>")
```

**3.** Verbindung zum Server aufbauen und Sitzung starten:

```csharp
client.Connect();
```

```vbnet
client.Connect()
```

**4.** Mit dem Server arbeiten (Ihr Code):

```csharp
// Your code to interact with the server.
```

```vbnet
'Your code to interact with the server.
```

**5.** Vor dem Beenden der Anwendung die Verbindung wieder trennen:

```csharp
client.Disconnect();
```

```vbnet
client.Disconnect()
```

**6.** Mit einem `using`-Block sieht das so aus:

```csharp
using (var client = new OpcClient("opc.com://localhost:48410/<progId>/<classId>")) {
    client.Connect();
    // Your code to interact with the server.
}
```

```vbnet
Using client As New OpcClient("opc.com://localhost:48410/<progId>/<classId>")
    client.Connect()
    'Your code to interact with the server.
End Using
```

Wie es weitergeht, hängt davon ab, ob Sie die Nodes und NodeIds des Servers kennen:

- **unbekannt:** Welche Nodes der Server bereitstellt, zeigt der Abschnitt [Adressraum erkunden](https://www.traeger.de/docs/development/opcua/client/browse#adressraum-erkunden).
- **bekannt:** [Werte lesen](https://www.traeger.de/docs/development/opcua/client/read-write-values#werte-lesen) oder [Werte schreiben](https://www.traeger.de/docs/development/opcua/client/read-write-values#werte-schreiben)

**So ist die Adresse des Servers aufgebaut**: `opc.com://localhost:48410/<progId>/<classId>`

- `opc.com` gibt an, dass sich der Client mit einem *OPC Classic Server* verbindet.
- `localhost` steht für den Namen oder die IP-Adresse des Rechners, auf dem der *OPC Classic Server* läuft.
- `48410` ist die optionale Portnummer, die der *OPC UA Wrapper Server*[^wrapper-server] verwenden soll. Wenn sie fehlt, verwendet der Wrapper Server einen freien Port, den das System zuweist.
- `<progId>` ist ein optionaler Platzhalter. Ersetzen Sie ihn durch die `ProgID` aus den DCOM-Anwendungsinformationen des *OPC Classic Servers*, zum Beispiel `OPCManager.DA.XML-DA.Server.DA`. Die Adresse `opc.com://localhost/<classId>` ohne `<progId>` genügt ebenfalls.
- `<classId>` ist ein Platzhalter. Ersetzen Sie ihn durch die `ClassId` (auch CLSID oder `AppID`) aus den DCOM-Anwendungsinformationen des *OPC Classic Servers*, zum Beispiel `{E4EBF7FA-CCAC-4125-A611-EAC4981C00EA}`. Die `ClassId` muss als GUID angegeben werden.

**`<classId>` beziehungsweise `<progId>` des Servers ermitteln**:

**Methode: `OpcClassicDiscoveryClient`**

```csharp
using (var discoveryClient = new OpcClassicDiscoveryClient("<host>")) {
    var servers = discoveryClient.DiscoverServers();

    foreach (var server in servers) {
        Console.WriteLine(
                "- {0}, ClassId={1}, ProgId={2}",
                server.Name,
                server.ClassId,
                server.ProgId);
    }
}
```

```vbnet
Using discoveryClient As New OpcClassicDiscoveryClient("<host>")
    Dim servers = discoveryClient.DiscoverServers()

    For Each server In servers
        Console.WriteLine( _
                "- {0}, ClassId={1}, ProgId={2}", _
                server.Name, _
                server.ClassId, _
                server.ProgId)
    Next
End Using
```

**Methode: Systeminformationen.** Führen Sie die folgenden Schritte auf dem Rechner des *OPC Classic Servers* durch:

1. `AppID` über die Komponentendienste ermitteln
   - Systemsteuerung
   - Verwaltung
   - Komponentendienste
   - „Komponentendienste“ erweitern
   - „Computer“ erweitern
   - „Arbeitsplatz“ erweitern
   - „DCOM-Konfiguration“ erweitern
   - `<OPC Classic Server>` auswählen
   - „Eigenschaften“ öffnen
   - erster Reiter „Allgemein“
   - „Anwendungs-ID:“ kopieren, also die `AppID`
2. `ProgId` über die Systemregistrierungsdatenbank ermitteln
   - „Windows-Taste“ + „R“
   - `regedit` eingeben
   - „OK“ klicken
   - den Schlüssel „Computer“ erweitern
   - dann den Schlüssel „HKEY_LOCAL_MACHINE“
   - „SOFTWARE“ erweitern
   - „WOW6432Node“ erweitern (nur auf 64-Bit-Systemen, sonst diesen Schritt überspringen)
   - „Classes“ erweitern
   - „CLSID“ erweitern
   - `<classId>` erweitern
   - `ProgID` auswählen
   - Wert „(Standard)“ in der Spalte „Daten“ kopieren, also die `ProgID`

[^wrapper-server]: Der OPC UA Client startet den *OPC UA Wrapper Server* automatisch und beendet ihn beim Trennen der Verbindung. Jeder Client startet dabei seinen eigenen Wrapper Server. Der *OPC UA Wrapper Server* verpackt die Zugriffe des OPC UA Clients und sendet sie an den *OPC Classic Server*. Die Antworten des OPC Classic Servers sendet der *OPC UA Wrapper Server* als OPC-UA-Antworten an den *OPC UA Client* zurück.

## Vollständiges Beispiel

Vollständiges Programm: ein Client, der sich mit einem Server verbindet und
einmal je Sekunde einen Temperatur-Node liest:

```csharp
namespace Client
{
    using System;
    using System.Threading;

    using Opc.UaFx.Client;

    /// <summary>
    /// This sample demonstrates how to connect to an OPC UA server and read the value of a node
    /// once per second.
    /// </summary>
    public class Program
    {
        public static void Main()
        {
            using (var client = new OpcClient("opc.tcp://localhost:4840")) {
                client.Connect();

                while (true) {
                    var temperature = client.ReadNode("ns=2;s=Temperature");
                    Console.WriteLine("Current Temperature is {0} °C", temperature);

                    Thread.Sleep(1000);
                }
            }
        }
    }
}

```

```vbnet
Imports System
Imports System.Threading

Imports Opc.UaFx.Client

Namespace Client
    ''' <summary>
    ''' This sample demonstrates how to connect to an OPC UA server and read the value of a node
    ''' once per second.
    ''' </summary>
    Public Class Program
        Public Shared Sub Main()
            Using client = New OpcClient("opc.tcp://localhost:4840")
                client.Connect()

                While True
                    Dim temperature = client.ReadNode("ns=2;s=Temperature")
                    Console.WriteLine("Current Temperature is {0} °C", temperature)

                    Thread.Sleep(1000)
                End While
            End Using
        End Sub
    End Class
End Namespace

```

Läuft der Server aus dem [vollständigen Beispiel](https://www.traeger.de/docs/development/opcua/server/getting-started#vollstandiges-beispiel) der Server-Entwicklung auf demselben Rechner, gibt der Client einmal je Sekunde eine Zeile `Current Temperature is … °C` aus. Der Wert steigt dabei von 100 bis 110 und beginnt dann wieder bei 100.

## Nächste Schritte

- [Nodes browsen](https://www.traeger.de/docs/development/opcua/client/browse): Den Adressraum eines Servers untersuchen: vom ObjectsFolder aus Node für Node oder mehrere Ebenen in einem Durchgang.

- [Werte lesen und schreiben](https://www.traeger.de/docs/development/opcua/client/read-write-values): Werte einzelner und mehrerer Nodes lesen und schreiben, andere Attribute und Teile von Arrays ansprechen und Ergebnisse mit Status auswerten.

- [Subscriptions](https://www.traeger.de/docs/development/opcua/client/subscriptions): Wertänderungen und Ereignisse von Nodes per Subscription abonnieren, Benachrichtigungen behandeln, Subscriptions verwalten und mit Filtern eingrenzen.

- [Clients absichern](https://www.traeger.de/docs/development/opcua/security/client): Den Client absichern: Endpunkt wählen, Serverzertifikate prüfen, das eigene Zertifikat schützen, Benutzer anmelden, Checkliste für den Betrieb.
