14. Okt 2024
Lesedauer 14 Min.
Hybride Integration mit Azure Service Bus
Die Verbindung zwischen Cloud- und On-Premises-Anwendungen
Mit Messaging Netzwerkgrenzen überbrücken, um Anwendungen in der Cloud mit On-Premises-Anwendungen zu verbinden.

Unternehmen stehen in der heutigen IT-Landschaft vor der Herausforderung, flexibel und effizient auf wechselnde Geschäftsanforderungen reagieren zu müssen. Dabei spielt die Bereitstellung von Softwarelösungen eine zentrale Rolle. Die Entscheidung, ob Anwendungen und Daten in einer On-Premises-Umgebung oder in der Cloud betrieben werden, ist längst nicht mehr eine Frage von Entweder-oder. Stattdessen setzen immer mehr Unternehmen auf hybride Integrationsszenarien, um das Beste aus beiden Welten zu kombinieren.On-Premises-Lösungen bieten nach wie vor unübertroffene Kontrolle und Sicherheit. Besonders in Branchen mit strengen Compliance-Vorgaben bleibt die lokale Datenhaltung ein entscheidender Faktor. Doch dieser Sicherheitsgewinn geht oft einher mit hohen Kosten und begrenzter Skalierbarkeit. Hier setzt die Cloud an, die mit ihrer Flexibilität, Skalierbarkeit und den geringeren Betriebskosten punktet. Cloud-Computing ermöglicht es, Ressourcen je nach Bedarf dynamisch zu nutzen und neue Technologien wie künstliche Intelligenz oder Big-Data-Analysen effizient in Geschäftsprozesse zu integrieren.Doch weder On-Premises noch Cloud-Computing sind allein in der Lage, sämtliche Anforderungen moderner Anwendungen zu erfüllen. Hybride Szenarien bieten hier die optimale Lösung. Sie ermöglichen eine nahtlose Integration von lokal gehosteten Anwendungen mit Cloud-Diensten und bieten so eine flexible, skalierbare und sichere Umgebung, die den individuellen Bedürfnissen eines Unternehmens gerecht wird. Durch hybride Ansätze lassen sich bestehende Investitionen in On-Premises-Infrastrukturen optimal nutzen und gleichzeitig die Vorteile der Cloud erschließen. So können Unternehmen schnell auf Marktveränderungen reagieren, Innovationszyklen verkürzen und die Gesamtbetriebskosten senken. In einer Welt, in der Agilität und Effizienz entscheidend sind, stellen hybride Integrationsszenarien die Zukunft der IT-Anwendungslandschaft dar.Wie gelingt es, Cloud und On-Premises miteinander zu verbinden, ohne dafür ein ganzes IT-Security-Team inklusive IT-Netzwerkspezialisten einzustellen beziehungsweise hohen Konfigurations- und Wartungsaufwand zu erzeugen? Die Antworten liefert Ihnen dieser Artikel: Sie erfahren, wie Sie mithilfe von Azure Service Bus dieses Ziel erreichen.
Azure Service Bus: Netzwerkgrenzen überwinden ohne Kompromisse bei der IT-Security
In einer Zeit, in der verteilte Anwendungen über verschiedene Netzwerke und Umgebungen hinweg kommunizieren müssen, stehen Unternehmen vor der Herausforderung, diese Verbindungen sicher und zuverlässig zu gestalten. Dabei gilt es nicht nur, technische Hürden wie Netzwerkgrenzen zu überwinden, sondern auch strenge IT-Sicherheitsrichtlinien einzuhalten. Der Azure Service Bus bietet hier eine effektive Lösung, die es ermöglicht, Kommunikationsbarrieren zu überwinden, ohne die Sicherheit zu gefährden.Der Azure Service Bus fungiert als vermittelnde Instanz, die Nachrichten zwischen Anwendungen transportiert, selbst wenn diese sich in unterschiedlichen Netzwerkzonen oder hinter Firewalls befinden. Durch die Verwendung von Warteschlangen können Nachrichten sicher zwischengespeichert und erst zu einem späteren Zeitpunkt abgerufen werden, sobald die Zielanwendung verfügbar ist. Diese asynchrone Kommunikation ermöglicht es, Netzwerkgrenzen zu durchbrechen, ohne direkte Verbindungen herstellen zu müssen, die potenziell Sicherheitsrisiken mit sich bringen.Ein wesentliches Sicherheitsmerkmal des Azure Service Bus ist die strenge Zugriffskontrolle. Über Role-Based Access Control (RBAC) und Shared Access Signatures (SAS) lässt sich präzise steuern, welche Anwendungen und Benutzer auf welche Ressourcen zugreifen dürfen. Dadurch wird sichergestellt, dass nur autorisierte Anwendungen oder Services Nachrichten senden oder empfangen können. Diese granular einstellbaren Berechtigungen minimieren das Risiko von unbefugtem Zugriff und schützen sensible Daten effektiv.Zudem unterstützt der Azure Service Bus eine Ende-zu-Ende-Verschlüsselung. Nachrichten werden sowohl während der Übertragung als auch im Ruhezustand verschlüsselt, was den Schutz vor Abhörversuchen und Datenlecks weiter verstärkt. In Kombination mit der Möglichkeit, Nachrichten über dedizierte Kommunikationspfade zu senden, wird ein hohes Maß an Sicherheit gewährleistet, selbst in Szenarien, die komplexe Netzwerkarchitekturen umfassen.Für hybride Szenarien bietet der Azure Service Bus eine sichere Brücke zwischen On-Premises-Systemen und Cloud-Diensten. Unternehmen können ihre bestehenden Sicherheitsrichtlinien beibehalten und gleichzeitig die Vorteile der Cloud nutzen. Durch die Nutzung von Service Bus können Anwendungen in der Cloud nahtlos mit On-Premises-Lösungen kommunizieren.Der Azure Service Bus ermöglicht es, Netzwerkgrenzen sicher zu überwinden und gleichzeitig die IT-Security auf höchstem Niveau zu halten. Unternehmen erhalten damit eine zuverlässige, skalierbare und sichere Plattform, um komplexe Kommunikationsanforderungen zu erfüllen und ihre IT-Infrastruktur zukunftssicher zu gestalten.Service Bus in der Übersicht
Der Azure Service Bus (komplette Dokumentation unter [1]) zeichnet sich durch eine Reihe von Eigenschaften aus, die ihn zu einem leistungsfähigen und vielseitigen Message-Broker für moderne Anwendungen machen. Hier sind die wichtigsten Merkmale:1. Warteschlangen (Queues):- First In, First Out (FIFO): Nachrichten werden in der Reihenfolge zugestellt, in der sie eingegangen sind.
- Lastausgleich: Mehrere Empfänger können Nachrichten parallel verarbeiten, was die Skalierbarkeit erhöht.
- Publish/Subscribe-Modell: Ermöglicht das Verteilen einer Nachricht an mehrere Abonnenten.
- Filtern von Nachrichten: Nachrichten können basierend auf Attributen gefiltert und ausschließlich an relevante Abonnenten gesendet werden.
- Rollenbasierte Zugriffskontrolle (RBAC): Präzise Steuerung, wer Nachrichten senden und empfangen kann.
- Ende-zu-Ende-Verschlüsselung: Schutz sensibler Daten während der Übertragung.
- Dauerhafte Speicherung: Nachrichten bleiben gespeichert, bis sie erfolgreich verarbeitet wurden.
- Dead-Letter Queues: Fehlgeschlagene Nachrichten können zur späteren Analyse in speziellen Warteschlangen abgelegt werden.
- Hybrid-Umgebungen: Verbindung von On-Premises und Cloud-Diensten.
- Nahtlose Integration mit anderen Azure-Diensten: Einfache Anbindung an Azure Functions, Logic Apps und mehr.
- Hohe Verfügbarkeit: Automatische Replikation der Nachrichten in der Azure-Region.
- Automatische Skalierung: Dynamische Anpassung an das Nachrichtenvolumen ohne manuelle Eingriffe.
- Scheduled Delivery: Nachrichten können für die zukünftige Zustellung geplant werden.
- Session Management: Nachrichten mit logischen Abhängigkeiten können als Gruppe verarbeitet werden.
Warum eine Messaging-Lösung sinnvoll ist
Für Szenarien, in denen Cloud-Komponenten mit On-Premises-Komponenten kommunizieren, bietet sich eine Messaging-Lösung an. Dies gilt auch für ein umgekehrtes Szenario, Cloud-zu-Cloud oder Multicloud-Szenarien. Der Grund ist die asynchrone Kommunikation der Anwendungen mit dem Message Broker. Der Message Broker kümmert sich um die Komplexität von Verfügbarkeit, Speicherung der Nachrichten, Security und die garantierte Zustellung der Nachrichten an den Empfänger oder die Verschiebung in eine DLQ (Dead-Letter Queue), wenn der Empfänger die Nachricht nicht innerhalb der definierten Zeit entgegennimmt. In einer direkten beziehungsweise synchronen Kommunikation müssen diese Dinge immer wieder selbst implementiert, getestet und gewartet werden.Wartung ist ein gutes Stichwort: Sollten die Anwendungen in einer geplanten Wartung nicht verfügbar sein, bleibt die Nachricht wie beschrieben auf dem Message Broker gespeichert. Sobald die Anwendung den Wartungszustand verlässt und wieder verfügbar ist, werden die Nachrichten zugestellt. Der Gesamtprozess ist durch Wartung einzelner Anwendungen also nicht unterbrochen – ein wichtiges Merkmal von Messaging-Lösungen und ideal für unseren Anwendungsfall.Der Demo-Anwendungsfall
In diesem Artikel möchte ich Ihnen das Konzept der Messaging-Lösung vorstellen. Daher habe ich ein einfaches, nachvollziehbares Beispiel gewählt, um das zu realisieren. Wir behandeln nur die Kernkomponenten und werden keine ausformulierte Geschäftslogik implementieren. Am Ende erhalten Sie aber ein funktionsfähiges Beispiel für die Ende-zu-Ende-Kommunikation von Cloud zu On-Premises.Für unser Beispiel werden wir eine Azure Functions App (.NET 8) in Azure bereitstellen, die über einen HTTP-Trigger eine ZIP-Datei entgegennimmt. Diese ZIP-Datei enthält einzelne Bestelldateien, die wir von einem Partnerunternehmen über diese Schnittstelle erhalten. Die Functions App entpackt die Dateien und schickt jede einzelne Bestellung als Nachricht auf den Service Bus in eine Warteschlange. On-Premises ist ein ERP-System vorhanden, das eine standardisierte REST-Schnittstelle zur Verfügung stellt, damit Bestellungen auf diesem Wege übertragen werden können. Um die Nachrichten aus der Warteschlange entgegenzunehmen, wird ein .NET-8-Background-Worker implementiert, der dann auch die Kommunikation in Richtung ERP übernimmt (siehe Bild 1). Steigen Sie ein, der Service Bus auf der Linie 18 fährt heute nicht nach Istanbul, sondern nach On-Premises.
Architekturskizze zur Beispielanwendung (Bild 1)
Autor
Kurze Übersicht zu Azure Functions
Bevor wir starten, zunächst noch eine kurze Übersicht zu Azure Functions (siehe [2]). Azure Functions ist ein serverloser Compute-Dienst von Microsoft, der Entwicklern die Möglichkeit bietet, Anwendungen schnell und effizient zu erstellen und auszuführen.Ohne sich um Infrastruktur kümmern zu müssen, können Entwickler sich vollständig auf den Code konzentrieren. Hier sind die wichtigsten Eigenschaften von Azure Functions:1.Serverless Computing:- Automatische Skalierung: Azure Functions skaliert automatisch basierend auf der Last. Es werden nur Ressourcen genutzt, wenn der Code ausgeführt wird.
- Kostenoptimierung: Bezahlen Sie nur für die Rechenleistung, die Ihre Anwendung tatsächlich nutzt. Keine laufenden Kosten für ungenutzte Ressourcen.
- Vielseitigkeit: Entwickeln Sie Funktionen in einer Vielzahl von Sprachen, darunter C#, JavaScript, Python, Java und PowerShell. Dies ermöglicht Flexibilität bei der Wahl der Programmiersprache.
- Einfache Anbindung: Azure Functions integriert sich nahtlos mit anderen Azure-Diensten wie Azure Service Bus, Blob Storage, Event Grid und Cosmos DB. Diese Integration erleichtert die Erstellung von Workflows und datengetriebenen Anwendungen.
- Trigger und Bindungen: Azure Functions verwendet Trigger, um Funktionen bei bestimmten Ereignissen automatisch auszuführen, und Bindungen, um nahtlos auf Datenquellen zuzugreifen.
- Entwicklungsumgebung: Unterstützt sowohl lokale Entwicklung als auch die Entwicklung direkt im Azure-Portal. Funktionen lassen sich einfach über GitHub, Azure DevOps oder andere CI/CD-Pipelines bereitstellen.
- App-Service-Plattform: Azure Functions nutzt dieselbe bewährte Infrastruktur wie Azure App Service und bietet hohe Verfügbarkeit und Sicherheit.
- Rollenbasierte Zugriffskontrolle (RBAC): Fein abgestimmte Sicherheitsmodelle sorgen dafür, dass nur autorisierte Benutzer auf Funktionen zugreifen können.
- VNet-Integration: Ermöglicht die sichere Verbindung von Funktionen mit Ressourcen in einem virtuellen Netzwerk.
- Hohe Verfügbarkeit: Azure Functions bietet integrierte Redundanz und Ausfallsicherheit, um eine hohe Verfügbarkeit zu gewährleisten.
- Globale Verteilung: Funktionen können in verschiedenen Azure-Regionen bereitgestellt werden, um eine globale Reichweite und geringe Latenzzeiten zu gewährleisten.
- Consumption Plan: Automatische Skalierung basierend auf Ereignissen, ideal für variable Lasten.
- Premium Plan: Skalierung ohne Kaltstarts und zusätzliche Funktionen wie VNet-Integration.
- Dedicated (App Service) Plan: Läuft auf dedizierten VMs und bietet volle Kontrolle über die Skalierung.
- Application Insights: Integrierte Überwachung und Protokollierung ermöglichen es, die Performance von Funktionen zu analysieren und Fehler schnell zu identifizieren.
- End-to-End-Debugging: Unterstützung für Remote-Debugging und lokale Tests.
Einen Azure Service Bus Namespace erstellen
Lassen Sie uns starten, indem wir einen Service Bus Namespace anlegen. Der Namespace ist der Ort, an dem der Message Broker lebt.Die Erstellung des Service Bus Namespace kann über den Azure Marketplace (siehe Bild 2) gestartet werden. Suchen Sie im Marketplace nach Service Bus und bestätigen Sie über Erstellen. Unter Grundlegende Einstellungen wählen Sie Ihr Abonnement aus und wählen eine vorhandene Ressourcengruppe oder erstellen eine neue. Damit sind die Projektdetails gesetzt. Im Anschluss geht es an die Instanzdetails, wo Sie einen Namen für Ihren Namespace festlegen. Hier müssen Sie einen FQDN (Full Qualified Domain Name) vergeben, der weltweit eindeutig ist. Danach wählen Sie Ihren Standort aus, in dem der Namespace bereitgestellt werden soll, und zum Abschluss wählen Sie Ihren Tarif. Für die Demo ist die der Basic-Tarif völlig ausreichend. Alle weiteren Einstellungen auf den folgenden Reitern können Sie im Standard belassen. Die Provisionierung lässt sich einfach per Klick auf Überprüfen + erstellen direkt anstoßen.
Erstellung des Azure Service Bus Namespace im Azure Portal (Bild 2)
Autor
Warteschlange erstellen
Wie bereits erwähnt, ist der Service Bus Namespace der Speicherort für die Warteschlangen. Lassen Sie uns daher im nächsten Schritt eine Warteschlange erstellen. Gehen Sie wie in Bild 3 gezeigt vor.
Einrichtung einer Warteschlange im Service Bus Namespace (Bild 3)
Autor
Auf der Übersichtsseite Ihres erstellten Namespaces finden Sie die Schaltfläche + Warteschlange. Klicken Sie hier, um eine neue Warteschlange hinzuzufügen. Im darauffolgenden Dialog vergeben Sie einen Namen für die Warteschlange und passen die Parameter auf Ihre Bedürfnisse an. Sie können die Einstellungen auch im Standard belassen und auf Erstellen klicken.An dieser Stelle ist die Einrichtung des Service Bus (Namespace und Warteschlange) abgeschlossen. Wir werden später noch einmal zurückkehren, um die Verbindungszeichenfolge abzuholen, die wir für die Verbindung mit Azure Functions und dem Background-Worker benötigen.
Azure Functions App erstellen
Wir schließen die Bereitstellung in Azure mit dem Anlegen der Azure Functions App ab (siehe Bild 4). Diese benötigt eine Laufzeitumgebung für die Bereitstellung und Ausführung.
Erstellen der Azure Functions App (Bild 4)
Autor
Der Einstiegspunkt dafür ist wieder der Marketplace, und dort suchen Sie nach Funktions-App. Wählen Sie Verbrauch als Bereitstellungsmethode aus. Der Funktionsumfang, der mit dieser Bereitstellungsmethode zur Verfügung steht, reicht für unsere Demo aus.Unter den Grundlagen bei den Projektdetails definieren Sie Abonnement und Ressourcengruppe für die Bereitstellung. Bei den Instanzendetails wählen Sie wieder einen FQDN, der eindeutig sein muss. Als Runtime wählen Sie .NET in der Version 8 (LTS), isolated worker model (beachten Sie hierzu auch den Kasten Azure Functions Worker Model).
Azure Functions Worker Model
Azure Functions können als Isolated-Worker (wie in unserem Beispiel) oder im In-Process-Model ausgeführt werden. Das In-Process-Model wird ab dem 10. November 2026 nicht mehr unterstützt. Sie sollten sich daher bei Azure Functions für das Isolated-Model entscheiden.
Zum Abschluss wählen Sie noch Ihre Region und als Betriebssystem den Eintrag Windows. Alle anderen Reiter und die damit verbundenen Einstellungen können Sie im Standard belassen. Schließen Sie die Bereitstellung mit Überprüfen + erstellen ab.Die Functions App ist im Endeffekt ein Behälter, in dem die einzelnen Functions bereitgestellt und ausgeführt werden. Die Function, die die Geschäftslogik beinhaltet, wird in Visual Studio erstellt, implementiert und in der Functions App über die Option Publish veröffentlicht.Sie haben damit die Infrastruktur, die in Azure benötigt wird, erfolgreich angelegt. Lassen Sie uns jetzt mit dem starten, was Ihnen am meisten Freude bereitet: die Implementierung!
Erstellung der Visual Studio Solution
Alle Artefakte werden in einer Visual Studio Solution angelegt. Starten Sie mit der Erstellung des Azure-Functions-Projekts. Wählen Sie das entsprechende Projekttemplate aus und konfigurieren Sie als Worker-Runtime .NET 8 im Isolated-Worker Model. Wenn Sie hier eine andere Runtime wählen, können Sie die Azure Functions in Azure später nicht als Deployment-Target auswählen. Im nächsten Schritt erstellen Sie eine neue Function und wählen HttpTrigger aus. Sie haben nun eine Function erstellt, die einen HTTP-Endpunkt bereitstellt. Listing 1 zeigt die vollständige Implementierung für die Demo.Listing 1: Azure Function zum Empfangen der ZIP-Datei
<span class="hljs-keyword">using</span> Microsoft.Azure.Functions.Worker;<br/><span class="hljs-keyword">using</span> Microsoft.Extensions.Logging;<br/><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Http;<br/><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Mvc;<br/><span class="hljs-keyword">using</span> System.IO.Compression;<br/><span class="hljs-keyword">using</span> Azure.Messaging.ServiceBus;<br/><span class="hljs-keyword">namespace</span> <span class="hljs-title">FunctionApp</span><br/>{<br/> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmpfangeZipBestelldatei</span><br/> {<br/> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;EmpfangeZipBestelldatei&gt; <br/> _logger;<br/> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusClient <br/> _serviceBusClient;<br/> <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ServiceBusSender <br/> _serviceBusSender;<br/> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EmpfangeZipBestelldatei</span>(</span><br/><span class="hljs-function"><span class="hljs-params"> ILogger&lt;EmpfangeZipBestelldatei&gt; logger</span>)</span><br/><span class="hljs-function"> </span>{<br/> logger = logger;<br/> serviceBusClient = <span class="hljs-keyword">new</span> ServiceBusClient(<br/> <span class="hljs-string">"&lt;CONNECTIONSTRING&gt;"</span>);<br/> serviceBusSender = _serviceBusClient.CreateSender(<br/> <span class="hljs-string">"&lt;QUEUENAME&gt;"</span>);<br/> }<br/> [Function(<span class="hljs-string">"EmpfangeZipBestelldatei"</span>)]<br/> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">Run</span>(<span class="hljs-params">[HttpTrigger(</span></span><br/><span class="hljs-function"><span class="hljs-params"> AuthorizationLevel.Function, <span class="hljs-string">"post"</span></span>)] </span><br/><span class="hljs-function"> HttpRequest req)</span><br/><span class="hljs-function"> </span>{<br/> logger.LogInformation(<span class="hljs-string">"Received a request to </span><br/><span class="hljs-string"> process and send notifications."</span>);<br/> <span class="hljs-keyword">if</span> (!req.HasFormContentType || <br/> !req.Form.Files.Any())<br/> {<br/> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BadRequestObjectResult(<br/> <span class="hljs-string">"Please upload a ZIP file."</span>);<br/> }<br/> <span class="hljs-keyword">var</span> file = req.Form.Files.First();<br/> <span class="hljs-keyword">if</span> (file.Length == <span class="hljs-number">0</span> || !file.FileName.EndsWith(<br/> <span class="hljs-string">".zip"</span>, StringComparison.OrdinalIgnoreCase))<br/> {<br/> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BadRequestObjectResult(<br/> <span class="hljs-string">"The uploaded file is not a valid ZIP file."</span>);<br/> }<br/> <span class="hljs-keyword">try</span><br/> {<br/> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> zipStream = file.OpenReadStream())<br/> {<br/> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> archive = <span class="hljs-keyword">new</span> ZipArchive(<br/> zipStream, ZipArchiveMode.Read))<br/> {<br/> <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> entry <span class="hljs-keyword">in</span> archive.Entries)<br/> {<br/> <span class="hljs-keyword">using</span> (<span class="hljs-keyword">var</span> entryStream = entry.Open())<br/> {<br/> <span class="hljs-keyword">string</span> fileContent = <span class="hljs-keyword">new</span> StreamReader(<br/> entryStream).ReadToEnd();<br/> logger.LogInformation(<span class="hljs-string">$"<span class="hljs-subst">{fileContent}</span>"</span>);<br/> <span class="hljs-keyword">await</span> <br/> _serviceBusSender.SendMessageAsync(<br/> <span class="hljs-keyword">new</span> ServiceBusMessage(fileContent));<br/> }<br/> }<br/> }<br/> }<br/> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> OkObjectResult(<span class="hljs-string">"ZIP file processed </span><br/><span class="hljs-string"> and notifications sent successfully."</span>);<br/> }<br/> <span class="hljs-keyword">catch</span> (Exception ex)<br/> {<br/> logger.LogError(<br/> <span class="hljs-string">$"An error occurred: <span class="hljs-subst">{ex.Message}</span>"</span>);<br/> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StatusCodeResult(<br/> StatusCodes.Status500InternalServerError);<br/> }<br/> }<br/> }<br/>}
Microsoft stellt ein NuGet-Package zur Anbindung von Service Bus bereit (Azure.Messaging.ServiceBus). Referenzieren Sie dieses in Ihr Projekt. Alle anderen Infrastrukturkomponenten und Abhängigkeiten werden von der Azure Functions Runtime isoliert.Die Verbindung zum Service Bus bauen wir über die Verbindungszeichenfolge auf. Diese können Sie im Azure Portal im Service Bus Namespace auslesen (siehe Bild 5). Kopieren Sie die primäre oder sekundäre Verbindungszeichenfolge und übergeben Sie diese dem ServiceBusClient-Konstruktor. Der ServiceBusClient stellt die Verbindung zum Service Bus Namespace her.

Verbindungszeichenfolge ermitteln (Bild 5)
Autor
Im nächsten Schritt muss die Warteschlange initialisiert werden. Dazu wird dem ServiceBusSender der Name der Warteschlange als Parameter übergeben.
_serviceBusClient =
new ServiceBusClient("<CONNECTIONSTRING>");
_serviceBusSender =
_serviceBusClient.CreateSender("<QUEUENAME>");
Die Function hat den Namen EmpfangeZipBestelldatei und wird über HTTP ausgeführt. Die Function nimmt ausschließlich POST-Anfragen an.
[Function("EmpfangeZipBestelldatei")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function,
"post")] HttpRequest req){...}
Neben der Entpack-Logik erzeugt die Function für den Inhalt der jeweiligen Bestellung eine ServiceBusMessage und legt diese in die Warteschlange.ServiceBusMessage
await _serviceBusSender
.SendMessageAsync(
new ServiceBusMessage(
fileContent));
Bei Fehlern wird eine entsprechende Fehlermeldung erzeugt.Sie können die Function lokal testen und debuggen. Ich empfehle Ihnen den Postman-Client, damit Sie komfortabel eine ZIP-Datei an den HTTP-Endpunkt der Function senden können. Sie können aber auch gerne jedes andere Tool verwenden, um den Request abzuschicken. Wenn der Code fehlerfrei ausgeführt wird, können Sie sich die Nachrichten im Service Bus Explorer ansehen (siehe Bild 6). Wichtig zu verstehen ist hier, dass Sie die Nachrichten nur einsehen können, wenn Sie keinen Abnehmer der Daten haben. Zu diesem Zeitpunkt haben wir noch keinen. Den Background-Worker erstellen wir im nächsten Schritt.

