Blazor – The Good, the Bad and the Ugly
My very first Steps in the wonderful world of Server-Side Blazor with ASP.NET Core
This is an older Blog Entry i have written a bit over a year ago, but i gave up on hosting my own platform pretty quickly.
After living career-wise under a rock for the past 2 years and not having a chance to test and grow my programming skills in a professional environment, I have missed a lot of development in the ASP.NET Core community.
Having switched my Employer recently, my new job includes a lot more programming and far less supporting a low-quality software, I now have plenty of catching-up to do.
Lots has changed.
They decided to rewrite the Core of Entity Framework Core, allowing for the grand reappearing of already fixed bugs (in fact, I do not recommend an upgrade of your old software projects if they run pre-3.0. This may break the application), dotnet core 3.0 came out with surprisingly little changes and they published yet another architecture to have your (web)server communicate with the client: *Blazor
2-Way Communication with the client in real-time and not a single speck of JavaScript programming required? Heck yeah count me in!
The Good
So, what is Blazor?
Blazor – or in this specific case: Blazor Server-Side as there is also a client side variant that gives me some flashbacks of my short time with Angular, is a new way of delivering and communicating with the website your webserver has just delivered.
And its not limited to websites either, as the underlaying technology, the SignalR Hub, allows for real-time interaction with basically every client you like.
At work, we already use SignalR to communicate with a Dotnet Framework (not core!) WPF application to display various monitoring data in real-time and its pretty darn impressive to watch.
And this works for Websites too!
A Blazor Server-Side Application only sends a token-website to the client. This only includes a small JavaScript applet together with an HTML Framework to make the Website run. Afterwards, all further communication will continue via the JS-Applet.
Whenever the Server decides that additional Parts needs to be displayed, it will render that part and that part alone, it to the Client which keeps a permanent connection to the Server and the Applet updates the specific part in the HTML Framework. And this also works two-way. Each action will be sent back to the Server who then decides if any more parts needs to be updated again.
For me, this means I have not to deal with any client-side programming at all. All Code can be written entirely in C# (or VB if so desired), HTML and CSS with all the bells and whistles the dotnet framework offers.
And since architectural Blazor renders component for component, the whole thing is Modular. Define one component like a navigation menu or similar and you can reuse it again on other pages.
This makes it fun to develop because things like input-validation can now be done entirely server-side.
The Bad
Of course, being barely 2 years old and basing on the dotnet core framework which introduces application-breaking changes with each major version update, there are some teething problems that every new product experiences.
To make matters worse, previous experiences in the web development area do simply not apply here anymore. Over are the times of request-based development where you put as much information into each response as each request is slow and expensive.
No more controllers / interface-channels, heck even the term “webpage” barely qualifies anymore due the highly modular setup.
The whole setup is more akin to a thin-client running entirely on the server than the traditional webserver-client relationship.
As such, there are not many experiences found in the internet of other developers, documentation and demos are scarce (in comparison with like ASP.NET MVC) and it seems, some use-cases have simply been forgotten or overlooked when designing the base architecture.
As such, I spend roughly 14h last weekend working on a simple Blazor-component based login because by god I hate the ASP.Net Identity Package that Microsoft loves to ship whenever you make the mistake of selecting one of the pre-set authentication-methods on project generation just to learn that cookie-based authentication via Blazor-component is not supported in the current architecture and you need to revert to the old request-based communication to set the cookie on login.
I did not fully understand why, but that is the census on the developer team, they will not change anything here anytime soon either.
And this is not a single case either. A lot of use-cases that are hardly to think away from websites nowadays have simply been overlooked.
I also did already ask my share of stupid questions on StackOverflow as I kept falling back in old habits and need to experiment a lot with things which cost time. And the Visual Studio Editor is also not fully compatible with Blazor-components yet, it gets slow and hard to use with growing complexity.
Also, since Blazor renders each component individually, it uses a truly asynchronous architecture, rendering them in parallel. This means you really need to be aware of this, as you quickly will run into concurrency problems and/or memory leaks.
… and the Ugly!
And this brings me directly to the biggest problem I keep struggling the most, one that almost (but not quite) makes Blazor a gamebreaker: Entity Framework is not truly asynchronous. The times I ran into concurrency-problems with EFCore 3.1 is so damn high, I started reverting to run Blazor as well as EFCore strictly in a synchronous context.
This is a darn shame because this means no partial page-updates while the server still renders the whole.
Blazor offers 3 ways of which it can handle a service (such as Entity Framework):
Singleton – The service will be instanced once on demand and will be reused for all following demands. Working thread-safe here is a must.
Scoped – The service will be instanced once per request, aka the current user-session as its stateful. Thus, each user has its own instance of the service for all demands. Given the parallel rendering of components and that a user is potential able to send another action while rendering, working thread-safe here is a must as well
Transient – This is the only being thread-safe is not strictly needed, as each demand will create a new instance of the service. This however will quickly result in a huge memory usage as everything needs to be re-allocated with each demand.
And here lies the Problem with Entity Framework. It does not fit into either category as its architectural a hybrid of singleton and transient. Its singleton because it keeps track on the database changes and holding a store of frequently used data and it is a transient as each time the database is queried, the data-reader is busy and hence needs to be newly instanced with its own connection and all.
If you use the whole Service as a singleton, you will quickly run into the situation where you want to access the data-reader while its busy with a previous task.
Should you instead use the whole Service in a transient mode, each time you access the data-reader a new DbContext needs to be created, data gets stored redundantly and while the construction of the DbContext is not that big of an overhead, it’s a overhead nonetheless that takes additional time and memory. I noticed a heavy memory-leak here as well, going above 1GB of usage after clicking around a couple times on my website for a couple minutes.
In the end…
… I still like Blazor. Simply because I can stay in my warm and cozy Visual Studio IDE, working with well defined languages even if the Razor-Editor loves to partially crash when I use the 2-way databinding.
Since I do not need to write any JavaScript of my own as it will easily bind with any html-element on its own and comes with its own additional controls as well, it beats traditional web-development by a landslide for me.
I just hope that with time, the Blazor-Community will get the concurrency problems with other Services under control, as this is a massive headache not just for me. It feels like every second article I read about Blazor is how to get more complex Services run smoothly here.
However, I do not think that Blazor will replace traditional Request-based Websites.
While Microsoft states that a Dual core with 4GB Ram can handle up to 5000 simultaneous Users (according to my memory), a single poorly optimized Service can crash that card house easily.
For me, Blazor has its place in the environment of an enterprise intranet where the userbase is small and quality of data is more important than server bandwidth.
And the fact that many use-cases such as cookie-based logins via Blazor-components was simply overlooked when designing the architecture, show me that the developers thought so too.