Záznam ze Vzdělávacího okénka HAVIT, kde Jirka Kanda ukazoval některé aspekty odesílání e-mailů…
- SPF
- DKIM
- DMARC
Záznam ze Vzdělávacího okénka HAVIT, kde Jirka Kanda ukazoval některé aspekty odesílání e-mailů…
Záznam ze Vzdělávacího okénka HAVIT, kde Tomáš Wagner ukazoval, jak lze využít pull-requesty v Azure DevOps (Azure Repos) na organizaci code-reviews.
Záznam ze Vzdělávacího okénka HAVIT, kde Alex Hájek ukazoval, jak se z .NET (ASP.NET Core Blazor klientů) připojujeme na GraphQL API.
Záznam ze Vzdělávacího okénka HAVIT, kde Jirka Činčura ukazoval, jaké dochází v .NET 8 k ladění výkonu za běhu pomocí PGO.
Záznam ze Vzdělávacího okénka HAVIT z 8. listopadu 2023, kde jsem telegraficky představoval novinky přicházející v „.NET 8 vlně“.
Záznam ze Vzdělávacího okénka HAVIT, kde Jirka Kanda ukazoval, jaké v HAVITu máme coding-standardy a konvence v C# kódu.
Záznam z přednášky pro konferenci SQL Server Bootcamp 2023, kterou pořádal WUG Česká Republika v Brně 13. září 2023.
Slides z mé přednášky 12. září 2023 pro konferenci WUG Days 2023.2 Brno:
Záznam z přednášky pro konferenci WUG Days 2023.2 Brno z 11. září 2023.
Starší provedení přednášky, kde je méně profilingu a více ukázek kódu, najdete též na YT:
Demo samotné najdete tradičně na GitHub: https://github.com/hakenr/PerformanceTuningDotnetCoreDemos
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):
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ů:
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
Zaregistrujeme podpůrné služby do dependency-injection ve Startup.cs:
builder.Services.AddCodeFirstGrpc(config => { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });
Přidáme gRPC middleware někam mezi UseRouting() a definici end-pointů (před MapXy() metody):
app.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });
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);
}
DataContract pro označení třídy, kterou budeme používat jako datovou zprávu gRPC.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.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:
[ServiceContract]
public interface IWeatherForecastFacade
{
Task<List<WeatherForecast>> GetForecastAsync(CancellationToken cancellationToken = default);
}
[ServiceContract] nám označuje použitelnost pro gRPC (lze později využít i pro automatické registrace).CancellationToken, který nám může zprostředkovat signál o předčasném ukončení komunikace klientem (nebo přerušení spojení).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):
public class WeatherForecastFacade : IWeatherForecastFacade
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<List<WeatherForecast>> GetForecastAsync(CancellationToken cancellationToken = default)
{
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Today.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToList());
}
}
Připravenou službu vypublikujeme skrze Startup.cs:
app.MapGrpcService<WeatherForecastFacade>();
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.
Do projektu přidáme potřebné NuGet balíčky:
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:
@inject IWeatherForecastFacade WeatherForecastFacade
...
@code {
private List<WeatherForecast>? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await WeatherForecastFacade.GetForecastAsync();
}
}
Hotovo. Projekt by měl být nyní spustitelný a stránka Fetch data bude nyní komunikovat prostřednictvím gRPC-Web.
Svoje řešení si můžete ověřit vůči vzorové repository
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
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:
Obojí open-source s MIT licencí, zdarma.