Die Nachrichten im Service Bus Explorer (Bild 6)
Autor
Wenn Ihr Test erfolgreich war, können Sie mit dem Veröffentlichen Ihrer Version nach Azure beginnen. Dazu wählen Sie Veröffentlichen im Projektkontextmenü aus und folgen dem Dialog wie in Bild 7. Wählen Sie Ihr Abonnement und die entsprechende Ressourcengruppe aus und klicken Sie auf die Azure Function, die Sie am Anfang erstellt haben. Schließen Sie den Dialog ab und warten Sie, bis die Bereitstellung erfolgreich ist. Ihre Function ist jetzt in Azure verfügbar.

Veröffentlichen der Azure Function (Bild 7)
Autor
Damit Sie den Aufruf gegen die Azure Function in der Cloud ausführen können, brauchen Sie den Endpunkt mit entsprechendem Schlüssel. Dieser wird benötigt, damit kein unautorisierter Aufruf der Function aus dem Internet erfolgen kann. Das ist wichtig, denn die Function steht jetzt im Public Internet zur Verfügung.Für den Abruf des Endpunkts gehen Sie zur Übersichtsseite der Function App Resource in Azure (siehe Bild 8). Klicken Sie auf die entsprechende Funktion und wählen Sie Funktions-URL abrufen (siehe Bild 9). Kopieren Sie eine der Adressen und führen Sie dann die Anfrage mit dem Tool Ihrer Wahl aus (siehe Bild 10). Wenn die Anfrage erfolgreich war, sehen Sie die Nachrichten im Service Bus Explorer.

