WebAssembly is supported in all modern browsers (so not in IE) and is already supported by many compilers. You can try it with code written in C ++, Rust and many more languages. But not only that - many interpreted languages already have an interpreter written in Wasm (e.g. Python).
What about .NET?
So, it is great that C++ code can run in a browser, but it does not help in developing a web application. However, Microsoft took this opportunity and decided to build upon it. The ideal solution would be to compile a .NET Core web application written in C# into Wasm, but the current state of CoreRT and general support of AOT compilation in .NET is lacking (we'll see at the time of .NET 5 release and beyond) so it was decided to pick a runtime that supports JIT compilation and compile into WebAssembly only that and the application itself remains in .NET IL. After the first experiments, Microsoft remembered it had acquired Mono and picked it as the runtime. Since then, the AOT compilation has taken a few steps forward, so one day it will hopefully be ready, but this is a truly challenging task in many ways.
Server-side hosting model
Client-side hosting model
So far in preview, should be finished this year. It works as described above - the runtime is in WebAssembly, compiles the application from MSIL and it runs directly in the browser. Files needed to run the application can be statically hosted by the web server, but for any real-world application you will also need a server application, which will among other things also take care of hosting of the files. Since ASP .NET Core 3.1, Mono on WebAssembly supports .NET Standard 2.1. Previously, its support of only .Net Standard 2.0 lead to relatively wild hierarchies of project dependencies to deal with this limitation. Now you can literally use the entire .NET Core.
How to start with Blazor?
You should absolutely check out the Visual Studio sample applications and study the documentation. It would be pointless to write here about everything Blazor has to offer. Rather, I will pick a few topics in this and future articles.
Architecture of Blazor applications
Officially, there is no defined architectural pattern that Blazor application should follow, but we will not lie to each other - Blazor is certainly closer to MVC than MVVM (but it can be "forced" to MVVM too). If you want to adhere strictly to a pattern, there will certainly appear some libraries or steps to follow, but it is possible to develop in Blazor with a calm mind even now - just accept that it picks bits out of multiple patterns.
If you have ever worked with a framework that uses components, Blazor will not surprise you in any way. It's all about nesting them and inserting their hierarchies into pages and layouts.
Components are written either directly in C# or Razor. Of course, it is not the exact Razor you know from Razor Pages or MVC, but the principle is identical - it is a template from which the component class is generated. Basically, all you have to understand is that the markup code block in the .razor file is used by the compiler to generate the method for rendering the component. Therefore, you can inherit your component from any existing component and override its rendering method. This is useful for modifying built-in components. In addition, the generated component classes are partial, which is ideal if you do not want to have the C# code mixed with the markup code - just use a second file.
Blazor is aiming to work as efficiently as possible when it comes to redrawing the DOM, but it requires something from you in exchange. All components and elements have ids that must be unique to their parent, and in addition when compared to their siblings in ascending sequence - you must follow to this if you write the component's rendering function manually. Thanks to the identifiers, Blazor can quickly detect changes in the DOM and reuse items without deleting them and creating new ones of the same type - it just sends the input parameters into them again. However, you may be unpleasantly surprised if the component has its own internal state that does not depend on the input parameters - the internal state will remain, but the parameters will change to the component's parameters that had this id in the last render batch (typically in collections). Fortunately, you can also assign a component unique key (using the “key” attribute) that ensures the parameters are always mapped to the same component.
I will not describe here all the stages of the component life cycle; I rather recommend finding some illustrative diagrams. Moreover, the names of these methods are quite indicative. However, let me mention just a few notes about some of them:
SetParametersAsync: the main function of the component; you must call the parent's implementation synchronously - there can be no await before the call. Therefore, it is useful mainly for throwing exceptions when some parameters are not set.
OnInitializedAsync and OnParametersSetAsync: it is crucial to realize if you are correctly working with the component as it is being created. Note that the input parameters may change must the component must handle such change correctly. If you perform operations that depend on the input parameters in OnInitializedAsync, it will eventually bite you back. It is also important to note that if the calls to these two functions are truly asynchronous and therefore return an unfinished Task, the component is rendered immediately. In such case, it is rendered one more time when compared to situation when the method completes synchronously and the entire startup stage of the life cycle of the component is completed.
OnAfterRenderAsync: The returned Task is not awaited by Blazor, it is a fire-and-forget, but fortunately Blazor catches and handles exceptions thrown in it.
Communication between components
Blazor has a neat for one-way binding parameters to nested components. You can either send parameters directly to child component, or to all nested components (using the so-called cascading parameters). The nested components capture them either by type or name. To me cascading parameters seem as a double-edged sword – firstly, they do not contribute to the readability of the code, and secondly, their use can easily turn into a situation where they actually replace the internal state of the application, which should be solved by something more sophisticated. So do not overuse them. Blazor itself does not implements a shared store/application state. Either you reach for a finished solution or using a singleton that sends events to components is sufficient for your scenario.
Basically, all events in Blazor are handled with the EventCallback structure, which can handle both synchronous and asynchronous operations and at it also notifies the component that its state has changed and consequently the component is rerendered. When a component is rendered, its nested components that use any of its variables as an input parameter are also rerendered.
Blazor can even handle two-way binding. However, in fact is just one-way binding combined with adding the above-mentioned EventCallback (by default with the same name as the variable with the suffix “Changed”). This callback contains action that sets the value of the variable in the parent component. You must call this callback manually - either in a function every time you change a value, which is not very intuitive, or in the setter, but you have to have a duplicated property to avoid infinite loop (the setter informs the parent, it redraws and wants to redraw the nested component (because binding exists), it sets the parameter, and this happens over and over). Moreover, this callback can only be invoked asynchronously (since it can also handle asynchronous operations, but it is kind of unpleasant in a setter), so you must choose between fire and forget or synchronous wait for this method. It doesn't really matter, because it will run synchronously anyway, so pick what seems more right to you.
So yes – there is two-binding in Blazor and you can use it to chain parameters over multiple components, but it's kind of unintuitive. However, what I must acknowledge is that in two-way binding, Blazor also sets another optional parameter. This parameter has the same name as the bound variable with the suffix “Expression”. This parameter must be of type Expression<Func<T>>. And what is it for? Well, because it is always an expression with the same lambda in which only the member variable is present, you can extract the name of that variable from it. This is useful in many cases (eg when working with forms) and you do not need to pass the variable name explicitly.
Blazor and threads
WebAssembly does not support multithreading yet and this means that Blazor has only one thread available. It does not report itself as a thread-pool thread, but it is called that and fortunately it behaves like it. If you had only UI thread and an empty threadpool in your application, you would not have much fun with asynchronous functions because they have nowhere to run. Therefore, you can use asynchronous functions in Blazor, but you can't wait for them synchronously (which might be just fine - at least you find out where your libraries have issues with async calls) because you simply don't have the two threads available where one could wait while the other is running. Consequently, all synchronous waits for async methods cause a deadlock.
In the server-side Blazor, the situation is a bit different. There, of course, you have no problem with the thread pool, but something else is returning from the times of ASP .NET - synchronization context. Blazor needs it to guarantee working DOM synchronization, and it has the same limitations as in ASP .NET - one thread at a time. Therefore, if you are performing an operation in a thread with this synchronization context, you cannot wait for another that needs it. I mean you can, but it will deadlock.
We quickly ran through the introduction to Blazor and its basic principles. I strongly encourage you to give it a try because it is undoubtedly an interesting technology. What is most interesting about it, however, is its impact on application development. In the following articles, we will talk about the impact of writing C# front end on the overall application design and what to focus on, including a quick reference to the other features of Blazor and its future.