gRPC code-first for Blazor WebAssembly front-end

gRPC is a phenomenon of our time. This modern and performance-efficient protocol is rapidly spreading, and today we will show how to use it for communication between the Blazor WebAssembly front-end and the ASP.NET Core backend (host):

  1. We will efficiently use the possibilities of sharing code between the server and client part. We will use the code-first arrangement and put the “contract” (interface for the called service and data object definitions) into the assembly shared by both the server and client parts of the solution.
  2. To overcome browser limitations, we will use the gRPC-Web extension.

We will show the entire implementation on a simple example – we will use the default Blazor WebAssembly App template from Visual Studio (ASP.NET Core hosted, version of the .NET7 template) and we will convert the prepared Fetch data example, which uses the REST API in this template, to a gRPC-Web call using code-first.

Let’s do this, it’s just a few steps:

1. MyBlazorSolution.Server – Preparing ASP.NET Core host

First, we prepare the server-side infrastructure for gRPC. We will go directly to the version with the gRPC-Web extension with code-first support and install NuGet packages

We register support services in dependency-injection in Startup.cs:

builder.Services.AddCodeFirstGrpc(config => { config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal; });

We add gRPC middleware somewhere between UseRouting() and endpoint definition (before MapXy() methods):

app.UseGrpcWeb(new GrpcWebOptions() { DefaultEnabled = true });

2. MyBlazorSolution.Shared – Service contract definition (code-first)

Now we define in the form of an interface what our service will look like. We will then use the interface on the server side (we will create its implementation) and on the client side (we will generate a gRPC client that will implement the interface and we will directly use it in our code via dependency injection).
Add to the project a NuGet package that allows us to decorate the interface with necessary attributes

Find the example WeatherForecast.cs file from the project template. It contains the definition of the return data message, which the sample REST API now returns to us. We will convert this class into the following form:

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);
  • We added the [DataContract] attribute to mark the class we will use as the gRPC data message.
  • We added [DataMember(Order = ...)] attributes that mark the elements to be transmitted via gRPC (others are ignored, here TemperatureF is calculated and recalculated from other data on the client anytime). Each element needs to be set Order, which defines the fixed layout for the used protobuf serialization.
  • We replaced the original DateOnly type with DateTime. We have to stick to types supported by used protobuf serialization.

Next, we need to create an interface that will describe the whole service:

public interface IWeatherForecastFacade
    Task<List<WeatherForecast>> GetForecastAsync(CancellationToken cancellationToken = default);
  • The [ServiceContract] attribute tells us the applicability for gRPC (can be used later for automatic registrations).
  • By the nature of network communication, the entire interface should be asynchronous.
  • We can use the optional CancellationToken, which can convey a signal of premature termination of communication by the client (or disconnection).

3. MyBlazorSolution.Server – Implementing the gRPC service

Now we need to implement the prepared interface on the server side (we will use slightly modified code from the sample WeatherForecastController, which you can now delete):

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)]

Now we have to add the gRPC service in Startup.cs:


4. MyBlazorSolution.Client – gRPC client in Blazor WebAssembly

Now all that is left is to use the service in the Blazor WebAssembly front-end. The entire definition is available in the form of the IWeatherForecastFacade interface with its WeatherForecast data class.

We will add the necessary NuGet packages to the project:

Register the gRPC-Web infrastructure and the client (in factory form) in Program.cs:

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);

Well, now we can use IWeatherForecastFacade anywhere in the front-end project by having the service injected using dependency injection. So, for example, we’ll modify FetchData.razor to use our new gRPC service instead of the original REST API:

@inject IWeatherForecastFacade WeatherForecastFacade


