Die Blob REST API
Zur systemagnostischen Interaktion hat Microsoft die Blob Storage REST API zur Verfügung gestellt. Diese stellt, wie der Name schon sagt, eine REST-API für den Blob Storage bereit, mit der man recht einfach mit den üblichen HTTP-Verben arbeiten kann. Die Basis-URL ist dabei immer von der Form storacc123.blob.core.windows.net/container456.
Blobs anlegen
Als erste Operation schauen wir uns das Anlegen von Blob an. Dazu senden wir einen PUT-Request an die Basis-URL mit angehängtem Blob-Namen, z.B. storacc123.blob.core.windows.net/container456/blob789
Blobs auflisten
Um eine Liste aller Blobs in einem Container zu erhalten, senden wir einfach einen GET-Request an die Basis-URL, hängen aber noch den URL-Parameter comp=list an, also z.B so: storacc123.blob.core.windows.net/container456
Man erhält dann ein XML, in dem die Blobs mit allen Metainformationen aufgelistet sind. Die Namen der Blobs lassen sich mit dem XPath „/EnumerationResults/Blobs/Blob/Name“ finden.
Blobs herunterladen
Auch das ist ein einfacher GET-Request, diesmal aber mit dem Blob-Namen in der URL wie beim Anlegen. Der Blob kommt das ungefiltert als Antwort zurück.
Blobs löschen
Letztendlich will man die Blobs natürlich auch wieder loswerden. Dazu sendet man einfach einen DELETE-Request and dieselbe URL wie beim Hoch- und Runterladen. Die Antwort ist leer.
Authentifizierung
Selbsverständlich können wir den Zugriff auf den Blob Storage beschränken. Microsoft bietet hierfür Shared Access Signatures (SAS) an, am besten in Kombination mit Access Policies. Diese lässt sich in Form von URL-Parametern einfach an die URL dranhängen.
Die Blob API mit BizTalk Server benutzen
Im Port
Da wie gesagt BizTalk Server 2016 und früher keine Blob-Storage-Adapter haben, nehmen wir stattdessen einen WCF-WebHttp-Adapter, über den wir die REST-API ansprechen. Als URI setzen wir die Basis-URL ein, und das HTTP Method and URL Mapping setzen wir zum Beispiel folgendermaßen:
<BtsHttpUrlMapping>
<Operation Name="RequestList" Method="GET"
Url="?comp=list&restype=container&sp={sp}&st={st}&se={se}&spr={spr}&sv={sv}&sr={sr}&sig={sig}" />
<Operation Name="RequestBlob" Method="GET" Url="/{blobname}?sp={sp}&st={st}&se={se}&spr={spr}&sv={sv}&sr={sr}&sig={sig}" />
<Operation Name="DeleteBlob" Method="DELETE" Url="/{blobname}?sp={sp}&st={st}&se={se}&spr={spr}&sv={sv}&sr={sr}&sig={sig}" />
<Operation Name="UploadBlob" Method="PUT" Url="/{blobname}?sp={sp}&st={st}&se={se}&spr={spr}&sv={sv}&sr={sr}&sig={sig}" />
</BtsHttpUrlMapping>
Die SAS benutzt in diesem Beispiel keine Access Policy und auch keine IP-Adressenbeschränkungen. Die Variablen werden wie üblich über Context Properties gefüllt. Etwas abenteuerlustige Naturen können die SAS auch direkt in das Binding schreiben und sich somit das Hantieren mit Context Properties sparen, haben dann aber mehr Arbeit, wenn die SAS ausgetauscht werden muss.
Außerdem muss im Messages-Tab unter Suppress Body for Verbs noch GET, DELETE eingetragen werden, da einerseits diese Verben keinen Body erlauben, andererseits aber BizTalk nicht das Versenden von leeren Nachrichten unterstützt.
In der Orchestration
Auch das ist recht simpel, wenn auch nicht ganz so simpel wie unter BizTalk Server 2020. Außer beim Anlegen von Blobs ist der Inhalt der Nachricht irrelevant, sollte aber nicht unnötig groß sein. Beim Anlegen sollte die Nachricht natürlich der Inhalt des Blob sein. Dann setzt man noch die nötigen Context Properties (bei allem, was nicht List ist also mindestens den Blob-Namen) und schickt die Nachricht an einen Port wie diesen:
Die Operationen (DeleteBlob, RequestBlob, RequestList) entsprechen den Operationen im Port und werden in diesem ensprechend verwendet. Alle Nachrichten sind vom Typ XmlDocument, auch wenn sie nicht immer XML enthalten. Ein UploadBlob fehlt hier, weil es bei dem spezifischen Kundenprojekt nicht nötig war.
Receive Locations
Der Blob-Storage-Adapter von BizTalk Server 2020 lässt sich auch zum Empfangen von Blobs nutzen. Diese Möglichkeit haben wir in BizTalk Server 2020 nicht. Aber auch hier gibt es Alternativen. Zum einen kann man über einen Timer (z.B. Sandro Pereiras Schedule Adapter) periodisch eine Orchestration aufrufen, welche die Blobs listet und sie dann nacheinander herunterlädt und weiterverarbeitet.
Etwas eleganter – jedenfalls in den Augen des Autors – und schneller ist es, über den Event Grid das Anlegen eines Blobs an den Azure Service zu kommunizieren, und über diese Service-Bus-Nachricht den Download des Blobs zu veranlassen. Das lässt sich mit zwei Aufrufen des Azure CLI erledigen:
az eventgrid system-topic create --name blobcreatetopic --resource-group backup-storage-rg --topic-type microsoft.storage.storageaccounts --source "/subscriptions/$subscription/resourcegroups/$storageResourceGroup/providers/Microsoft.Storage/storageAccounts/$storageAccount" --location $storageLocation --subject-begins-with "/blobServices/default/containers/$container/blobs/"
az eventgrid system-topic event-subscription create --name BlobCreate -g backup-storage-rg --system-topic-name blobcreatetopic --endpoint-type ServiceBusTopic --endpoint "/subscriptions/$subscription/resourceGroups/$sbResourceGroup/providers/Microsoft.ServiceBus/namespaces/$namespace/topics/$topic" --included-event-types "Microsoft.Storage.BlobCreated"
Die Variable müssen vorher natürlich sinnvoll gesetzt werden. Der Service-Bus-Topic muss bereits existieren. Der Service Bus muss mindestens Standard Tier sein, da das Basic Tier keine Topics unterstützt.
Dann muss nur noch eine SB-Messaging Receive Location angelegt werden, die auf dem entsprechenden Topic lauscht. Die Blob-Created-Nachricht, die dort empfangen wird, enthält unter dem JSONPath „$.data.url“ die URL des erzeugten Blobs, die dann auch gleich zum Herunterladen benutzt werden kann.
Fazit
Auch wenn der Blob-Storage-Adapter in BizTalk Server 2020 vieles einfacher macht, so ermöglicht es insbesondere die REST API, ohne größeren Aufwand Blobs zu empfangen und anzulegen. Auch der Event Grid und Service Bus tragen sehr dazu bei, die Verarbeitung von Blobs zu vereinfachen und beschleunigen. Eine einfache Lösung lässt sich in weniger als zwei Tagen auf die Beine stellen.