Generate a Kiota client at build time from an ASP.NET Core OpenAPI file

 
 
  • Gérald Barré

In a previous post, I explained how to generate the OpenAPI document during the ASP.NET Core build and commit it to the repository. That gives you a versioned API contract that is easy to review in pull requests.

In this post, let's go one step further: use that generated OpenAPI file as the input for Kiota, so your typed .NET client is also generated during build.

The goal is simple:

  1. The server produces the OpenAPI document at build time.
  2. The client project references that OpenAPI file.
  3. Kiota runs during build only when the OpenAPI file changes.

Building the solution should then produce an updated OpenAPI file and regenerate the client if needed, all in one go.

#Generate the OpenAPI file in the server project

In the Web API project, configure build-time OpenAPI generation:

XML
<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>net10.0</TargetFramework>

        <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
        <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
        <OpenApiGenerateDocumentsOnBuild>true</OpenApiGenerateDocumentsOnBuild>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.8" />
        <PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="10.0.8">
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
            <PrivateAssets>all</PrivateAssets>
        </PackageReference>
    </ItemGroup>
</Project>

After dotnet build, the OpenAPI document is generated next to the project (for example WebApi.json). Commit this file so it is tracked and reviewed.

#Reference the OpenAPI file from the client project

In the client project, reference the server project only to enforce build order, and define the OpenAPI file path:

XML
<ItemGroup>
    <ProjectReference Include="..\WebApi\WebApi.csproj" ReferenceOutputAssembly="false" />
</ItemGroup>

<PropertyGroup>
    <ApiSpecFile>$(MSBuildThisFileDirectory)..\WebApi\WebApi.json</ApiSpecFile>
    <KiotaOutputDir>$(MSBuildThisFileDirectory)Generated</KiotaOutputDir>
    <KiotaStampFile>$(IntermediateOutputPath)kiota.stamp</KiotaStampFile>
</PropertyGroup>

ReferenceOutputAssembly="false" ensures the API project builds first, but the client assembly does not directly reference the server assembly.

#Run Kiota from MSBuild

Install Kiota as a local .NET tool (recommended so builds do not depend on a global installation):

Shell
dotnet new tool-manifest
dotnet tool install Microsoft.OpenApi.Kiota

Then run Kiota from custom MSBuild targets:

XML
<Target Name="RestoreKiotaTool" BeforeTargets="GenerateKiotaClient">
    <Exec Command="dotnet tool restore" />
</Target>

<Target Name="GenerateKiotaClient"
                BeforeTargets="BeforeCompile"
                DependsOnTargets="RestoreKiotaTool"
                Inputs="$(ApiSpecFile)"
                Outputs="$(KiotaStampFile)">
    <Exec Command='dotnet kiota generate -l CSharp -d &quot;$(ApiSpecFile)&quot; -c ApiClient -n MyCompany.MyApi.Client -o &quot;$(KiotaOutputDir)&quot; --clean-output' />
    <Touch Files="$(KiotaStampFile)" AlwaysCreate="true" />
</Target>

<ItemGroup>
    <Compile Include="Generated\**\*.cs" />
</ItemGroup>

The important part is Inputs and Outputs on GenerateKiotaClient:

  • If $(ApiSpecFile) did not change since the last build, MSBuild skips the target.
  • If the OpenAPI file changed, Kiota regenerates the client.

This keeps builds fast while still ensuring the client stays aligned with the current contract.

#Required Kiota runtime dependencies

The generated code needs Kiota runtime packages. For .NET, the simplest option is:

Shell
dotnet add package Microsoft.Kiota.Bundle

Depending on your authentication scenario, you may also need packages such as Microsoft.Kiota.Authentication.Azure and Azure.Identity.

#Typical developer workflow

With this setup, the workflow is straightforward:

  1. Change an endpoint or model in the server.
  2. Run dotnet build.
  3. Review changes in both WebApi.json and generated client files.
  4. Commit everything together.

This makes contract evolution explicit and safe. If an API change is accidental, you usually notice it immediately in the OpenAPI diff or in generated client changes.

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?