@code {
    private List<WeatherForecast>? forecasts;

    protected override async Task OnInitializedAsync()
        forecasts = await WeatherForecastFacade.GetForecastAsync();

Done. The project should now be executable and the Fetch data page will now communicate via gRPC-Web.

You can check your solution against the sample repository

Other extensions and more advanced techniques

The gRPC service can, of course, accept input. In this case, use one input parameter for the incoming message – a data class created in the same way we prepared the WeatherForecast output. (Usually these classes are referred to as Data Transfer Object and thus given the suffix Dto. The implementation is usually as a C# record.)

If we have authentication and authorization in our project, then we can use the [Authorize] attribute on the implementing class/method, just as we would on a controller/action.

We can apply arbitrary techniques to the published gRPC endpoint like any other mapped server endpoint (rate limiting, caching, …).

gRPC has support for interceptors which can be used to further improve gRPC communication

  • pass exceptions from server to client (basic support is built-in, but you may want to enrich it with specific handling of custom scenarios),
  • passing the required culture from client to server (what language the front-end is switched to),

In a more advanced variant of the layout, you can also provide automatic registration of interface and data contracts without having to decorate them with [ServiceContract], [DataContract] and [DataMember(Order = ...)] attributes. All this and much more can be found ready in:

Both open-source with MIT license, free of charge.

Blazor WASM: Unsupported connection to AAD using the standard auth-library (Microsoft.AspNetCore.Components.WebAssembly.Authentication)

If you (like me) were hoping to “easily” create a Blazor application that connects to a generic OIDC identity-provider using the Microsoft.AspNetCore.Components.WebAssembly.Authentication library, while also supporting connections to Azure Active Directory (AAD) this way, you’ll be disappointed.

The idea is simple, AAD does support OIDC and therefore now why shouldn’t a generic OIDC client be able to connect to AAD as well. Unfortunately the hurdles are more than you would like to overcome.

While the Microsoft.Authentication.WebAssembly.Msal library for AAD is an extension of the underlying Microsoft.AspNetCore.Components.WebAssembly.Authentication library, it does a lot more than just boilerplate configuration of the underlying generic OIDC.

The basic difference can be found, for example, in the “interop” part with the underlying oidc-client JavaScript module.

  • AuthenticationService.ts in Microsoft.AspNetCore.Components.WebAssembly.Authentication,
  • AuthenticationService.ts in Microsoft.Authentication.WebAssembly.Msal.
    This is manifested for example when retrieving access-tokens. The MSAL version “fixes” the AAD specificity that when querying a token endpoint does not always return an access-token with all required scopes (the details are for a broader discussion, but e.g. you don’t get a token that has User.Read scope in it along with the custom-scope of your API, etc.).

The base library uses the “caching” of tokens in the oidc-client UserManager and relies on the assumption “If token-endpoint returned an access-token, then that token has all the required scopes in it.” (i.e., it stores the required scopes for the retrieved token, and then returns the already retrieved token the next time the same scopes are requested).

The “fixed” MSAL library knows this shortcoming of the underlying oidc-client and knows that while it claims to have a token for some set of scopes, the access-token may not actually have those scopes. Therefore, it “turns off” caching at this level and always gets the token again.

A week with Lenovo ThinkPad Z16

After two weeks with the ThinkPad P16s and a week with the ThinkPad P1 Gen5, I got the chance to try the ThinkPad Z16 to my great joy. The Z series is brand new and the character (minimalist aluminum chassis, USB-C ports only, high-end components) is strikingly reminiscent of Apple or Dell XPS laptops.

I’ll admit that despite the excellent paper specs, I was suspicious of this newcomer, thinking that a completely fresh model lineup would need a generation or two to iron out all the newborn issues. However, much to my surprise, I have to admit that it is a very hilarious piece and I am very seriously considering getting one, even though I was already decided on the previously tested P16s.

I got the pre-production model 21D5Z9ZVUS to test:

  • AMD Ryzen 7 PRO 6850H processor (45W TDP)
  • 16GB RAM
  • 500GB SSD
  • no dedicated graphics card, only integrated AMD Radeon 680M
  • 16″ WUXGA (1920×1200) touch LCD (IPS), 16:10
  • (135W USB-C charging, no LTE)

First impressions

At first glance, this is a different kind of ThinkPad, one that may even scare the die-hard conservative. On the other hand, I have to admit, using my own example, that if this machine hadn’t been labeled ThinkPad, I wouldn’t have had the urge to even try it and would have (wrongly) placed it somewhere in the IdeaPad category (or thereabouts, I don’t know much about it, just B-team Lenovo). The branding has undoubtedly played a role here, and it’s attracted my attention as well.

Anyway, forget the classic black ThinkPad chassis with rubberized or otherwise non-metallic surface. Here it is pure all-metal aluminum (but not shiny) in its classic light gray color. On the other hand, when opened, the surface is black and smooth (it’s quite slippery, you’ll only stumble over the black Lenovo logo under your right wrist), the edges almost sharp.

The first thing you’ll notice about this laptop is its size. The first P16s I tried seemed bigger than I would have expected, the subsequent P1 Gen5 seemed “about as I would have expected” and the Z16 is just another chunk more subtle than the P1 and in that respect “better than I would have expected”. The bezel around the 16″ display (16:10) is minimal (at the cost of a hump for the cameras and microphones), the thickness is even a little less, and the whole thing is suddenly kind of “just right – superior size”.

The choice of chassis material, 72 Wh battery capacity (versus 52.5 Wh in the P16s and 90 Wh in the P1) and touch display unfortunately predetermines the 1.9kg weight. Of course, a number somewhere around 1.5kg would be much more fitting for the machine, but compared to the 1.8kg of both the P16s and P1, it’s not that much of a difference.

The second thing you’ll notice immediately after turning it on is the noticeably inferior display. After years with high-res displays in the X1 Carbon and T14, suddenly the “ordinary” 1920×1200 “blinded” touchscreen suddenly hit me in the eyes. Fortunately, however, the Z16 comes (in addition to another non-touch 1920×1200 variant) with the ultimate OLED 3840×2400 display (with OGS touch), which neither of the P16s/P1 “competitors” offer, or the P1 does with 4K resolution in IPS. (We certainly can’t assume that the P16s/P1’s high-res displays are inferior; after all, the P-series boasts factory color calibration and are high-end displays for creative work – but OLED has its own “sound” and I assume it won’t disappoint anyone.)

The third thing that surprised me (very pleasantly this time) is thermal management. I care a lot about quiet operation and after a week with the P1 Gen5 and “charred sidewalks + deaf pedestrians”, I expected a similar experience here because of the 45W TDP. Yes, the AMD Ryzen 6850H has a paper TDP of 45W the same as the Intel i9-12900H in the P1 Gen5, and no way was I hoping that the relatively low-perforated aluminum chassis (compared to the P-models) would give room for some sophisticated cooling sound (especially if we’re only at the first generation of this series), unless it was redeemed by high temperatures and throttling performance. The opposite is true (!) – you can hardly hear the cooling during normal operation – even though the fans never turn off on AC power, the laptop just rustles lightly and doesn’t venture into any higher temperatures. When running on battery power, the fans even shut down, while under load it speeds up (still rather rarely and very refined).

Of course, I immediately thought that this would be dearly redeemed by the reduced performance, so I reached for the Passmark benchmark to get some basic idea:

The CPU performance is nowhere near the values of the P1 Gen5 with Intel i9-12000H (there the CPU score was ~31500), but it is still a very nice result and the overall tuning of the machine is perched a bit higher than the P16s (the latter was fitted with AMD Ryzen 6850U with 28W TDP).

Overall, I was surprised by the behavior of the 6850H processor with its paper 45W TDP compared to the 6850U and its 28W TDP. Apart from TDP and frequencies, I couldn’t find any parameters in which the two processors differed, while the H-version doesn’t seem to try to “cook” the laptop any noticeably more than the U-version I had in the tested P16s. The difference in measured performance is almost negligible (CPU score 25111 vs 23603) and more likely to be a difference in the overall tuning of the notebook model lines (firmware), with the ThinkPad P16s as a workstation trying to squeeze the most out of the processor (I’d rather not even mention the P1 Gen5, that’s a completely different formula). The ThinkPad Z16, on the other hand, seems willing to “boost” (bump performance requirements), but otherwise it’s more or less the same performance level as the 6850U. So for nearly twice the price, look for other benefits here than significantly higher computing power (e.g. quieter operation, subtler chassis).

Overall impressions after a week of production use

I’d be exaggerating if I said I loved the Z16 after a week, yet I like it a lot and if Lenovo tweaked these few parameters, I’d probably “rip their hands off” (not just me) for such a machine:

  • black carbon instead of aluminum + “softer” design,
  • at least HDMI and 1x USB-A ports,
  • half a kilo less (with a slightly smaller battery),
  • ideally bring back the classic ThinkPad chicklet keyboard with higher stroke, PgUp/PgDown keys and original layout of Ctrl/Fn keys and arrow keys, but I expected more difficulties with adaptation,
  • (no touch or, if anything, Yoga flipping for pen usability)

Actually, these are not major drawbacks, in fact the Z16 has many positives, for me in particular:

  • Excellent thermal management with quiet cooling and very mild thermal symptoms,
  • very decent performance for development (if you don’t need graphics, it’s an ideal tune),
  • subtle chassis (smaller than both P16s and P1 Gen5),
  • large and high quality 16″ display (OLED 3840×2400) – touch with Lenovo Pen option,
  • USB-C docking and power supply (it complains about the 65W adapter, 90W is enough, although for fast charging the machine comes with a 135W adapter),
  • solid battery life (estimated at around 10-12 hours for anything but Teams-meetings),
  • a classic centered keyboard with no numeric part,
  • high quality high-end workmanship (+service+warranty),
  • optional LTE module (SIM),
  • decent equipment: fingerprint reader, IR camera for Windows Hello, SD reader.

Of course, an essential condition is also the offer of a combination of components that meets my needs. Specifically in my case, this could be for example the 21D4001LCK variant:

  • AMD Ryzen 7 PRO 6850H (8C / 16T, 3.2 / 4.7GHz, 4MB L2 / 16MB L3)
  • Integrated AMD Radeon 680M Graphics
  • 32GB Soldered LPDDR5-6400 (dual channel)
  • 1TB M.2 2280 PCIe 4.0×4 Performance NVMe Opal 2.0 SSD
  • 16″ WQUXGA (3840×2400) OLED 400nits Anti-reflection / Anti-smudge, 100% DCI-P3, Dolby Vision, Touch
  • LTE: Quectel EM05-G, 4G LTE CAT4
  • FHD 1080p + IR Discrete with E-shutter
  • 3Y Premier Support

Final summary and comparison of P16s / P1 Gen5 / Z16

We’re moving into the 16″ ThinkPad notebook category here with a 16:10 aspect ratio display…

If you’re looking for the ultimate ultra-mobile graphics machine, are willing to sacrifice performance for everything (especially audio/thermal comfort and battery life), and have an unlimited budget, then go with the Lenovo ThinkPad P1 Gen5. Go for a variant with some dedicated graphics card to suit your needs and enjoy a formula that just about anyone else doesn’t have.

If you’re looking for a powerful machine that can also handle some of that graphics work, but you need to budget somewhere around 40,000 CZK + VAT, then go for the Lenovo ThinkPad P16s. If you prefer battery life and quieter operation, then definitely the AMD variant, absolutely ideal for developers. If, on the other hand, you need to crank up the graphics performance, then the Intel variant with a dedicated graphics card will probably do the trick (AMD versions are only made with integrated graphics).

If you are willing to pay twice as much, somewhere around 80 000 CZK + VAT, you are not concerned about workstation parameters (color calibration, ISV certification, etc.), you do not insist on port equipment, but want to indulge in a more compact design, quieter operation and maybe a little more subjective performance for development, then I recommend Lenovo ThinkPad Z16 with OLED display (or IPS without touch if you want to save).

…I’ll probably go the Z16 route at this point. Be surprised and look forward to the continuing story.

PS: I finally had the Z16 on loan for two weeks and am ordering it in the 21D4001LCK configuration. I’m keeping the P16s in my sights for other options.

A week with Lenovo ThinkPad P1 Gen5

After more than two weeks with the Lenovo ThinkPad P16s AMD Gen1, I had the opportunity to try out the Lenovo ThinkPad P1 Gen5, specifically the pre-production configuration 21DDZA2PUS. The ThinkPad P1s are the workstation-version of the ThinkPad X1 Extreme, which is the bigger brother from the flagship X1 Carbon. Specialty machines aside, we’re moving to the very top of Lenovo’s lineup here.

The loaner machine was fitted with

  • Intel i9-12900H CPU
  • 64GB RAM (2x 32MB)
  • 4 TB SSD
  • no dedicated graphics card, only Intel Iris Xe integrated graphics

The goal was to make a direct comparison with the P16s, i.e. to conclude which of the two machines is the right one for me. I’m recalling my main conclusions on the P16s, as I’ll mainly describe the differences here:

  • The P16s goes beautifully for performance, the AMD Ryzen 7 PRO 6850U processor with 28W TDP is a more caustic successor to the 5850U (15W TDP) and overall it is unfortunately noticeable on thermal-management (noticeably noisier cooling than my current T14 AMD Gen2),
  • The P16s is a bit of a pussycat; not quite a giant, but a slightly more subtle design would be deserved,
  • The P16s has a numeric keypad, and paid for it by shrinking the base keyboard slightly,
  • The P16s has a comfortable large 16″ display, which I find very comfortable.

First impressions of the P1 Gen5 (day 1)

Right out of the box, it’s obvious that this is a higher-end piece than the P16s

  • The machine is a bit more subtle (compared to the X1 Carbon it’s still a giant, but let’s just say that’s the sort of size I would expect from the P16s in my transition from the T14/P14s),
  • the touch-pad is nicer to the touch, and it’s precision-grazed (on the P16s I found it had a bit of a tendency to ding, though I’ve definitely experienced worse on older ThinkPads),
  • the machine doesn’t have a numeric keyboard section and so the base section is unreduced (it remains smaller in stroke than the previous ultimate Lenovo chicklet keyboard, but the layout fits and I had to get used to the new distance of the keys from the chassis edge rather than the stroke being an issue; the keyboard, on the other hand, is a bit quieter, supposedly the keys are foam-backed),
  • the loaner model, although it doesn’t have a dGPU, was fitted with two coolers, this may prove to be both an advantage and a disadvantage, we’ll see later,
  • The P16s has a cooling outlet to the right side, the P1 has a grille on the entire back (how the cooling efficiency is affected by the fact that when the laptop is open, the lid is placed in front of the back in the path of the air flow, I dare not guess).

The very first PassMark test showed a score of 4310, a good chunk lower than the P16s with the AMD processor (~5900). Don’t be fooled though, the whole score is thrown down by the very weak Intel Iris Xe graphics part, the performance of the rest is brutal on the contrary:

  • CPU Mark ~31500 vs. ~23600 (+33%)
  • 2D Graphics Mark ~400 vs. ~800 (-50%)
  • 3D Graphics Mark ~3430 vs. ~5800 (-41%)
  • Memory Mark ~3440 vs ~2260 (+52%)
  • Disk Mark ~31100 vs ~22050 (+41%)

Note: A machine without a dGPU was my specific wish, the vast majority of P1s instead come with a dedicated graphics card and there are several to choose from. I don’t need the graphics performance for development, so I’m looking for a configuration that won’t add additional TDP to my already stretched thermal-management.

After a week of use

I finally installed my work tools on the P1 Gen5 and used it for a week for a production workload.

Compared to the P16s, it’s actually pleasantly subtler, the classic keyboard layout is also easier to adapt to, but I spent the whole week practically not worrying about anything other than whether I could somehow tame the cooling. Gradually, I’ve come to realise that it’s a futile struggle, and that I’m really sitting at a machine in a different category, for a different target group than me.

With the P1, everything is obviously subordinated to maximum performance, and no compromises are attempted:

  • The Intel i9-12900H processor is just a level away. With its 45W TDP, it can continuously heat up the machine to the point where the P1 doesn’t even attempt a “no fan running” mode. There are also two fans and the cooling just makes itself known. How it would work with a dedicated graphics card I dare not even guess. Nor do I dare hope that the situation would be any significantly different with the more mundane i7-12800H or i7-12700H processors, which would be out of the question for me. They both have the same TDP of 45W and I don’t expect such a significant difference.
  • I was surprised that the P1, despite being fitted with a large 90Wh battery, only lasted around 2-2.5 hours on my lap (and that was just looking up flights in my browser). Initially I interpreted this as a non-correct condition and looked for a bug in the settings/firmware/drivers, but gradually I found other users’ experiences on the net and realized that this is just the way it is.
  • Similarly, I was surprised to find a hot machine on my desk every morning that had slept overnight in Modern Standby (S0). The fans weren’t running, but the heat production remained respectable.
  • Still, it must be remembered that the loaner is a pre-production model. Thermal-management tends to be more problematic with those, and one can expect a bit more restrained performance with production pieces. Likewise, it’s common for new models to take a few months for things to settle down and for cooling to find its optimum (either through driver/firmware updates or through Intel Dynamic Tuning Technology, which tries to find a tune for each machine using AI/ML).

Overall, I have come to the conclusion that the P1 Gen 5 is not for me. It’s a performance maximalist, and you have to be prepared to pay for that performance by sacrificing audio comfort, accepting significant thermal performance, and sacrificing battery life.

The P1 is such a formula. It roars, it shoots flames, it has power to spare, you’ll beat anyone by a class difference. I’ve decided I’m more comfortable with a regular sports car in the form of the P16s, it beats most rivals too, but you can drive it around town without leaving charred pavements and deaf pedestrians in your wake.

PS: Much to my delight, I got the chance to try out AMD’s brand new ThinkPad Z16. So you can look forward to the third installment of my selection anabasis.

Two weeks with Lenovo ThinkPad P16s (AMD)

I’m a long-time fan of ThinkPad laptops. It’s not a fanatical love, but rather a moderate satisfaction combined with conservatism and an unwillingness to risk change. It’s just that with ThinkPads I kind of know what I’m going to get, I’m set on it, and I’m fine with it.

With ThinkPads, I started somewhere around the X201 and X230 when it was still a complementary machine to the main desktop, then went through the T420s, T440s to the flagship X1 Carbon (Gen4 and Gen6). I’ve always been looking for a machine for developer/office work (let’s say 50:50), and I care about solid performance, quiet operation, and I cared about light weight (daily commute with a bike backpack). On the other hand, I’m willing to pay 80K for a laptop, it’s my main work tool and I’m not really limited by budget (more expensive machines seem more like a splurge to me, rather than me wanting them and not being willing to pay that money for them).

Basically, keeping the basic criteria in mind (quality, weight, size, …) I always look for the best balance between performance and noise, and I have quite demanding criteria for noise and a pretty low upper limit. (Lately I’ve added the requirement for USB-C charging, I’m tired of carrying around adapters separately for different devices.)

Around a year ago, it came together again and I was looking for a replacement for my then X1 Carbon Gen6. Naturally, I was looking for the latest X1 Carbon at the time, however, after two X1s I had already experienced the relatively problematic cooling of the higher performance in these ultra-light machines and so René Stein’s positive recommendation of the ThinkPad T14/P14s with the promising AMD processor caught my eye.

Lenovo ThinkPad T14 AMD Gen2

I bought a T14 back then and after a year of daily use, I have to say that the ThinkPad T14 AMD Gen2 (specifically the 20XK002UCK) was a great choice. Intel slept a bit back then and the AMD Ryzen 7 PRO 5850U processor was a proper cut above comparable Intel models. With only 15W TDP (= extremely quiet operation, minimal throttling) it gets a lot done (super performance) and I really can’t praise the T14 enough. It may not be as subtle and exclusive as the X1 Carbon, but it’s still a great piece of hardware that carries very good performance for development. As a bonus, it was half the price of the X1 Carbon, so I wasn’t even afraid to take a chance on it at the time.

For the record, the T14 is essentially the same hardware as the P16s, differing in things like factory LCD calibration, ISV certification, etc.

Lenovo ThinkPad P16s AMD (Gen1)

And here’s today. After a year (I usually last two or three years with one machine), I’ve started itching for a change. I don’t really know why. I still consider my T14 to be a great machine, and I would be perfectly fine with it for another year/two. The only thing that bothers me is the 16:9 aspect ratio, seeing that today’s ThinkPads are 16:10, and then the size. For years I’ve mocked a colleague for lugging around a 15″ laptop, and it’s gotten to me, I can’t see it well and I’m tempted by the larger display.

So it happened at the Update Conference that I hobbled over to Lenovo’s booth and walked away with an offer to borrow a ThinkPad P16s AMD Gen1. I’ve been eyeing their new ThinkPad Z16 before, but there I’m afraid of the all-new Z design (aluminum chassis ála MacBook or XPS, no ports), which I’d rather give a generation/two of time before it sits with Lenovo.

It took a while to get the loaner produced, but I ended up with a pre-production piece of ThinkPad P16s with the model name 21CLZA96US (WQXGA 2560×1600, AMD Ryzen 7 PRO 6850U, 32GB RAM, 2TB Performance SSD). Because I had arranged a two-week loan, I was able to install my work tools on the machine and used it in full production mode – a week of which was in classic mode (i.e. at work in a USB-C dock, at home standalone) and a week with the covid in full home-office (standalone).

First impressions (day 1)

On first hold, this is a denser machine than the T14. I was kind of hoping that as it’s more or less identical hardware in a different chassis, it would just be stretched to a format to accommodate a larger display and keyboard, but in fact it’s grown a bit in thickness as well, and right off the bat it struck me that a slightly more subtle design would suit it better.

The second thing that surprised me from the first moment was the keyboard. It’s the first ThinkPad I’ve ever tried that has a numeric keypad. I thought I’d just have to contend with the keyboard being offset to the left and would rather benefit from the added numeric section over time. But it turns out that the classic keyboard part is a bit smaller, and thus the good old days of the ultimate ThinkPad-chicklet keyboards are probably gone. The keyboard also has a smaller stroke.

On the other hand, the advantage of the 16″ display is clear from the start. Not only does more fit on the screen, but everything is bigger and beautiful to work with. For me, an expected and obvious plus from the first moment.

The machine came with Windows 10 pre-installed, which I practically immediately reinstalled to Windows 11. I managed to do a quick PassMark Benchmark, unfortunately I didn’t save it, but as far as I remember it came out a tad higher on Win10 classic than the subsequent Win11. The very first PassMark on Win11 came out 5900 points.

During the first day of playing with the laptop, it turned out that it was a bit orders of magnitude noisier than my existing T14. The cooling vent triggered almost every time I touched the mouse that day, and it was not a decent vent, but a distinct whirr. However, on the noise level of the machine, it should be noted at the outset that I was borrowing a pre-production piece, where this aspect is traditionally more problematic and production models tend to be more polished in this respect. In addition, thermal management is improving over time (with new firmware and driver versions). So personally I expect (hope?) that the resulting behavior will be noticeably better, certainly not worse.

Impressions after two weeks of production work

I ended up using the laptop for two weeks at full intensity as my only machine. I don’t know if I’ve rather gotten used to it, but I would definitely say subjectively that the thermal management has settled down a bit after a few days, the laptop is now willing to even slightly cool down during work, and it’s no longer just from extreme to extreme – nothing vs. blower. In office noise with a docking station, I’m basically not even aware of the cooling (except for the notorious MS Teams meeting issues, which are willing to eat up any amount of power and battery and could easily be used to fire up machines of any category), in a quiet home environment it echoes more than I would like, but acceptably so even for my high standards.

Anyway, the machine goes very willingly for performance (probably also due to the P-workstation tuning, compared to business T-models) and doesn’t hesitate to hold the CPU boost for longer periods of time, which necessarily implies the need for more intensive cooling. Additionally, the new AMD Ryzen 7 PRO 6850U has a TDP of 28W, so 30-38W normally flows into the CPU.

Summing up the overall impressions, the distinct pluses are:

  • Large 16″ quality display (at 2560×1600 resolution, it allows for good scaling),
  • a powerful AMD Ryzen 7 PRO 6850U processor with an acceptable TDP of 28W,
  • overall a performance-forgiving tuning (unless you need graphics performance),
  • ThinkPad quality chassis design,
  • USB-C power supply (even a small 65W adapter will suffice),
  • wide range of ports (USB-C, USB-A, HDMI, RJ-45, audio, …),
  • wide range of equipment (fingerprint reader, LTE module, smart-card reader,

Disadvantages include:

  • cooling could be quieter (I do not expect passive ala Mac, but for example ThinkPad T14 is two orders of magnitude better in this),
  • the design (size and weight) I would have liked to see more subtle, it’s quite small (compared to what I was used to),
  • the keyboard – I haven’t found the smaller format with the numeric part and smaller stroke yet.


Despite the described drawbacks, I consider the Lenovo ThinkPad P16s a very hilarious piece for anyone who needs a powerful laptop for development and desires a larger format. For comparison, I still have a promised loan of an Intel ThinkPad P1 Gen 5 (which is also made in a version without a dedicated graphics card). With its keyboard without the numeric part and at a slightly smaller size, it could be an interesting alternative. We’ll see how the intel processor (45W TDP) behaves in the performance vs thermal management relationship.

…Anyway, I’m ready to pick one of these laptops at the moment, I already promised my T14 to a colleague. :-D

Lenovo WWAN – Quectel EM120R-GL – No service

Just spent several hours fixing the “No service” cellular issue in my Lenovo T14 AMD Gen 2 with Quectel EM120R-GL. The notebook was able to search for networks (when disabled the automatic network selection), but was not able to connect to internet (Vodafone CZ mobile provider).

It was more and more obvious that the issue is related to the APN profile.

In the end I found the right settings which connected the notebook to mobile internet almost immediately:

Announcing HAVIT Blazor 1.4.3 – Free Bootstrap 5 components for ASP.NET Blazor

Didn’t have a chance to announce our component bundle on this KnowledgeBase yet…

Now we released version 1.4.3. What’s new?

  • HxInputDateHxInputDateRange and HxCalendar have new MinDate and MaxDate parameters to allow customization of selectable dates in calendars (also added to Defaults to be able to customize the application-wide defaults)
  • HxInputDate and HxInputDateRange have new CalendarDateCustomizationProvider which allows further customization (enabled/disabled, CssClass) of individual dates in dropdown calendars
  • ⚠️ HxCalendar parameters MinYear and MaxYear replaced with the new MinDate and MaxDate parameters
  • HxCalendar has new simplified month/year navigation
  • HxInputDate fixed validation icon position if CalendarIcon is used
  • HxInputFileCore has new HxInputFileCore.Defaults.MaxFileSize application-wide default to be able to limit maximum file size,
  • HxInputFile has new HxInputFile.Defaults.InputSize application-wide default to be able to set form component size
  • HxSidebar fixed ability to scroll on mobile if viewport is overlapped
  • HxSidebar has new CSS variable for customising background-colour
  • Updated to Bootstrap 5.1.3 and Bootstrap Icons 1.6

What is HAVIT Blazor?

HAVIT Blazor is a free open-source (MIT) component bundle build on top of Bootstrap 5. It not only covers all Bootstrap 5 components but also brings a few enterprise-level ones (e.g. HxGrid, HxInputDate, HxAutosuggest, HxInputTags) and special ones (e.g. HxGoogleTagManager).

Interactive documentation & demos –

Source code –


Buttons & Indicators

Data & Grid

Layout & Typography


Modals & Interactions


Enterprise-application template [OPTIONAL]

Beside the components there is a ready to run enterprise level application template which includes gRPC code-first communication, full layered architecture stack (Model, DataLayer, Services, …) and much more.

Blazor WASM error: Could not load settings from ‘_configuration/BlazorClient’

Make sure your startup project is set to Web.Server (ASP.NET Host).

This kind of error appears when you try to start the Web.Client directly.

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Could not load settings from '_configuration/Havit.Bety2.Web.Client'
      Error: Could not load settings from '_configuration/Havit.Bety2.Web.Client'
          at Function.createUserManager (http://localhost:59799/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:5893)
          at async Function.initializeCore (http://localhost:59799/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:5027)
Microsoft.JSInterop.JSException: Could not load settings from '_configuration/Havit.Bety2.Web.Client'
Error: Could not load settings from '_configuration/Havit.Bety2.Web.Client'