The main difference between any large system and a small system is the complexity related to having multiple developers in the team, and then the complexity of the maintenance over time. Any mistakes in architecture cause big problems that go on and on.
Since Client Side Blazor runs in the client’s browser, you don’t have control over the computer that it runs on. Correspondingly with Server Side Blazor, your application will be limited by the internet speed of your users. Server Side Blazor may not be your first choice if you intend to deliver your solution to a mining company in Wiluna WA. Equally, you would question the wisdom of delivering a Client Side Blazor app to racing car drivers with low end computers.
Therefore we will build all our future Blazor solutions as dual ClientSide/ServerSide solutions because:
If your solution will EVER have a mobile component (all ours do) then going MVVM allows you to share your code on your mobile build.
Not all of our mobile solutions duplicate the functionality required on a Web app, but when they do, it is usually not trivial and comes with significant savings. We expect that more and more often we will be able to enrich the experience for a mobile user because we have that function available.
For those of you unfamiliar, the MVVM design pattern is quite different to the MVC pattern but from a practical stand point you put your page based business logic in a class separate to the page (called a View Model), you add View Model based navigation (Blazor’s navigation is page based), and you add Property Notify Change functionality so that the page can respond to a property change.
Remember that even for your Client Side WASM implementation, your database will sit on your server.
We implemented SQL Server on Azure, but this is probably irrelevant for this discussion.
On our ServerSide implementation, our pages access the database directly, whereas with our ClientSide implementation we access via an API which then accesses the data directly.
But A and B are the same piece of code. Therefore at all three ‘x’s we implement an IDataServices interface which, through dependency injection, resolves to different implementations.
Note that ServerSide and the API resolve to the same direct code, offering a single database optimisation point.
The API in the above diagram is the same API we use for our Data Transfer Objects coming to and from our mobile apps, with some caveats. Mobile apps:
This is a work in progress for us.
So far we have been able to use a single API for both because:
So far so good. But we have a number of fall-back options that don’t impact our architecture.
It is unusual to use async programming on the server, but this isn’t just a server side solution.
Although we haven’t proved this, in theory, for a reasonable sized implementation, ClientSide Blazor could quite easily block the UI thread. For this reason alone we choose to go async programming. You can’t add it in later.
We wrap third party components in our own components. Sounds wasteful but there are only 20 or 30 of them, and the upsides are:
Early on we chose to base our user interface design on the Material Design. That decision simplified our transition to Razor pages considerably. We chose and recommend MatBlazor (https://github.com/SamProf/MatBlazor) and thank Vladimir for his considerable efforts.
Our first major challenge, like with any large project, was standards. Different programmers doing slightly different things. Blazor projects add new dimensions to this problem.
Our second challenge, which we didn’t realise the extent of until we went live, was the user experience with respect to bugs. ServerSide Blazor sites on SignalR, which is effectively a continuous socket connection. If the SignalR gets killed the user is left in a horrible dead screen state with a “Press Reload” message. No option to give you a screen print, and if you are not careful the only details of the error are hidden in the console of their browser. Horrible and expensive.
Large site.css files are a nightmare on a large project. It eventually got to the point that it was easier to create new css code rather than try and work out the impact of changing the existing. Hence this small note … we now use SASS. Our implementation is simple: align the SASS folder structure to our Blazor folder structure, which means css is easy to find and change and the bootstrap and ionic type css are out of harms way with no temptation to change.
Base holds our variables (site colours, panel sizes, font sizes), our fonts and functions.
Components holds a sass file for each of our components.
Vendors holds any vendor supplied css or sass file.
Views holds our page specific styles and classes.
These are pages that change because of underlying data changes, as distinct from user actions. Two examples:
Blazor is really good at doing this type of thing and we bake it into our architecture. Without going into too much detail, which would be an entire blog by itself, we do this:
We call this the ModelStateChanged event notification.
Razor pages are used for two different purposes: Components and Pages. There are also two different styles for creating Razor code: @Code{} and code-behind. Which should I use?
In components we use the @Code {} style because they are generally small and we can see all the code on a single screen.
In pages we use the code-behind style:
Maintenance is a lot easier if razor syntax is separated from business logic code, especially when the programmer changing it is not the one who wrote it.
The learning examples for creating razor pages, where accurate, often don’t reflect what we are aiming at in a large system. Below is a snippet which I hope illustrates some key points which help us create systems that are more maintainable:
Having built large systems on many platforms, we understand the importance of a good architecture. Blazor is no different. The principles of good architecture don’t change, so the question is simply how do you do this with Blazor in a way that maximises the wealth of benefits that Blazor offers.
We consult in Blazor and Blazor Architecture, and we offer a pragmatic approach to taking a desktop app to the cloud using Blazor.
In the spirit of reconciliation, AAD respectfully acknowledges the Traditional Custodians of country throughout Australia and their connections to land, sea and community. We pay our respect to their Elders past and present and extend that respect to all Aboriginal and Torres Strait Islander peoples today. Our head office is located on the land of the Gadigal people, of the Eora nation.