
Protobufs delen tussen projecten & AI-integratie
Schaalbare architectuur vraagt om strakke samenwerking. Die begint bij duidelijke afspraken tussen services. Met gedeelde protobuf-contracten leg je vast wat werkt, voorkom je ruis en bouw je door met tempo.
1) Waarom protobufs delen tussen projecten?
Door protobufs te delen, communiceren services consistent met elkaar, kunnen teams sneller ontwikkelen dankzij hergebruik en ontstaan er minder bugs en integratieproblemen. Bovendien maakt het een gecontroleerde evolutie van API’s mogelijk zonder steeds opnieuw het wiel uit te vinden. Tegelijkertijd brengt dit ook risico’s met zich mee: breaking changes kunnen clients onverwacht breken, versiebeheer kan complex worden en teams kunnen te sterk van elkaar afhankelijk raken.
Daarbovenop komen praktische problemen zoals distributie en het gevaar dat lokale kopieën van contracten langzaam verouderen. Deze risico’s zijn echter goed te beheersen door protobuf-contracten te centraliseren in een gedeelde repository of package, automatische validatie toe te passen met tools zoals Buf, duidelijke wijzigingsregels te documenteren en distributie te borgen via CI/CD-pipelines. Zo blijven gedeelde protobufs een versneller in plaats van een rem.
Architectuurdiagram – Protobuf sharing & gRPC

2) Strategieën om protobufs te delen
Optie 1: Shared NuGet package (gegenereerde C# types)
Genereer C#-klassen uit .proto en publiceer deze als NuGet-pakket. Consumers nemen alleen het pakket op en gebruiken de gegenereerde types.
Voorbeeld contracts-project (.csproj):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>MyCompany.AI.Contracts</PackageId>
<Version>1.2.0</Version>
<Description>Protobuf-based contracts for AI services</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.66.0" />
<PackageReference Include="Grpc.Tools" Version="2.66.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="protos\ai.proto" GrpcServices="Client;Server" ProtoRoot="protos" />
</ItemGroup>
</Project>
Consumer-project voegt het NuGet-pakket toe en gebruikt de types:
<ItemGroup>
<PackageReference Include="MyCompany.AI.Contracts" Version="1.2.0" />
</ItemGroup>
Optie 2: NuGet package met .proto-bestanden (consumers compileren zelf)
Publiceer de originele .proto-bestanden in het pakket zodat ieder project zelf kan genereren (ook multi-language).
Producer (.csproj):
<ItemGroup>
<None Include="protos\ai.proto" Pack="true" PackagePath="contentFiles/any/any/protos/ai.proto" />
</ItemGroup>
Consumer (.csproj):
<ItemGroup>
<PackageReference Include="Grpc.Tools" Version="2.66.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="$(UserProfile)\.nuget\packages\mycompany.ai.proto\1.2.0\contentFiles\any\any\protos\ai.proto" GrpcServices="Client;Server" />
</ItemGroup>
Optie 3: Git Submodule / Monorepo
Koppel een centrale contracts-repository als submodule in services/clients. Iedereen bouwt tegen dezelfde bron.
git submodule add https://git.example.com/contracts-proto contracts
git submodule update --init --recursive
Consumer (.csproj):
<ItemGroup>
<PackageReference Include="Grpc.Tools" Version="2.66.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="contracts/ai.proto" GrpcServices="Client;Server" ProtoRoot="contracts" />
</ItemGroup>
Bonus: Schema Registry & linting (Buf)
Gebruik Buf voor linting, breaking-change checks en een centrale registry. Hiermee bewaak je compatibiliteit automatisch en vereenvoudig je distributie.

3) Compatibiliteitsregels (uitgebreid)
- Wijzig nooit een bestaand field-nummer
- Gebruik reserved voor verwijderde velden/namingen
- Voeg velden toe i.p.v. verwijderen (opt-in)
- Introduceer nieuwe berichten bij grote wijzigingen (bijv. UserV2)
- Automatiseer compatibiliteitschecks (Buf) in CI/CD
Testmatrix
- Oude client ↔ nieuwe server
- Nieuwe client ↔ oude server
4) AI integreren met gRPC en gedeelde protobufs (uitgebreid)
Proto-contract (gedeeld via NuGet of Git submodule)
syntax = "proto3";
package ai;
option csharp_namespace = "MyCompany.AI.Proto";
service AiInference {
rpc Classify (ClassifyRequest) returns (ClassifyResponse);
rpc Embed (EmbedRequest) returns (EmbedResponse);
rpc GenerateStream (GenerateRequest) returns (stream GenerateChunk);
}
message ClassifyRequest {
string text = 1;
}
message ClassifyResponse {
string label = 1;
float confidence = 2;
}
message EmbedRequest {
repeated string inputs = 1;
}
message EmbedResponse {
repeated Vector vectors = 1;
}
message Vector {
repeated float values = 1;
}
message GenerateRequest {
string prompt = 1;
int32 max_tokens = 2;
}
message GenerateChunk {
string text = 1;
bool is_final = 2;
}
Server-implementatie (.NET, vereenvoudigd)
public class AiInferenceService : AiInference.AiInferenceBase
{
public override Task<ClassifyResponse> Classify(ClassifyRequest request, ServerCallContext context)
{
// TODO: roep AI-model aan
return Task.FromResult(new ClassifyResponse { Label = "positive", Confidence = 0.92f });
}
public override Task<EmbedResponse> Embed(EmbedRequest request, ServerCallContext context)
{
var resp = new EmbedResponse();
foreach (var _ in request.Inputs)
resp.Vectors.Add(new Vector { Values = { 0.1f, 0.2f, 0.3f } });
return Task.FromResult(resp);
}
public override async Task GenerateStream(GenerateRequest request, IServerStreamWriter<GenerateChunk> stream, ServerCallContext context)
{
var tokens = new[] { "Hallo", " ", "wereld", "!" };
foreach (var t in tokens)
{
await stream.WriteAsync(new GenerateChunk { Text = t, IsFinal = false });
}
await stream.WriteAsync(new GenerateChunk { Text = "", IsFinal = true });
}
}
Client (C# streaming-voorbeeld)
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new AiInference.AiInferenceClient(channel);
using var call = client.GenerateStream(new GenerateRequest { Prompt = "Schrijf een haiku over gRPC" });
await foreach (var chunk in call.ResponseStream.ReadAllAsync())
{
Console.Write(chunk.Text);
if (chunk.IsFinal) Console.WriteLine("\n[done]");
}
Serverconfiguratie (ASP.NET Core)
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<AiInferenceService>();
});
}
gRPC-Web inschakelen (browser-clients)
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<AiInferenceService>().EnableGrpcWeb();
});
Met Protobuf behoud je overzicht én tempo
Protobuf vormt het fundament onder stabiele gRPC architecturen en speelt een directe rol in het beheersbaar houden van AI integraties. Door Protobuf contracten centraal te delen, werken teams vanuit één duidelijke afspraak en verdwijnen inconsistenties tussen services en clients. Dat voorkomt fouten, versnelt ontwikkeling en houdt de communicatie strak, ook wanneer meerdere teams tegelijk bouwen.
Met goed ingericht Protobuf beheer blijven API wijzigingen onder controle en behoud je overzicht, zelfs bij groei. Tools zoals Buf en CI CD pipelines signaleren breaking changes vroeg en zorgen dat Protobuf contracten gecontroleerd worden verspreid. In de praktijk, bijvoorbeeld bij AI services die communiceren met microservices en webapplicaties, bewijst Protobuf zijn waarde elke dag. Dezelfde contracten zorgen dat integraties direct kloppen en blijven werken. Wie vandaag kiest voor een centrale Protobuf aanpak, houdt tempo, maakt ruimte voor AI en bouwt IT die doet wat nodig is.
Hulp nodig met je Protobuf beheer?
Deze blog is geschreven door Justin Veenis, Software Developer | Fullstack(.Net + Angular)
Delta-N helpt organisatie hierbij. We inspireren, faciliteren, configureren, begeleiden en verbeteren de inzet van de oplossingen die het beste passen bij jouw organisatie. We vertellen er graag meer over! [Neem contact op]
Deel dit bericht
