gRPC je fenomén dnešní doby. Moderní a výkonově efektivní protokol se rychle rozšiřuje a my si dnes ukážeme, jak ho použít pro komunikaci mez Blazor WebAssembly front-endem a ASP.NET Core backendem (hostem):
Efektivně využijeme možnosti sdílení kódu mezi serverovou a klientskou částí. Použijeme uspořádání code-first a „contract“ (interface pro volanou službu a definice datových objektů) dáme do assembly sdílené serverovou i klientskou částí solution.
Pro překonání omezení browserů použijeme gRPC-Web rozšíření.
Celou implementaci si ukážeme na jednoduché příkladu – použijeme výchozí šablonu Blazor WebAssembly App z Visual Studia (ASP.NET Core hosted, verze šablony .NET7) a připravenou ukázku Fetch data, která v této šabloně používá REST API, předěláme na gRPC-Web volání s použitím code-first.
Pojďme na to, bude to jen pár kroků:
1. MyBlazorSolution.Server – Příprava ASP.NET Core host
Nejprve si na straně serveru připravíme infrastrukturu pro gRPC. Půjdeme rovnou do varianty s rozšířením gRPC-Web s code-first podporou a nainstalujeme NuGet balíčky
2. MyBlazorSolution.Shared – Definice contractu služeb (code-first)
Nyní v podobě interface definujeme, jak bude naše služba vypadat. Interface následně využijeme jak na straně serveru (vytvoříme jeho implementaci), tak na straně klienta (necháme si vygenerovat gRPC-klienta, který bude interface implementovat a my ho v našem kódu budeme přímo využívat prostřednictvím dependency injection).
Přidejte do projektu NuGet balíček, který nám umožní interface dekorovat potřebnými atributy
Najděte si ukázkový soubor WeatherForecast.cs z šablony projekty. Obsahuje definici návratové datové zprávy, kterou nám nyní vrací ukázkové REST API. Tuto třídu předěláme do následující podoby:
[DataContract]
public class WeatherForecast
{
[DataMember(Order = 1)]
public DateTime Date { get; set; }
[DataMember(Order = 2)]
public int TemperatureC { get; set; }
[DataMember(Order = 3)]
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Přidali jsme atribut DataContract pro označení třídy, kterou budeme používat jako datovou zprávu gRPC.
Přidali jsme atributy DataMember, kterými jsme označili prvky, které se mají přes gRPC přenášet (ostatní se ignorují, zde TemperatureF je počítané a dopočítá se nám z ostatních údajů na klientovi kdykoliv znovu). Každému prvku je potřeba nastavit Order, kterým se definuje pevný layout pro používanou protobuf serializaci.
Původní typ DateOnly jsme vyměnili za DateTime. Musíme se držet typů podporovaných použitou protobuf serializací.
Dále potřebujeme vytvořit interface, který bude celou službu popisovat:
Atribut [ServiceContract] nám označuje použitelnost pro gRPC (lze později využít i pro automatické registrace).
Z podstaty síťové komunikace by měl být celý interface asynchronní.
Můžeme použít volitelný CancellationToken, který nám může zprostředkovat signál o předčasném ukončení komunikace klientem (nebo přerušení spojení).
3. MyBlazorSolution.Server – Implementace a publikování služby
Nyní zbývá připravený interface implementovat na straně serveru (použijeme lehce modifikovaný kód z ukázkového WeatherForecastController, který můžete nyní smazat):
Připravenou službu vypublikujeme skrze Startup.cs:
app.MapGrpcService<WeatherForecastFacade>();
MyBlazorSolution.Client – konzumace gRPC služby
Nyní už zbývá jen službu použít v Blazor WebAssembly front-endu. Celou definici máme k dispozici v podobě IWeatherForecastFacade interface s jeho WeatherForecast datovou třídou.
V Program.cs zaregistrujeme gRPC-Web infrastrukturu a klienta (ve factory podobě):
builder.Services.AddTransient<GrpcWebHandler>(provider => new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
builder.Services.AddCodeFirstGrpcClient<IWeatherForecastFacade>((provider, options) =>
{
var navigationManager = provider.GetRequiredService<NavigationManager>();
var backendUrl = navigationManager.BaseUri;
options.Address = new Uri(backendUrl);
})
.ConfigurePrimaryHttpMessageHandler<GrpcWebHandler>();
No a nyní již můžeme IWeatherForecastFacade ve front-endovém projektu kdekoliv použít tak, že si necháme službu nainjectovat pomocí dependency injection. Například tedy upravíme FetchData.razor, aby používalo naší novou gRPC službu namísto původního REST API:
gRPC služba může samozřejmě přijímat i vstup. V takovém případě použijte jeden vstupní parametr pro příchozí zprávu – datovou třídu vytvořenou stejně jako jsme připravili výstupní WeatherForecast. Obvykle se tyto třídy označují jako Data Transfer Object a dostávají tak suffix Dto. Implementace je obvykle jako C# record.
Pokud máme v našem projektu authentizaci a authorizaci, pak můžeme na implementující třídě/metodě použít atribut [Authorize], stejně jako bychom ho použili na controlleru/action.
Na publikovaný gRPC endpoint můžeme aplikovat libovolné techniky jako na jakýkoliv jiný namapovaný serverový endpoint (rate limiting, caching, …).
gRPC má v sobě podporu interceptorů jejichž prostřednictvím můžeme gRPC komunikaci dále vylepšovat
předávat si ze serveru na klienta výjimky (základní podpora je vestavěna, ale může se vám hodit ji obohatit o specifický handling vlastních scénářů),
předávat si z klienta na server požadovanou culture (do jakého jazyka je front-end přepnut),
V pokročilejší variantě uspořádání můžete zajistit i automatickou registraci interface a datových contractů, aniž byste je museli dekorovat atributy [ServiceContract], [DataContract] a [DataMember(Order = ...)]. Vše toto a mnohé další najdete připravené v:
V pátek 12. května jsme společně s Davidem Gešvindrem (WUG) a Tomášem Hercegem (Update Conference) pořádali v pražském Microsoftu lokální běh celosvětové konference Global Azure.
Záznam z keynote, kde jsem v podstatě celou dobu mluvil o Azure OpenAI a vytváření chatbota v ChatGPT.
Pokud jste si (podobně jako já) slibovali, že „snadno“ vytvoříte Blazor aplikaci, která bude napojitelná na obecného OIDC identity-providera pomocí knihovny Microsoft.AspNetCore.Components.WebAssembly.Authentication, přičemž budete zároveň touto cestou podporovat i napojení na Azure Active Directory (AAD), zklamu vás.
Myšlenka je jednoduchá, AAD přeci podporuje OIDC a tedy nyní důvod, proč by obecný OIDC klient neměl jít připojit i na AAD. Bohužel překážek je více, než byste chtěli překonávat.
Knihovna Microsoft.Authentication.WebAssembly.Msal, která je pro AAD určená, je sice nadstavbou základní Microsoft.AspNetCore.Components.WebAssembly.Authentication knihovny, dělá toho však o dost více, než jenom boilerplate konfiguraci podkladového obecného OIDC.
Základní rozdíl můžete najít například v „interop“ části s podkladovým JavaScriptovým modulem oidc-client.
AuthenticationService.ts v Microsoft.AspNetCore.Components.WebAssembly.Authentication,
AuthenticationService.ts v Microsoft.Authentication.WebAssembly.Msal.
Projevuje se to například při vyzvedávání access-tokenů. MSAL verze „fixuje“ specifikum AAD, které při dotazech na token endpoint ne vždy vrátí access-token se všemi požadovanými scopes (detaily jsou na širší diskuzi, ale např. nedostanete token, který by v sobě měl User.Read scope společně s custom-scope vašeho API, atp.).
Základní knihovna využívá „cachování“ tokenů v UserManageru oidc-client a spoléhá se na předpoklad: „Pokud token-endpoint vrátil access-token, pak tento token v sobě má všechny požadované scopes.“ (tedy si k získanému tokenu požadované scopes uloží a pak při dalším požadavku na stejné scopes vrací již získaný token).
„Fixovaná“ knihovna MSAL tento nedostatek podkladového oidc-client zná a ví, že tento sice tvrdí, že má token pro nějakou sadu scopes, ale access-token ve skutečnosti tyto scopes mít nemusí. Proto „vypíná“ na této úrovni cachování a získává token vždy znovu.
Záznam z přednášky pro komunitní setkání WUG Zlín z 28. února 2023. Povídal jsem o uspořádání Havit.Blazor stacku (šablona https://github.com/havit/NewProjectTemplate-Blazor) a proč je uspořádaný, tak jak je.
Záznam z přednášky pro konferenci WUG Days 2023.1 v Brně z 30. ledna 2023. Povídal jsem o uspořádání Havit.Blazor stacku (šablona https://github.com/havit/NewProjectTemplate-Blazor) a proč je uspořádaný, tak jak je.
Po dvou týdnech z ThinkPad P16s a týdnu s ThinkPad P1 Gen5 jsem ke své velké radosti dostal možnost vyzkoušet i ThinkPad Z16. Modelová řada Z je úplně nová a charakterem (minimalistické hliníkové šasi, jen USB-C porty, high-end komponenty) nápadně připomíná notebooky Apple nebo Dell XPS.
Přiznám se, že i přes vynikající papírové parametry jsem byl k této novince nedůvěřivý a říkal jsem si, že úplně čerstvá modelová řada bude potřebovat jednu nebo dvě generace, než se vyladí všechny novorozenecké problémy. K mému velkému překvapení však musím uznat, že se jedná o kousek velmi povedený a velmi vážně uvažuji o jeho pořízení, byť jsem byl již rozhodnutý pro dříve testované P16s.
K vyzkoušení jsem dostal preprodukční model 21D5Z9ZVUS:
procesor AMD Ryzen 7 PRO 6850H (45W TDP)
16GB RAM
500GB SSD
bez dedikované grafické karty, pouze integrovaná AMD Radeon 680M
16″ WUXGA (1920×1200) touch LCD (IPS), 16:10
(135W USB-C nabíjení, bez LTE)
První dojmy
Na první pohled se jedná o jiný druh ThinkPadu, který zarytého konzervativce může až vyděsit. Na druhou stranu musím na svém vlastním příkladu připustit, že nemít ten stroj označení ThinkPad, tak bych jej neměl nutkání ani zkoušet a řadil bych ho (neprávem) někam do kategorie IdeaPad (nebo tam někam, moc se v tom nevyznám, prostě B-tým Lenovo). Branding zde nepochybně sehrál svoji roli a přitáhl i moji pozornost.
Každopádně zapomeňte na klasické černé šasi ThinkPad s pogumovaným či jinak nekovovým povrchem. Zde se jedná o čistokrevný celokovový hliník (nikoliv však lesklý) v jeho klasické světle šedé barvě. Naopak po otevření je povrch černý a hladký (docela klouže, budete se zadrhávat jen o černé logo Lenovo pod pravým zápěstím), hrany až ostré.
První, čeho si u tohoto notebooku všimnete, je jeho velikost. První zkoušené P16s mi přišlo větší, než bych čekal, následné P1 Gen5 mi přišlo „asi tak, jak bych čekal“ a Z16 je prostě ještě o další kus subtilnější než P1 a v tomto ohledu „lepší, než bych čekal“. Rámeček okolo 16″ displeje (16:10) je minimální (za cenu hrbu pro kamery a mikrofony), tloušťka je ještě o trochu menší a celé je to najednou takové „tak akorát – super velikost“.
Volba materiálu šasi, kapacity baterie 72 Wh (oproti 52.5 Wh v P16s a 90 Wh v P1) a touch displeje bohužel předurčuje hmotnost 1.9kg. Stroji by samozřejmě mnohem více slušelo číslo někde kolem 1.5kg, ale ve srovnání s 1.8kg u P16s i P1 to není zase takový rozdíl.
Druhá věc, které si ihned po zapnutí všimnete, je zřetelně horší display. Po letech se špičkovými high-res displeji v X1 Carbon a T14 mně najednou „obyčejné“ 1920×1200 „zaslepené“ dotykovou vrstvou praštilo do očí. Naštěstí se však Z16 dodává (kromě další non-touch varianty 1920×1200) i s ultimátním OLED 3840×2400 displejem (s OGS touch), což ani jeden z „konkurentů“ P16s/P1 nenabízí, resp. P1 se s 4K rozlišením dělá v IPS provedení. (Rozhodně nelze předpokládat, že by high-res displeje P16s/P1byly horší, ostatně P-řada se pyšní tovární kalibrací barev a jde o špičkové zobrazovací jednotky pro kreativní práci – OLED má však svůj „zvuk“ a předpokládám, že nikoho nezklame.)
Třetí věc, která mě překvapila (tentokrát velmi příjemně), je thermal management. Velmi mi záleží na tichém provozu a po týdnu s P1 Gen5 a „ohořelými chodníky + ohluchlými chodci“, jsem čekal kvůli TDP 45W i zde podobný zážitek. Ano, AMD Ryzen 6850H má papírové TDP 45W stejné jako Intel i9-12900H v P1 Gen5 a ani náhodou jsem nedoufal, že by relativně málo perforované hliníkové šasi (ve srovnání s P-modely) dávalo prostor pro nějaký kultivovaný zvukový projev chlazení (obzvláště, pokud jsme teprve u první generace této řady), leda by to bylo vykoupeno vysokými teplotami a throttlingem výkonu. Opak je pravdou (!) – chlazení za běžného provozu téměř neslyšíte – přestože na AC napájení ventilátory nikdy nevypínají, notebook si jen lehounce šustí a do žádných vyšších teplot se nevydává. Při provozu na baterii se ventilátory i vypnou, pod zátěží naopak otáček přidává (stále však spíše výjimečně a velmi kultivovaně).
Samozřejmě mě hned napadlo, že to bude draze vykoupeno redukovaným výkonem a tak jsem sáhl po Passmark benchmarku, abych si udělal nějakou základní představu:
Procesorový výkon sice ani zdaleka nedosahuje hodnot P1 Gen5 s Intel i9-12000H (tam bylo CPU score ~31500), ale i tak se jedná o velmi příjemný výsledek a celkové naladění stroje je posazeno o trochu výše než P16s (ten byl osazen AMD Ryzen 6850U s 28W TDP).
Celkově mě překvapilo chování procesoru 6850H s papírovými 45W TDP ve srovnání s 6850U a jeho 28W TDP. Kromě TDP a frekvencí se mi nepodařilo najít parametry, v kterých by se tyto dva procesory lišily, přičemž H-verze zdaleka nevypadá, že by se snažila notebook „uvařit“ nějak zřetelně více než U-verze, kterou jsem měl v testovaném P16s. Rozdíl v naměřeném výkonu je téměř zanedbatelný (CPU score 25111 vs 23603) a spíše bude rozdíl v celkovém naladění modelových řad notebooků (firmware), kdy ThinkPad P16s jako workstation se snaží z procesoru vymáčknout maximum (o P1 Gen5 raději ani nemluvím, to je úplně jiná formule). ThinkPad Z16 naopak vypadá, že ochotně „boostuje“ (nárazové výkonové požadavky), ale jinak jde víceméně o stejnou výkonovou hladinu jako 6850U. Za bezmála dvojnásobnou cenu tak zde hledejte jiné výhody než výrazně vyšší výpočetní výkon (např. tišší provoz, subtilnější šasi).
Celkové dojmy po týdnu produkčního používání
Přeháněl bych, kdybych řekl, že jsem si Z16 po týdnu zamiloval, přesto se mi velmi líbí a kdyby Lenovo doladilo těchto pár parametrů, asi bych jim (nejenom já) za takový stroj „ruce utrhal“:
černý carbon místo hliníku + „měkčí“ provedení,
alespoň HDMI a 1x USB-A porty,
o půl kila méně (klidně s trochu menší baterií),
ideálně vrátit zpět klasickou ThinkPad chicklet klávesnici s vyšším zdvihem, PgUp/PgDown klávesami a původním rozložením Ctrl/Fn kláves i šipek, ale čekal jsem větší obtíže s adaptací,
(bez touch nebo když už, tak s Yoga překlopitelností pro využitelnost pera)
Vlastně to nejsou žádné zásadní nevýhody, ve skutečnosti má totiž Z16 spoustu kladů, pro mě pak zejména:
výborný thermal management s tichým chlazením a velmi mírnými teplotními projevy,
velmi slušný výkon pro vývoj (pokud nepotřebujete grafiku, je to ideální naladění),
subtilní šasi (menší než P16s i P1 Gen5),
velký a kvalitní 16″ display (OLED 3840×2400) – touch s možností využití Lenovo Pen,
USB-C docking i napájení (na 65W adaptér si to stěžuje, 90W tomu stačí, i když pro rychlé nabíjení se stroj dodává se 135W adaptérem),
solidní výdrž baterie (odhadem kolem 10-12 hodin pro cokoliv kromě Teams-meetingů),
klasická vycentrovaná klávesnice bez numerické části,
kvalitní high-end zpracování (+servis+záruka),
volitelný LTE modul (SIM),
slušné vybavení: fingerprint reader, IR camera for Windows Hello, SD reader.
Samozřejmě podstatnou podmínkou je i nabídka kombinace komponent, která naplňuje moje potřeby. Konkrétně v mém případě by to mohla být třeba varianta 21D4001LCK:
Pohybujeme se zde v kategorii 16″ notebooků ThinkPad s displejem o poměru stran 16:10…
Pokud hledáte ultimátní ultra-mobilní stroj pro grafickou práci, jste ochotni výkonu obětovat vše (zejména pak zvukový/tepelný komfort a výdrž baterie) a máte k dispozici neomezený rozpočet, pak zvolte Lenovo ThinkPad P1 Gen5. Jděte do varianty s nějakou dedikovanou grafickou kartou odpovídající vašim potřebám a užívejte si formule, kterou jen tak někdo další nemá.
Pokud hledáte výkonný stroj, který nějakou tu grafickou úlohu také zvládne, ale rozpočtově se potřebujete pohybovat někde kolem 40 000 Kč + DPH, pak zvolte Lenovo ThinkPad P16s. Pokud preferujete výdrž baterie a tišší provoz, pak rozhodně variantu AMD, pro vývojáře úplně ideální. Pokud naopak potřebujete přitopit více grafického výkonu, pak zřejmě poslouží varianta Intel s dedikovanou grafickou kartou (AMD verze se dělají jen s integrovanou grafikou).
Pokud jste ochotni dát dvojnásobek, někde kolem 80 000 Kč + DPH, nejde vám o workstation parametry (kalibraci barev, ISV certifikace atp.), netrváte na výbavě portů, ale chcete si naopak dopřát kompaktnější provedení, tišší provoz a možná i trochu více subjektivního výkonu pro vývoj, pak doporučuji Lenovo ThinkPad Z16 s OLED displejem (nebo IPS bez touch, pokud chcete ušetřit).
…já se v tuto chvíli nejspíš vydám cestou Z16. Nechte se překvapit a těšte se na pokračování příběhu.
PS: Nakonec jsem měl Z16 půjčené dva týdny a objednávám si ho v konfiguraci 21D4001LCK. P16s si nechávám v hledáčku pro další možnosti.