Übersichtsseite der Azure Function Resource in Azure (Bild 8)
Autor

Abruf des URL für die Azure Function (Bild 9)
Autor

Aufruf der Function mit Postman (Bild 10)
Autor
Erstellung des .NET 8 Background Worker
Sie haben erfolgreich Nachrichten an die Service-Bus-Warteschlange gesendet. Schon jetzt haben Sie einen großen Vorteil der Messaging-Lösung kennengelernt, der am Anfang erwähnt wurde: Ihre Nachrichten werden gespeichert, ohne dass ein Empfänger für die Nachrichten da ist (quasi nicht zu Hause ist). In Fällen von wartungsbedingten oder unvorhergesehenen Systemausfällen verlieren Sie mit diesem Ansatz keine Daten. Machen wir uns also daran, einen Empfänger für die Nachrichten aus der Warteschlange zu implementieren. Als Template bietet sich der Background-Worker an, da er „unendlich“ läuft.Legen Sie dazu in der Visual Studio Solution ein neues.NET-8-Worker-Projekt an. In Listing 2 finden Sie die komplette Implementierung des Workers. Wie bei der Function nutzen wir für die Verbindung zum Service Bus wieder das NuGet-Package Azure.Messaging.ServiceBus. Dem ServiceBusClient wird die Verbindungszeichenfolge als Parameter übergeben. Damit ist die Verbindung zum Service Bus Namespace aufgebaut.
Listing 2: Empfang der Nachrichten aus dem Service Bus
using Azure.Messaging.ServiceBus;<br/>namespace ServiceBusWorker;<br/>public class Worker : BackgroundService<br/>{<br/> private readonly ILogger&lt;Worker&gt; _logger;<br/> private readonly ServiceBusClient _serviceBusClient;<br/> private readonly ServiceBusProcessor <br/> _serviceBusProcessor;<br/> public Worker(ILogger&lt;Worker&gt; logger)<br/> {<br/> logger = logger;<br/> serviceBusClient = new ServiceBusClient(<br/> "&lt;CONNECTIONSTRING&gt;");<br/> serviceBusProcessor = _serviceBusClient<br/> .CreateProcessor("&lt;QUEUENAME&gt;");<br/> serviceBusProcessor.ProcessMessageAsync += <br/> _serviceBusProcessor_ProcessMessageAsync;<br/> serviceBusProcessor.ProcessErrorAsync += <br/> _serviceBusProcessor_ProcessErrorAsync;<br/> }<br/> private async Task <br/> _serviceBusProcessor_ProcessMessageAsync(<br/> ProcessMessageEventArgs arg)<br/> {<br/> var bestellung = arg.Message.Body.ToString();<br/> // Hier findet nun die Verarbeitung der Bestellung <br/> // statt. Validierung etc., Transfer ins ERP<br/> // Wenn keine Fehler aufgetreten sind, kann die<br/> // Nachricht im Service Bus gelöscht werden.<br/> logger.LogInformation(<br/> $"On-Premises-Worker: Bestellung empfangen. <br/> Inhalt der Datei: {bestellung}");<br/> await arg.CompleteMessageAsync(arg.Message);<br/> }<br/> private Task _serviceBusProcessor_ProcessErrorAsync(<br/> ProcessErrorEventArgs arg)<br/> {<br/> logger.LogCritical("Fehler bei der Verarbeitung <br/> der Bestelldateien.");<br/> return Task.CompletedTask;<br/> }<br/> protected override async Task ExecuteAsync(<br/> CancellationToken stoppingToken)<br/> {<br/> await _serviceBusProcessor.StartProcessingAsync(<br/> stoppingToken);<br/> while (!stoppingToken.IsCancellationRequested)<br/> {<br/> if (logger.IsEnabled(LogLevel.Information))<br/> {<br/> logger.LogInformation("Worker running at: <br/> {time}", DateTimeOffset.Now);<br/> }<br/> await Task.Delay(1000, stoppingToken);<br/> }<br/> }<br/>}
Jetzt erstellen wir zum Empfang der Nachrichten aus der Warteschlange einen ServiceBusProcessor. Dieser bekommt den Namen der Warteschlange als Parameter übergeben.
serviceBusClient =
new ServiceBusClient("<CONNECTIONSTRING>");
serviceBusProcessor = _serviceBusClient.CreateProcessor(
"<QUEUENAME>");
Der ServiceBusProcessor ist ein Observer, in dem zwei Events registriert und implementiert werden müssen:
serviceBusProcessor.ProcessMessageAsync +=
_serviceBusProcessor_ProcessMessageAsync;
serviceBusProcessor.ProcessErrorAsync +=
_serviceBusProcessor_ProcessErrorAsync;
ProcessMessageAsync wird aufgerufen, sobald eine neue Nachricht in der Warteschlange verfügbar ist, und ProcessErrorAsync wird für Fehlerfälle benötigt. In der ProcessMessageAsync wird die Logik zum Empfang und zur weiteren Verarbeitung der Nachricht implementiert. In diesem Fall packen wir die Payload der Nachricht – die Bestellung – aus und speichern diese als variable, damit wir diese auf der Konsole ausgeben (siehe Bild 11). Die Logik zum ERP enfällt hier.

Ausgabe der Nachrichten aus dem Service Bus (Bild 11)
Autor
Zum Abschluss muss die Nachricht im Service Bus als verarbeitet gemeldet werden.
await arg.CompleteMessageAsync(arg.Message);
Wird das nicht gemacht, wird die Nachricht im definierten Zeitraum immer wieder an den Empfänger übergeben (Guaranteed Delivery), bevor sie in der Dead-Letter Queue landet.Damit der ServiceBusProcessor seine Arbeit aufnehmen kann, müssen Sie ihn starten. Das passiert in der Execute-Methode des Workers mit folgendem Aufruf:
await _serviceBusProcessor.StartProcessingAsync(
stoppingToken);
Sie haben ein Ende-zu-Ende-Szenario aus der Cloud (Azure) auf Ihre On-Premises-Umgebung (Background-Worker) mithilfe von Service Bus implementiert. Vielen Dank für Ihre Fahrt mit unserem Service Bus!
Zusammenfassung
Sichere Kommunikation ist auch dann möglich, wenn Cloud und On-Premises-Systeme nicht über ein VPN-Gateway oder Ähnliches miteinander verbunden sind. Der leichtgewichtige, aber durchaus sichere Ansatz kommt ohne hohen administrativen Aufwand aus und bremst die Innovationsfähigkeit nicht aus.Auf der anderen Seite sind verteilte Systeme sehr komplex, und Sie oder Ihr Team benötigen das Hintergrundwissen über Azure Functions und Service Bus. Auch wenn es sich hierbei um Serverless-Angebote handelt, ist ein fundamentales Wissen notwendig.Fussnoten
- Microsoft Learn, Was ist Azure Service Bus?, http://www.dotnetpro.de/SL2411CloudOnPrem1
- Microsoft Learn, Übersicht zu Azure Functions, http://www.dotnetpro.de/SL2411CloudOnPrem2
- Azure Portal, https://portal.azure.com