{"id":1894,"date":"2021-02-10T15:08:42","date_gmt":"2021-02-10T15:08:42","guid":{"rendered":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?p=1894"},"modified":"2021-02-12T15:42:40","modified_gmt":"2021-02-12T15:42:40","slug":"wcf-alternativen-teil-3","status":"publish","type":"post","link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/","title":{"rendered":"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC"},"content":{"rendered":"\n<p>In diesem Blogpost der Artikelserie zu den <a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/topic\/wcf-alternativen\/\">Alternativen der Windows Communication Foundation (WCF)<\/a> werden die Besonderheiten und Herausforderungen einer WCF-Migration als Vorbereitung zu einer sp\u00e4teren Portierung der Anwendung auf .NET Core beschrieben.<\/p>\n\n\n\n<p>Nachdem im letzten Artikel ASP.NET Core Web API als Alternative vorgestellt wurde, wird in diesem Beitrag auf gRPC als eine weitere M\u00f6glichkeit eingegangen. Auch hier soll Schritt f\u00fcr Schritt ein m\u00f6gliches Vorgehen bei der Migration von WCF zu gRPC beschrieben werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Vorgehen bei der Migration<\/strong><\/h2>\n\n\n\n<p>In der Regel existiert ein separates WCF-Projekt in der Solution. Da eine direkte Umstellung nicht m\u00f6glich ist, kann dieses Projekt zun\u00e4chst unver\u00e4ndert in der Solution verbleiben.<\/p>\n\n\n\n<p>Zun\u00e4chst sollte ein neues Class-Library-Projekt f\u00fcr Shared-Objekte zwischen Server und Client angelegt werden. In dieses Projekt werden die ServiceContract Interfaces sowie die DataContract-Klassen aus dem WCF-Projekt kopiert und die WCF-spezifischen Attribute wie &#8222;ServiceContract&#8220;, &#8222;OperationContract&#8220;, &#8222;DataContract&#8220;, &#8222;DataMember&#8220; usw. entfernt.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Client-Projekt<\/strong><\/h3>\n\n\n\n<p>Im WCF Service konsumierenden Projekt wird als erstes die WCF-Service-Referenz entfernt. Auch k\u00f6nnen die WCF-spezifischen Attribute wie &#8222;CallbackBehavior&#8220; o. \u00c4. entfernt werden.<\/p>\n\n\n\n<p>Eine neue Referenz zum zuvor angelegten Class-Library-Projekt f\u00fcr die Shared-Objekte wird hinzugef\u00fcgt. Als n\u00e4chstes kann im Client-Projekt eine leere Implementierung des jetzt im Class-Library-Projekt abgelegten ServiceContract Interfaces erstellt werden. Die \u201ealte\u201c Initialisierung des WCF Service wird jetzt auf die noch leere Implementierung des ServiceContract ge\u00e4ndert.<\/p>\n\n\n\n<p>Abschlie\u00dfend m\u00fcssen noch die Usings f\u00fcr die zuvor verwendeten DataContract-Klassen aus dem WCF Service auf das neue Class-Library-Projekt ge\u00e4ndert werden. Damit sollte sich das Client-Projekt wieder kompilieren lassen. Um das Projekt auch wieder starten zu k\u00f6nnen, ist der Teil &lt;system.serviceModel&gt; aus der *.config zu entfernen.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Erstellung der Schnittstellenbeschreibung mit Protocol Buffers<\/strong><\/h3>\n\n\n\n<p>Bei gRPC wird die Schnittstelle mit der Protocol Buffer Language in *.proto-Dateien beschrieben. Am besten wird die *.proto-Datei im neu angelegten Class-Library-Projekt hinzugef\u00fcgt. Um sp\u00e4ter daraus Server- und Client-Klassen generieren zu k\u00f6nnen, m\u00fcssen zus\u00e4tzlich die NuGet-Pakete &#8222;Google.Protobuf&#8220;, &#8222;Grpc.Core&#8220; und &#8222;Grpc.Tools&#8220; hinzugef\u00fcgt werden.<\/p>\n\n\n\n<p>Nach Anlage der *.proto-Datei muss diese in der *.csproj-Datei im Knoten &#8222;ItemGroup&#8220; durch folgende Zeile bekannt gemacht werden.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;Project Sdk=\"Microsoft.NET.Sdk\">\n \n  &lt;ItemGroup>\n    &lt;Protobuf Include=\"ProtoZeitService.proto\" GrpcServices=\"Both\" \/>\n \n  &lt;\/ItemGroup>\n \n&lt;\/Project><\/pre>\n\n\n\n<p><em>Definition der *.proto in *.config Datei<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Aufbau der *.proto Datei<\/strong><\/h3>\n\n\n\n<p>Nachfolgend ist ein Beispiel zu sehen, wie eine WCF-Service-Beschreibung in eine *.proto-Datei \u00fcberf\u00fchrt werden kann.<\/p>\n\n\n\n<p>Die [ServiceContract]-Attribute werden zu &#8222;Service&#8220; und aus [OperationContract] werden &#8222;rpc&#8220;-Aufrufe. Die als [DataContract] gekennzeichneten Klassen werden zu &#8222;message&#8220;-Objekten.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[ServiceContract]\npublic interface IDataInputService\n{\n    [OperationContract]\n    int CreateUser(User user);\n \n    [OperationContract]\n    int Login(User user);\n \n    [OperationContract]\n    List&lt;Time> GetTimes(int userId);\n \n    [OperationContract]\n    void AddTime(Time time, int userId);\n \n    [OperationContract]\n    List&lt;string> Projects();\n}\n \n[DataContract]\npublic class User\n{\n    [DataMember]\n    public string Name { get; set; }\n \n    [DataMember]\n    public string Passwort { get; set; }\n}\n \n[DataContract]\npublic class Time\n{\n    [DataMember]\n    public DateTime Start { get; set; }\n \n    [DataMember]\n    public DateTime End { get; set; }\n \n    [DataMember]\n    public string Project { get; set; }\n \n    [DataMember]\n    public int uId { get; set; }\n \n    [DataMember]\n    public int Id { get; set; }\n}<\/pre>\n\n\n\n<p><em>Beispiel eines zu migrierenden WCF ServiceContract und DataContract<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">syntax = \"proto3\";\n \nimport \"google\/protobuf\/timestamp.proto\";\nimport \"google\/protobuf\/Empty.proto\";\n \noption csharp_namespace = \"DataInputt.ZeitService.Api\";\n \nservice DataInputService {\n    rpc CreateUser (UserDto) returns (UserResponse) {}\n    rpc Login (UserDto) returns (UserResponse) {}\n    rpc GetTimes (GetTimesRequest) returns (TimeCollection) {}\n    rpc AddTime (AddTimeRequest) returns (google.protobuf.Empty) {}\n    rpc Projects (google.protobuf.Empty) returns (ProjectCollection) {}\n}\n \n \nmessage UserDto {\n    string name = 1;\n    string passwort = 2;\n}\n \nmessage TimeDto {\n    google.protobuf.Timestamp start = 1;\n    google.protobuf.Timestamp end = 2;\n    string project = 3;\n    int32 uid = 4;\n    int32 id = 5;\n}\n \nmessage UserResponse {\n    int32 id = 1;\n}\n \nmessage GetTimesRequest {\n    int32 userId = 1;\n}\n \nmessage TimeCollection {\n    repeated TimeDto times = 1;\n}\n \nmessage AddTimeRequest {\n    TimeDto time = 1;\n    int32 userId = 2;\n}\n \nmessage ProjectCollection {\n    repeated string projects = 1;\n}<\/pre>\n\n\n\n<p><em>Beispiel der erstellten gRPC *.proto-Datei<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Bei der Erstellung der *.proto-Datei sollten folgende Punkte ber\u00fccksichtigt werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Angabe Namespace<\/strong><\/h3>\n\n\n\n<p>Damit die generierte Server- und Client-Implementierung den korrekten Namespace erh\u00e4lt, sollte dieser in der *.proto-Datei angegeben werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Definition \u00dcbergabe\/R\u00fcckgabe Parameter<\/strong><\/h3>\n\n\n\n<p>Bei gRPC-Schnittstellen sind nur Aufrufe mit einem einzigen Paramater zugelassen. Wird im WCF Service mit mehreren \u00dcbergabeparametern gearbeitet, m\u00fcssen diese in einem neuen Message-Objekt zusammengefasst werden.<\/p>\n\n\n\n<p>Jeder Aufruf einer gRPC-Schnittstelle muss auch einen R\u00fcckgabewert haben. Gab es im WCF Service void-Methoden, so m\u00fcssen diese bei gRPC jetzt den speziellen Typ &#8222;google.protobuf.Empty&#8220; zur\u00fcckgeben.<\/p>\n\n\n\n<p>Des Weiteren darf f\u00fcr die \u00dcbergabe und R\u00fcckgabe kein einzelner primitiver Datentyp (int, bool, string) verwendet werden. Soll f\u00fcr die R\u00fcckgabe nur ein<em> int<\/em> oder <em>string<\/em> verwendet werden, so muss auch daf\u00fcr ein extra Message-Objekt erstellt werden.<\/p>\n\n\n\n<p>Rufen sich im WCF Service Methoden gegenseitig auf, war das bei der Verwendung eines primitiven Datentyps sehr einfach. Soll das auch in der gRPC-Schnittstelle m\u00f6glich sein, ist darauf zu achten, dass die betreffenden Methoden dieselben Message-Objekte verwenden. So kann ein unn\u00f6tiges Mapping vermieden werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Bezeichnung der Message-Objekte<\/strong><\/h3>\n\n\n\n<p>Bei der Bezeichnung der Message-Objekte sollten diese besser nicht 1:1 von den DataContract-Klassen des WCF Service \u00fcbernommen werden. Der Grund daf\u00fcr ist, dass die sp\u00e4ter aus der Definition generierten C#-Klassen teilweise andere Datentypen verwenden und f\u00fcr die Verwendung erst gemappt werden m\u00fcssen. Um diese dann besser von den DataContract-Klassen zu trennen, empfiehlt sich hier eine differenzierte Bezeichnung.<\/p>\n\n\n\n<p>Au\u00dferdem m\u00fcssen die Properties innerhalb der Message-Objekte fortlaufend nummeriert werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Datentypen in Message-Objekten<\/strong><\/h3>\n\n\n\n<p>Aus den Message-Objekten der *.proto-Datei werden automatisch C#-Klassen generiert. Hier sollte man sich bewusst sein, dass nicht immer die Standard-C#-Datentypen f\u00fcr die Generierung verwendet werden.<\/p>\n\n\n\n<p>So wird aus dem in der *.proto-Datei angegebenen Typ google.protobuf.Timestamp in der C#-Klasse der Typ Google.Protobuf.WellKnownTypes.Timestamp, welcher bei Verwendung immer erst in ein DateTime umgewandelt werden muss.<\/p>\n\n\n\n<p>Wird in der *.proto-Datei &#8222;repeated&#8220; angegeben, wird daraus kein List&lt;T&gt; sondern ein Google.Protobuf.Collections.RepeatedField&lt;T&gt;, welches auch entsprechend gemappt werden muss.<\/p>\n\n\n\n<p>Auch andere Typen wie z. B. Dictionary&lt;K, V&gt; haben in der *.proto-Datei und der sp\u00e4ter generierten C#-Klasse jeweils andere Typen. Der C#-Typ &#8222;decimal&#8220; wird aktuell aufgrund fehlender Rundungsgenauigkeit von der *.proto-Datei noch gar nicht unterst\u00fctzt. Als Workaround wird empfohlen, sich ein eigenes Decimal-Message-Objekt zu erstellen, welches Vor- und Nachkommastellen als separate int-Werte abbildet.<\/p>\n\n\n\n<div style=\"height:29px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Anlage des gRPC-Server-Projekts<\/strong><\/h3>\n\n\n\n<p>Das gRPC-Server-Projekt kann als einfache Konsolenanwendung erstellt werden und sollte einen Verweis auf das zuvor neu angelegte Class-Library-Projekt mit der *.proto-Datei haben.<\/p>\n\n\n\n<p>Um den Server zu starten, sind nur wenige Zeilen Code n\u00f6tig:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">static void Main(string[] args)\n{\n    const int port = 9000;\n    const string host = \"0.0.0.0\";\n\n    Grpc.Core.Server server = new Grpc.Core.Server\n    {\n        Services = { DataInputt.ZeitService.Api.ZeitService.BindService(new ZeitService()) },\n        Ports = { new Grpc.Core.ServerPort(host, port, Grpc.Core.ServerCredentials.Insecure) }\n    };\n    server.Start();\n\n    Console.WriteLine($\"Starting server {host}:{port}\");\n    Console.WriteLine(\"Press any key to stop...\");\n    Console.ReadKey();\n}<\/pre>\n\n\n\n<p><em>Beispiel f\u00fcr den Start eines gRPC Server<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Es m\u00fcssen lediglich Host und Port definiert sowie dem im Class-Library-Projekt durch die *.proto-Datei generierten Service eine Implementierung zugewiesen werden. Dabei sollte die Implementierung im gRPC-Server-Projekt liegen.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Implementierung des gRPC Service<\/strong><\/h3>\n\n\n\n<p>Die Implementierung des gRPC Service erfolgt durch das Erben der im Class-Library-Projekt durch die *.proto-Datei generierten ServiceBase. Die einzelnen Serviceaufrufe k\u00f6nnen dann durch ein override implementiert werden.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class ZeitService : DataInputt.ZeitService.Api.ZeitService.ZeitServiceBase\n{\n    public override Task&lt;UserResponse> CreateUser(UserDto request, ServerCallContext context)\n    {\n         \n    }\n \n    public override Task&lt;UserResponse> Login(UserDto request, ServerCallContext context)\n    {\n         \n    }\n \n    public override Task&lt;TimeCollection> GetTimes(GetTimesRequest request, ServerCallContext context)\n    {\n         \n    }\n \n    public override Task&lt;Empty> AddTime(AddTimeRequest request, ServerCallContext context)\n    {\n         \n    }\n \n    public override Task&lt;ProjectCollection> Projects(Empty request, ServerCallContext context)\n    {\n         \n    }   \n}<\/pre>\n\n\n\n<p><em>Beispiel f\u00fcr die Server-Implementierung eines gRPC Service<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Wird f\u00fcr die Service-Implementierung der &#8222;alte&#8220; WCF Code verwendet, kann ein Mapping der Parameter n\u00f6tig sein, wenn die Datentypen nicht zu den &#8222;alten&#8220; DataContract-Klassen passen.<\/p>\n\n\n\n<p>Wichtig ist auch zu wissen, dass sich der Lifecycle der Service-Implementierung \u00fcber die gesamte Laufzeit des gRPC Service erstreckt (Singelton). Anders als bei einem Web API Controller wird nicht f\u00fcr jeden Request eine neue Instanz der Service-Implementierung erstellt. Somit bleibt der Zustand des gRPC Service zwischen den Aufrufen erhalten. Klassenvariablen und im Konstruktor erstellte oder injizierte Ressourcen sollten daher besser vermieden werden, da deren Zustand sonst zwischen den Aufrufen ggf. nicht sichergestellt werden kann.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Implementierung des gRPC Clients<\/strong><\/h3>\n\n\n\n<p>F\u00fcr die Implementierung des gRPC Clients kann die im konsumierenden Projekt angelegte leere Implementierung des ServiceContract Interfaces genutzt werden. Hier muss zun\u00e4chst eine Verbindung zum gRPC Server hergestellt werden.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const int port = 9000;\nstring host = Environment.MachineName;\n \nvar channel = new Channel(host, port, ChannelCredentials.Insecure);\nvar grpcClient = new ZeitService.Api.ZeitService.ZeitServiceClient(channel);<\/pre>\n\n\n\n<p><em>Beispiel eines Clients zum Herstellen der Verbindung zum gRPC Server<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Auch hier kommt eine aus der im Class-Library-Projekt durch die *.proto-Datei generierte Client-Klasse zum Einsatz. Durch diese werden die in der *.proto-Datei definierten Aufrufe bereitgestellt.<\/p>\n\n\n\n<p>Jetzt muss die leere Implementierung des ServiceContract Interfaces durch die entsprechenden Aufrufe der gRPC-Client-Klasse erg\u00e4nzt werden. Auch hier kann es n\u00f6tig sein, die vom gRPC Service verwendeten \u00dcber- und R\u00fcckgabeparameter auf die bisherigen DataContract-Klassen zu mappen.<\/p>\n\n\n\n<p>Durch die Verwendung und Implementierung des &#8222;alten&#8220; WCF Service Interface muss im konsumierenden Projekt nichts weiter angepasst und ge\u00e4ndert werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Bidirektionale Kommunikation<\/strong><\/h3>\n\n\n\n<p>Das Konzept der bidirektionalen Kommunikation in gRPC unterscheidet sich stark von WCF Duplex Services.<\/p>\n\n\n\n<p>Bei WCF kann der Server \u00fcber Callback Interfaces sehr einfach verschiedene Methoden auf Client-Seite aufrufen. Hingegen wird bei gRPC vom Client ausgehend eine Server-Methode angesprochen, welche als Stream Daten an den Client zur\u00fcckliefert.<\/p>\n\n\n\n<p>Dazu muss die gRPC-Server-Methode so implementiert werden, dass diese nicht beendet und somit die Verbindung aufrechterhalten wird. Anschlie\u00dfend kann zum Beispiel durch Events die \u00dcbertragung von Daten an den Client ausgel\u00f6st werden.<\/p>\n\n\n\n<p>Auch beim Client muss nach dem Aufruf der Server-Methode die Verbindung aufrechterhalten und auf den Empfang neuer Daten reagiert werden.<\/p>\n\n\n\n<p>Somit sind f\u00fcr eine Umstellung auf gRPC Streaming sehr rundlegende und konzeptionelle Anpassungen n\u00f6tig.<\/p>\n\n\n\n<p>Nicht betrachtet wurden <strong>Querschnittsfunktionen<\/strong> wie Authentifizierung, Autorisierung, Logging und Fehlerbehandlung der gRPC-Aufrufe \u2013 diese Punkte sollten im Einzelfall gepr\u00fcft und ggf. angepasst werden.<\/p>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Fazit<\/strong><\/h2>\n\n\n\n<p>Die Umstellung von WCF auf gRPC ist verglichen mit ASP.NET Core Web API deutlich aufwendiger und mit mehr Code-Anpassungen verbunden. Zun\u00e4chst muss eine *.proto-Datei erstellt werden. Durch die Vorgabe, dass jeder Serviceaufruf eine R\u00fcckgabe haben muss und max. ein \u00dcbergabeparamater zul\u00e4ssig ist, sind teilweise Anpassungen an den Methodensignaturen n\u00f6tig. Da in den generierten Klassen teilweise keine .NET-Standard-Typen verwendet werden, muss jede Server- und Client-Methode mit dem entsprechenden Mapping-Code erg\u00e4nzt werden.<\/p>\n\n\n\n<p>Bei der Verwendung von gRPC sollte auch unbedingt ber\u00fccksichtigt werden, dass sich der Lifecycle der Serviceinstanz \u00fcber die gesamte Ausf\u00fchrungszeit des gRPC Servers erstreckt (Singelton).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.<\/p>\n","protected":false},"author":104,"featured_media":1980,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"advgb_blocks_editor_width":"","advgb_blocks_columns_visual_guide":"","footnotes":""},"categories":[11,16],"tags":[240,521,522,557,558],"topics":[560],"class_list":["post-1894","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web","category-dot-net","tag-net-core","tag-wcf","tag-windows-communication-foundation","tag-asp-net-core","tag-grpc","topics-wcf-alternativen"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.0 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog<\/title>\n<meta name=\"description\" content=\"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog\" \/>\n<meta property=\"og:description\" content=\"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/\" \/>\n<meta property=\"og:site_name\" content=\"Digital Innovation Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-10T15:08:42+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-02-12T15:42:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1404\" \/>\n\t<meta property=\"og:image:height\" content=\"791\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"David Siebert\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:site\" content=\"@ZEISS_di\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"David Siebert\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/\",\"name\":\"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png\",\"datePublished\":\"2021-02-10T15:08:42+00:00\",\"dateModified\":\"2021-02-12T15:42:40+00:00\",\"author\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/25b5da9fd04d962532d448cb581c1912\"},\"description\":\"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.\",\"breadcrumb\":{\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png\",\"width\":1404,\"height\":791},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/\",\"name\":\"Digital Innovation Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/25b5da9fd04d962532d448cb581c1912\",\"name\":\"David Siebert\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/siebert_david-e1607418301577-150x150.jpg\",\"contentUrl\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/siebert_david-e1607418301577-150x150.jpg\",\"caption\":\"David Siebert\"},\"description\":\"David Siebert ist Senior Consultant Softwareentwicklung bei der ZEISS Digital Innovation. Sein Schwerpunkt liegt vor allem in der .NET-Entwicklung. Dar\u00fcber hinaus besch\u00e4ftigt er sich besonders mit Webtechnologien und Clean Code.\",\"url\":\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/davidsiebert\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog","description":"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/","og_locale":"de_DE","og_type":"article","og_title":"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog","og_description":"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.","og_url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/","og_site_name":"Digital Innovation Blog","article_publisher":"https:\/\/www.facebook.com\/ZEISSDigitalInnovation\/","article_published_time":"2021-02-10T15:08:42+00:00","article_modified_time":"2021-02-12T15:42:40+00:00","og_image":[{"width":1404,"height":791,"url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png","type":"image\/png"}],"author":"David Siebert","twitter_card":"summary_large_image","twitter_creator":"@ZEISS_di","twitter_site":"@ZEISS_di","twitter_misc":{"Verfasst von":"David Siebert","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/","name":"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC - ZEISS Digital Innovation Blog","isPartOf":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage"},"image":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png","datePublished":"2021-02-10T15:08:42+00:00","dateModified":"2021-02-12T15:42:40+00:00","author":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/25b5da9fd04d962532d448cb581c1912"},"description":"In diesem Beitrag wird auf gRPC als eine m\u00f6gliche Alternative zu WCF eingegangen und Schritt f\u00fcr Schritt beschrieben, wie eine Migration aussehen kann.","breadcrumb":{"@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#primaryimage","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies.png","width":1404,"height":791},{"@type":"BreadcrumbList","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wcf-alternativen-teil-3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/"},{"@type":"ListItem","position":2,"name":"WCF-Alternativen (Teil 3) \u2013 Eine Anleitung zur Migration von WCF zu gRPC"}]},{"@type":"WebSite","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#website","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/","name":"Digital Innovation Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Person","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/25b5da9fd04d962532d448cb581c1912","name":"David Siebert","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/#\/schema\/person\/image\/","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/siebert_david-e1607418301577-150x150.jpg","contentUrl":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2020\/12\/siebert_david-e1607418301577-150x150.jpg","caption":"David Siebert"},"description":"David Siebert ist Senior Consultant Softwareentwicklung bei der ZEISS Digital Innovation. Sein Schwerpunkt liegt vor allem in der .NET-Entwicklung. Dar\u00fcber hinaus besch\u00e4ftigt er sich besonders mit Webtechnologien und Clean Code.","url":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/davidsiebert\/"}]}},"author_meta":{"display_name":"David Siebert","author_link":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/author\/davidsiebert\/"},"featured_img":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-content\/uploads\/sites\/2\/2021\/01\/202101_WCF_communication_technologies-600x338.png","coauthors":[],"tax_additional":{"categories":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/web\/\" class=\"advgb-post-tax-term\">Web<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">.NET<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">Web<\/span>","<span class=\"advgb-post-tax-term\">.NET<\/span>"]},"tags":{"linked":["<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">.NET Core<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">WCF<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">Windows Communication Foundation<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">ASP.NET Core<\/a>","<a href=\"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/category\/dot-net\/\" class=\"advgb-post-tax-term\">gRPC<\/a>"],"unlinked":["<span class=\"advgb-post-tax-term\">.NET Core<\/span>","<span class=\"advgb-post-tax-term\">WCF<\/span>","<span class=\"advgb-post-tax-term\">Windows Communication Foundation<\/span>","<span class=\"advgb-post-tax-term\">ASP.NET Core<\/span>","<span class=\"advgb-post-tax-term\">gRPC<\/span>"]}},"comment_count":"0","relative_dates":{"created":"Posted 5\u00a0Jahren ago","modified":"Updated 5\u00a0Jahren ago"},"absolute_dates":{"created":"Posted on Februar 10, 2021","modified":"Updated on Februar 12, 2021"},"absolute_dates_time":{"created":"Posted on Februar 10, 2021 3:08 p.m.","modified":"Updated on Februar 12, 2021 3:42 p.m."},"featured_img_caption":"","series_order":"","_links":{"self":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/1894","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/users\/104"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/comments?post=1894"}],"version-history":[{"count":8,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/1894\/revisions"}],"predecessor-version":[{"id":2224,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/posts\/1894\/revisions\/2224"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media\/1980"}],"wp:attachment":[{"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/media?parent=1894"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/categories?post=1894"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/tags?post=1894"},{"taxonomy":"topics","embeddable":true,"href":"https:\/\/blogs.zeiss.com\/digital-innovation\/de\/wp-json\/wp\/v2\/topics?post=1894"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}