gRPC und Blazor

gRPC ist so ein Thema, das bei mir Erstaunen hervorruft. Kurz zur geschichtlichen Einordnung. In einer Client Server Welt ist es seit Dekaden notwendig Funktionen remote aufzurufen. Da gab es Ansätze wie Corba oder in der Microsoft Welt DCOM. Irgendwann in Windows NT kam der passende Service COM+ Enterprise Services. Tolles Zeugs das zuverlässig seinen Dienst tat. Im Zuge von .NET wurden dann abstrahierte Dienste wie zuerst .NET Remoting und ASMX Webservices und später das Universalmonster WCF verwendet. Nun finde ich WCF nicht schlecht aber neudeutsch “overengineering” nach Lehrbuch. Persönlich habe ich die ASP.NET Web Services gern genommen, weil einfach und interoperabel. Nun hat im Jahre 2000 Roy berühmte Dissertation REST zum defacto Standard erhoben, mit JSON als Formater statt XML. Das kam den hungerleidenden JavaScript Entwicklern gerade recht. So ein Browser ist eben kein Server und hat mit XML serialisierung seine lieben Nöte.

REST Webservices fand und finde ich eigentlich ganz gut. Der nicht vorhandene Standard erlaubt interpretationsspielraum, man kann man schnell was zum Service dazu erfinden und die Infrastruktur bricht nicht (im Gegensatz zu WFC Contract First Design). Aus Performance Sicht ist dieser Ansatz allerdings großer Bullshit. Weder ist der dokumentorientierte Ansatz optimal, noch HTTP als Protokoll mit seinem Overhead und schon gar nicht JSON. Das kann mir alles egal sein, wenn man eine dieser tollen SPA Anwendungen betreibt und nur Browser zu Web Server Kommunikation betreibt.

Nun sind die Jungs am Keyboard aber auf Microservice Architektur scharf. Viele kleine Services sitzen in ihren Docker Käfigen und telefonieren miteinander. Genau da fällt der große Mist einer REST basierenden Services Layers plötzlich dramatisch ins Gewicht, Persönlich finde ich ja den guten alten File Zugriff in einer Server Architektur nach wie vor nicht blöd, aber nun gut es muss ja entkoppelt werden.

Die Stunde der Wiedergeburt des Remote Procedure Calls. Da es von Google kommt muss es toll sein. Das fand Fefe übrigens 2015 nicht unbedingt so.

Persönlich abartig finde ich das Protobuf Format. Damit wird sozusagen das Interface definiert. Das textuelle Format erinnert mich an VTT oder so. Das sieht Clemens Vasters (Lead Architekt Microsoft Messaging) in einer auf Twitter geführten Diskussion anders.

   1:  message Person {
   2:    required string name = 1;
   3:    required int32 id = 2;
   4:    optional string email = 3;
   5:  }

Also Microsoft scheint gRPC nun auch zu lieben und implementiert in .net core die entsprechende Proxy Api. Da gRPC relativ stringent HTTP2 vorraussetzt und es wohl Probleme mit Browser und JacvaScript gibt, haben die Redmonder, in Person James Newton (der Schöpfer von json.net) eine weitere Abstraktion einfallen lassen gRPC Web. An dieser Stelle nochmal: gRPC soll das Performance Problem von Microservices lösen!

Die folgende Aufgabenstellung ist somit eigentlich völlig bescheuert. Aber wie sagt man, man tut weil mans kann. Wir werden also nun prototypisch einen gRPC Service mit einer Blazor Server Side App verknüpfen und diese am Ende sogar in der gleiche .net core App mit Kestrel betreiben.

 

image

Zu Visual Studio Solution eine neues Projekt hinzufügen

image

 

Im Blazor Projekt Service Reference hinzufügen

image

Installiert Grpc.AspNetCore

Verzeichnisreferenz auf die Protobuf IDL Definition im GprService1 Projekt.

image

 

Damit der Compiler den Proxy korrekt erstellen kann, muss in der Blazor Projekt Datei die Referenz auf den Service angelegt sein. Beim erstellen der Referenz wird das Nuget Paket Grpc.AspNetCore hinzugefügt und die nötige Änderung in der csproj durchgeführt.

   1:  <ItemGroup>
   2:      <Protobuf Include="..\GrpcService1\Protos\greet.proto" 

GrpcServices="Client">
   3:        <Link>Protos\greet.proto</Link>
   4:      </Protobuf>
   5:  </ItemGroup>

Falls es beim folgenden Code Sample zu einem Compiler Fehler GreeterClient is undefined kommt, nochmals prüfen ob da =”Client” steht.

image

In der Datei Index.razor wird dann der gRPC Service aufgerufen. Dazu einfach folgendes C# Schnipsel in die index.razor Datei kopieren

   1:  @using Grpc.Net.Client
   2:  @using GrpcService1
   3:   
   4:  @Reply
   5:  <button @onclick="call"> call service</button>
   6:   
   7:  @code
   8:  {
   9:  public string Reply { get; set; }
  10:  async void call()
  11:  {
  12:          using var channel = 
GrpcChannel.ForAddress("https://localhost:5001");
  13:          var client = new Greeter.GreeterClient(channel);
  14:          var x = await client.SayHelloAsync(
  15:                            new HelloRequest { Name = "GreeterClient" });
  16:          Reply = x.Message;
  17:  } }
  18:   

 

Nun muss die Solution umgestellt werden, damit beide Projekte gestartet werden.

image

Im nächsten Schritt versuche ich den gRPC Service und die Blazor Pages im selben Webserver zu hosten. Die Ideen dazu hole ich mir aus dem mit Visual Studio angelegten gRPC Projekt.

In der Startup.cs wird Service angelegt und der Endpunkt konfiguriert

   1:  public void ConfigureServices(IServiceCollection services)
   2:    {
   3:      ..
   4:    services.AddGrpc();
   5:            
   6:  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
   7:    ..
   8:    app.UseEndpoints(endpoints =>
   9:              { 
  10:    endpoints.MapGrpcService<GreeterService>();
  11:    ...

 

Die Blazor Projektdatei habe ich geändert um als GrpcService Client und Server sein zu können

   1:  <ItemGroup>
   2:      <Protobuf Include="Protos\greet.proto" GrpcServices="Both" />
   3:  </ItemGroup>

Nun muss noch die echte Proto Definition aus dem Service Projekt in das Blazor Projekt kopiert werden. Dies ist aktuell nur als Referenz eingebunden per Verzeichnis Protos

Selbiges für den eigentlichen GreeterService aus dem gRPC Service Projekt. Kopieren nach Blazor Projekt.

image

Um nicht aus versehen mit dem externen Service zu arbeiten empfiehlt es sich diesen aus der Visual Studio Solution zu entladen

image

Am Schluss muss noch der Hosting Webserver von IISExpress auf Kestrel umgestellt werden

image

Kommentare sind geschlossen