15. Okt. 2026
Microsoft Kiota
Den Auftakt macht Microsoft Kiota: ein Open-Source-Werkzeug zur Generierung typsicherer HTTP-API-Clients und der dazugehörigen Entitäten. Neben C#, das wir verwenden, unterstützt Kiota auch Go, Java, TypeScript, PHP, Python und weitere Sprachen.
Wer schon einmal manuell einen HTTP-Client für eine REST-API geschrieben hat, kennt das Spiel: Endpunkte abtippen, DTOs von Hand pflegen, bei jeder API-Änderung alles erneut durchgehen – und hoffen, nichts übersehen zu haben. Spätestens beim dritten API-Client im Projekt stellt sich die Frage, ob es sich wirklich lohnt, das Rad jedes Mal neu zu erfinden. Statt die Clients von Hand zu schreiben, generieren wir die benötigten Clients auf Basis einer OpenAPI-Beschreibung.
Installation
Anfangen müssen wir natürlich mit der Grundlage, denn Kiota ist ein dotnet-Tool, welches wir zunächst installieren müssen. Mittels dotnet-CLI lässt sich Microsoft Kiota einfach installieren:
dotnet tool install Microsoft.OpenApi.KiotaIntegration in den Build-Prozess
Hier wird es jetzt interessanter: Wir lassen den HTTP-Client und die zugehörigen Entitäten während des Build-Prozesses generieren. Für diese Aufgabe haben wir ein eigenes Projekt erstellt.
Die eigentliche Magie liegt in Command_Kiota_File1, wo Kiota konfiguriert wird. Welche Bedeutung die einzelnen Parameter haben, ist in der Dokumentation von Microsoft beschrieben.
<PropertyGroup>
<Command_Kiota_File1>
<![CDATA[
dotnet tool run kiota generate ^
--clean-output ^
--additional-data false ^
-l csharp ^
-c MyApiClient ^
-n MyNameSpace.Inbound ^
-d Specification/file-1.yml ^
-o Generated/Inbound
]]>
</Command_Kiota_File1>
</PropertyGroup>Jetzt muss Kiota beim Build natürlich auch ausgeführt werden. Zunächst legen wir dafür ein Target an. Den Namen vergeben wir selbst – im Beispiel GenerateClient – und definieren, wann alles ausgeführt werden soll. In unserem Fall soll das Target vor dem eigentlichen Build-Prozess laufen.
<Target Name="GenerateClient"
BeforeTargets="BeforeCompile;CoreCompile">
In diesem Target lassen wir zunächst die .NET-Tools wiederherstellen, bevor es zu den eigentlichen Ausführungen geht.
<!-- First, restore the .NET tools in case Kiota is not installed yet -->
<Exec WorkingDirectory="$(ProjectDir)"
ContinueOnError="false"
Command="dotnet tool restore" />
<!-- Execute the Kiota command -->
<Exec WorkingDirectory="$(ProjectDir)"
ContinueOnError="false"
Command="$(Command_Kiota_File1)" />Das ist tendenziell schon alles, was getan werden muss. Aber ...
Optimierungen und bekannte Probleme
Auch wenn in der Theorie alles erledigt ist, gibt es doch immer wieder Verbesserungen oder gar Steine im Weg.
Inkrementelle Generierung
Zunächst soll verhindert werden, dass bei wirklich jedem Build die Dateien generiert werden. Dazu bringt die Projektdatei freundlicherweise bereits alles Notwendige mit.
Wir lassen den Generierungsstatus mittels einer .done-Datei überwachen. Dazu wird das Target um Inputs und Outputs ergänzt. Beim Build prüft MSBuild dann, ob die Inputs neuer sind als unsere .done-Datei. Ist diese Datei nicht vorhanden, legt MSBuild sie automatisch an – siehe Touch.
<Target Name="GenerateClient"
BeforeTargets="BeforeCompile;CoreCompile"
Inputs="./Specification/file-1.yml;./Specification/file-2.yml"
Outputs="$(ProjectDir)/Generated/kiota-generate.done">
<Touch Files="$(ProjectDir)/Generated/kiota-generate.done"
AlwaysCreate="true" />
...Generierte Dateien in der Azure-Build-Pipeline
Des Weiteren war die Azure-Build-Pipeline der Meinung, die frisch generierten Dateien seien nicht vorhanden. Dafür war noch eine Ergänzung im Target nötig, damit die Dateien in den Build einbezogen werden.
<ItemGroup>
<Compile Include="$(ProjectDir)/Generated/**/*.cs" />
</ItemGroup>Problem bei der Verarbeitung von oneOf
Ein Problem mit Kiota in Verbindung mit C# gibt es jedoch. In unserer OpenAPI-Spezifikation verwendeten wir ein oneOf-Schema, das durch Kiota zu einem nicht nutzbaren Objekt generiert wurde.
# test.yml
components:
schemas:
FullDate:
type: string
format: date
example: '2026-12-24'
YearMonth:
type: string
pattern: '^\d{4}-(0[1-9]|1[0-2])$'
example: '2026-12'
NonWorkingDate:
oneOf:
- $ref: '#/components/schemas/FullDate'
- $ref: '#/components/schemas/YearMonth'
description: >-
Date (exact date or year-month)Daraus erstellt Kiota die Klassen FullDate und YearMonth, soweit zunächst wie erwartet. Beide Klassen waren allerdings ohne Properties und somit nicht nutzbar.
Wir mussten das Problem so lösen, dass beide Felder einzeln eingebaut werden. Anschließend prüfen wir manuell, welches der beiden Felder gesetzt ist.
Vollständige Projektdatei
Die fertige Projektdatei sieht wie folgt aus:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<!-- Versions are defined in Directory.Build.Props -->
<PackageReference Include="Microsoft.Kiota.Bundle" />
</ItemGroup>
<Target Name="GenerateClient"
BeforeTargets="BeforeCompile;CoreCompile"
Inputs="./Specification/file-1.yml;./Specification/file-2.yml"
Outputs="$(ProjectDir)/Generated/kiota-generate.done">
<!-- Recreate the folder so that classes no longer in use are also deleted -->
<RemoveDir Directories="Generated/" />
<MakeDir Directories="Generated" />
<Touch Files="$(ProjectDir)/Generated/kiota-generate.done" AlwaysCreate="true" />
<!-- First, restore the .NET tools in case Kiota is not installed yet -->
<Exec WorkingDirectory="$(ProjectDir)" ContinueOnError="false" Command="dotnet tool restore" />
<!-- Execute the Kiota command for file-1.yml -->
<Exec WorkingDirectory="$(ProjectDir)" ContinueOnError="false" Command="$(Command_Kiota_File1)" />
<!-- Add Exec commands for additional files, e.g. file-2.yml -->
<ItemGroup>
<Compile Include="$(ProjectDir)/Generated/**/*.cs" />
</ItemGroup>
</Target>
<PropertyGroup>
<Command_Kiota_File1>
<![CDATA[
dotnet tool run kiota generate ^
--clean-output ^
--additional-data false ^
-l csharp ^
-c MyApiClient ^
-n MyNameSpace.Inbound ^
-d Specification/file-1.yml ^
-o Generated/Inbound
]]>
</Command_Kiota_File1>
<!-- Add command definitions for additional files, e.g. file-2.yml -->
</PropertyGroup>
</Project>