Pro efektivní integraci .NET MAUI aplikací s Blazor a nativními platformami je nutné pochopit, jak správně nastavit a konfigurovat různé části architektury aplikace. V tomto případě budeme pracovat s projektem Northwind.Maui.Blazor.Client a ukážeme si, jak implementovat různé API endpointy, jak povolit nešifrované připojení a jak správně použít vzor Model-View-ViewModel (MVVM) pro usnadnění vývoje a údržby aplikace.
Začneme konfigurací webového serveru a integrací s Swaggerem pro zjednodušení dokumentace a testování našich API endpointů. V rámci projektu .NET je možné vytvořit REST API, které umožňuje manipulaci s daty, jako jsou kategorie v databázi Northwind. K tomu používáme služby jako builder.Services.AddEndpointsApiExplorer() a builder.Services.AddSwaggerGen(). Swagger generuje dokumentaci, která usnadňuje testování našich API přímo z prohlížeče.
Pro testování API je implementováno několik metod HTTP požadavků, jako jsou GET, POST, PUT a DELETE. Každý endpoint vrací odpovědi podle HTTP status kódů, přičemž zajišťuje správu dat kategorie v aplikaci. Například metoda GET pro zobrazení všech kategorií nebo jedné konkrétní kategorie podle ID, metoda POST pro přidání nové kategorie, PUT pro aktualizaci existující kategorie a DELETE pro odstranění kategorie. Každý z těchto endpointů je podrobně definován v aplikaci pomocí atributů jako .Produces() a .WithOpenApi(), což zajišťuje správnou integraci s Swagger UI pro vizualizaci a testování.
Další krok, který musíme provést, je povolení nešifrovaných HTTP připojení pro platformy iOS a Android v rámci aplikace .NET MAUI. Tato konfigurace je nezbytná pro umožnění komunikace mezi mobilní aplikací a naším webovým API během vývoje, kdy může být šifrování HTTPS dočasně neaktivní.
Pro iOS otevřeme soubor Info.plist a přidáme nový klíč NSAppTransportSecurity s hodnotou NSAllowsArbitraryLoads, čímž umožníme nešifrované připojení. Na Androidu je potřeba vytvořit soubor network_security_config.xml, ve kterém povolíme připojení přes specifickou IP adresu, která bude mapovat na localhost, a následně tuto konfiguraci zaregistrujeme v AndroidManifest.xml.
V neposlední řadě je důležité se zaměřit na implementaci vzoru MVVM (Model-View-ViewModel). Tento vzor je klíčovým prvkem pro rozdělení logiky aplikace na tři části: Model, View a ViewModel. Model reprezentuje data aplikace, například objekty typu Category nebo Product. ViewModel obsahuje logiku pro manipulaci s daty a také definuje vlastnosti, které budou svázány s uživatelským rozhraním. View představuje samotnou vizualizaci aplikace, která se mění v závislosti na změnách ve ViewModelu. Tento přístup umožňuje snadnější testování, rozšiřování a údržbu aplikace.
Jedním z problémů při implementaci MVVM v .NET MAUI je nutnost použít boilerplate kód, například implementaci rozhraní INotifyPropertyChanged, které zajišťuje, že se při změně dat v modelu automaticky aktualizuje i uživatelské rozhraní. Abychom si usnadnili práci, můžeme použít nástroje, jako je CommunityToolkit.Mvvm.ComponentModel, které automatizují tento proces. Důležité je vědoma si toho, že pokud náš model už dědí z jiné třídy, budeme muset použít speciální atributy, které zajistí, že všechny změny vlastností budou správně reflektovány ve View.
Kromě technických aspektů implementace je nezbytné mít na paměti, že správná správa dat a jejich integrita je základním předpokladem pro úspěšnou aplikaci. Měli bychom se soustředit na to, jak správně navrhnout naše API a jak efektivně pracovat s datovými modely, aby byly snadno rozšiřitelné a udržovatelné.
Jak implementovat a spravovat limitování rychlosti API pomocí ASP.NET Core
V moderních webových aplikacích, kde je interakce s externími službami a API stále častější, je kladeno velké důraz na správu zátěže a ochranu před přetížením serverů. Jedním z účinných způsobů, jak tomu zabránit, je použití techniky limitování rychlosti (rate limiting). Tento přístup nejen že chrání API před zbytečným zatížením, ale také umožňuje rovnoměrné a spravedlivé využívání zdrojů všemi uživateli. V této kapitole se podíváme na to, jak implementovat limitování rychlosti API pomocí middleware v ASP.NET Core a jak správně reagovat na chyby, které vzniknou, když uživatelé překročí stanovený limit.
Limitování rychlosti v API může být implementováno různými způsoby, včetně používání klientských ID, která slouží k rozlišení jednotlivých požadavků. V příkladu, který je součástí této kapitoly, se podíváme na způsob, jakým klientská aplikace využívá své unikátní identifikátory pro odesílání požadavků na server, který tyto požadavky následně kontroluje a omezuje podle stanovených pravidel.
Proces odesílání požadavků
V aplikaci klienta je inicializován HTTP klient s přidáním hlavičky „X-Client-Id“, která se používá pro identifikaci každého klienta. Tento identifikátor je generován při spuštění aplikace a každý klient má své jedinečné ID, což umožňuje sledovat počet požadavků, které tento klient odeslal. Kód, který zajišťuje tento proces, vypadá takto:
Tato hlavička je důležitá pro sledování chování jednotlivých klientů, jelikož server na základě těchto ID kontroluje, zda klient nepřekročil limit počtu požadavků během určitého časového intervalu. Pokud klient překročí stanovený limit, server vrátí odpověď s chybovým kódem 429, což znamená, že počet požadavků byl překročen a je nutné počkat, než bude možné odeslat další požadavek.
Chyby limitování rychlosti
Při překročení limitu požadavků server vrací odpověď 429 spolu s hlavičkou „Retry-After“, která udává, kolik sekund musí klient čekat před tím, než bude moci znovu poslat požadavek. Tento proces je důležitý pro správné řízení zátěže a umožňuje aplikaci reagovat na přetížení serveru tím, že zajistí, aby každý klient měl rovnoměrný přístup k serverovým zdrojům. Příklad chybové zprávy z API vypadá následovně:
Pokud aplikace klienta správně zpracuje tuto chybu, měla by automaticky počkat uvedený čas a znovu zkusit požadavek. To může být dosaženo pomocí následujícího kódu:
Logování a sledování chyb
Je také nezbytné správně logovat všechny požadavky a chyby spojené s limitováním rychlosti. Pro sledování, jak server reaguje na jednotlivé požadavky, můžeme použít HTTP logování, které ukáže všechny podrobnosti o požadavcích, včetně hlaviček, odpovědí a specifických chybových kódů, jako je 429. Příklad logu může vypadat takto:
Tato informace může být velmi užitečná při diagnostice problémů s přetížením nebo při ladění aplikace, kde se požadavky neustále opakují i přes to, že klient již překročil svůj limit.
Upravitelné limity pro různé klienty
Jedním z důležitých aspektů při implementaci limitování rychlosti je schopnost nastavit různé limity pro různé klienty. Například, jak ukazuje příklad v textu, aplikace může mít různé limity pro různé klientské identifikátory. Když zadáme jiný klientský identifikátor, server může reagovat s odlišnými limity:
Tato flexibilita umožňuje, že různí klienti mohou mít různou prioritu nebo různý přístup k API, což může být užitečné pro aplikace s více úrovněmi přístupu, například pro vývojáře, kteří mají zvýšený limit oproti běžným uživatelům.
Závěrečná poznámka
V implementaci limitování rychlosti se velmi často používá middleware ASP.NET Core, konkrétně balíček Microsoft.AspNetCore.RateLimiting, který umožňuje implementovat nastavení limitů pro různé klienty nebo pro celé API. Tento balíček poskytuje flexibilní způsob, jak nastavit různé limity pro různé klienty, což může být užitečné pro aplikace s více uživatelskými rolemi.
Kromě samotného limitování je nezbytné, aby aplikace dokázala efektivně reagovat na překročení limitu, zpracovávala chybové kódy správně a poskytovala uživateli dostatečné informace, jako je doba čekání, než bude možné provést další požadavek. Správně implementované limitování rychlosti chrání API před zbytečným přetížením a zajišťuje plynulý a efektivní přístup k serverovým prostředkům.
Jak efektivně používat OData pro získávání dat přes web?
OData je otevřený protokol, který umožňuje snadný přístup k datům prostřednictvím webových služeb. Tento protokol umožňuje interaktivní práci s daty ve formě REST API a je silně využíván pro zajištění přístupu k datovým zdrojům na webu, což je zvláště užitečné při práci s databázemi a systémy pro správu produktů. OData umožňuje snadné a efektivní dotazování, filtrování, řazení a procházení vztahů mezi entitami, což se ukáže jako nezbytné při práci s velkými množstvími dat.
Jedním z hlavních výhod OData je schopnost flexibilně vyhledávat specifické záznamy nebo skupiny záznamů podle předem definovaných parametrů. Tento protokol umožňuje definovat různé dotazovací možnosti pomocí URL parametrů. Mezi nejdůležitější možnosti patří $select, $expand, $filter, $orderby, $skip a $top. Každý z těchto parametrů slouží k dosažení specifických cílů při dotazování na data.
Například parametr $select umožňuje omezit výběr pouze na určité vlastnosti entity. Pokud se tedy zajímáte pouze o název produktu a jeho cenu, můžete dotaz omezit na vlastnosti ProductName a UnitPrice. Tento způsob optimalizuje přenos dat a zrychluje dotazy, protože server vrací pouze požadované údaje.
Pokud se rozhodnete pro použití $expand, umožňuje vám tento parametr načíst související entity v jednom požadavku. To znamená, že místo provádění několika dotazů na jednotlivé kategorie a produkty, můžete je získat v jednom komplexním dotazu. Takový přístup šetří čas a zjednodušuje práci s daty.
Další užitečnou možností je $filter, který vám umožňuje filtrovat výsledky na základě podmínek, například pouze produkty, jejichž cena je vyšší než 50, nebo produkty, jejichž název začíná písmenem "C". Filtrace je velmi silným nástrojem, který umožňuje pracovat s daty dynamicky a pouze s těmi, které splňují určité kritéria.
Parametr $orderby slouží k seřazení výsledků podle specifikovaných vlastností. Tento parametr může být užitečný, když chcete získat produkty seřazené podle ceny, nebo chcete-li řadit položky podle názvu. Tímto způsobem lze snadno optimalizovat způsob prezentace dat uživateli, ať už ve formě seznamu produktů nebo tabulky.
Další praktickou funkcí je $skip a $top, které vám umožňují ovládat stránkování výsledků. Pokud máte na serveru tisíce produktů, je efektivní rozdělit výsledky na menší dávky a načítat je po částech, což pomáhá zlepšit výkon a uživatelskou zkušenost. Parametry $skip a $top lze kombinovat pro přizpůsobení počtu zobrazených položek, což je ideální pro implementaci stránkování na webových stránkách nebo v aplikacích.
OData rovněž podporuje řadu operátorů pro použití s $filter, které jsou specifické pro textové a numerické hodnoty. Operátory jako eq (rovná se), ne (nerovná se), lt (menší než), gt (větší než) nebo and a or pro složitější logické výrazy umožňují komplexní filtrování dat.
Kromě operátorů má OData také funkce, které mohou být užitečné při práci s textovými a datovými hodnotami. Funkce jako startswith, endswith, contains, nebo concat umožňují provádět pokročilé operace nad textovými řetězci, jako je hledání řetězců začínajících nebo končících na určitý text, nebo sloučení dvou textových hodnot do jedné. Tyto funkce poskytují flexibilitu při práci s daty, která mají složitější strukturu.
Další důležitou funkcí je now, která vrací aktuální datum a čas. Tato funkce může být užitečná při filtrování dat podle data, například při vyhledávání produktů, které byly přidány do katalogu v posledních 30 dnech.
V praxi je práce s OData zjednodušena díky standardizovaným URL konvencím a dokumentaci, která vysvětluje, jak tyto dotazy správně formulovat. Příklady dotazů, jako je požadavek na produkty s určitou cenou nebo filtrování produktů podle počátečního písmena názvu, ukazují, jak tento přístup efektivně využít při hledání konkrétních dat.
Pokud se rozhodnete pro konkrétní dotazování na data přes OData, je důležité pochopit, jak fungují základy HTTP protokolu. V podstatě odesíláte HTTP požadavky na server, který na základě parametrů ve URL vrátí požadované údaje ve formátu JSON. Využití nástrojů jako RestClient nebo Postman pro testování a ladění OData dotazů může výrazně zjednodušit práci.
Závěrem je důležité si uvědomit, že efektivní využití OData vyžaduje správné pochopení struktury dat, které se používají v dotazech, a schopnost optimalizovat dotazy pro lepší výkon. Správné používání parametrů pro filtrování, řazení a stránkování může výrazně zlepšit výkon aplikace a zpřehlednit uživatelský zážitek. Naopak, nepřiměřené nebo složité dotazy mohou vést k pomalejšímu načítání dat a nižší efektivitě aplikace.
Jak získat metadata z gRPC volání a proč je důležité nastavit deadline
Při práci s gRPC službami nejsou jediným způsobem přenosu dat mezi klientem a serverem formálně definované request a response objekty. Vedle těchto standardních zpráv lze využít i metadata ve formě hlaviček (headers) a ukončovacích metadat (trailers), které představují jednoduché slovníky předávané spolu s hlavním obsahem komunikace. Tato metadata lze snadno číst na klientské straně, například v ASP.NET Core MVC aplikaci, a poskytují dodatečné informace o probíhajícím volání – například datum volání, server, stavové kódy a další relevantní informace.
Chceme-li tato metadata zachytit, potřebujeme použít objekt typu AsyncUnaryCall, který umožňuje získání hlaviček volání přes metodu ResponseHeadersAsync. Po zavolání služby bez awaitu je možné metadata extrahovat a zapsat do logu. Výstup v logu, pokud je správně nakonfigurován, pak zobrazí klíčové hodnoty jako date a server, které server připojuje k odpovědi. Stejně tak můžeme po ukončení volání získat tzv. trailers – metadata přenášená na konci komunikace – pomocí metody GetTrailers.
Tato technika je zvláště užitečná při ladění služeb, sledování výkonu nebo zaznamenávání bezpečnostně relevantních informací. Pokud chceme tyto záznamy sledovat důsledně, je nezbytné upravit konfiguraci úrovně logování v souborech appsettings.Development.json, aby bylo možné zaznamenat i informace a varování namísto výchozích výstrah.
Dalším zásadním prvkem při navrhování robustních gRPC služeb je nastavení tzv. deadline – časového limitu, do kdy má být odpověď poskytnuta. Deadline omezuje maximální dobu běhu volání a chrání tak klienta i server před zbytečným zatížením systémových prostředků. Pokud server nedokončí práci v přiděleném čase, klient požadavek přeruší a zaznamená chybu s kódem DeadlineExceeded. Deadline se odesílá v rámci požadavku, což umožňuje serveru rozhodnout se, zda má práci přerušit, pokud je již překročen časový rámec.
V ukázce implementace serverová metoda GetShipper uměle zpožďuje odpověď o pět sekund. Na straně klienta je pak při volání nastavena třísekundová deadline. Výsledkem je, že i když server nakonec odpověď připraví, klient už ji nezpracuje a výsledek je chybový stav s informací o překročení časového limitu. Tento scénář nejen simuluje reálné síťové podmínky, ale zároveň ukazuje správné zacházení s výjimkami, které je třeba na klientské straně ošetřit – zejména výjimky typu RpcException s příznakem DeadlineExceeded.
Na serverové straně je také důležité zaznamenávat tyto informace v logu. Výstup logu pak obsahuje přesný čas, kdy byl požadavek přijat, jaká byla očekávaná deadline, a jakým způsobem došlo k ukončení požadavku. Na klientské straně pak sledování odpovědí a stavových hlaviček umožňuje analyzovat přesné chování služby.
Přesná správa metadat a nastavení deadline tak tvoří zásadní součást konstrukce efektivních a škálovatelných mikroslužeb. Je to nejen technická nutnost, ale i praktické opatření pro vyšší spolehlivost, predikovatelnost a bezpečnost distribuovaných systémů.
Při návrhu a implementaci je důležité chápat rozdíl mezi hlavičkami (headers) a trailery. Hlavičky přicházejí ještě před samotnou odpovědí – lze je tedy využít například pro předběžné ověření, sledování verzí API nebo stavových indikátorů. Trailers přicházejí až po přenosu obsahu a mohou obsahovat diagnostické nebo výstupní informace, které souvisejí s konečným výsledkem volání.
Rovněž je třeba si uvědomit, že přítomnost deadline nutí vývojáře lépe přemýšlet o výkonnosti svých služeb. Pomáhá předcházet situacím, kdy služba zůstává zablokována nebo zatížená požadavky, které již nejsou relevantní. Současně to vede k transparentnějšímu chování klientů – ti se učí očekávat chyby a správně s nimi pracovat, což je zásadní pro stabilitu většího systému.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский