In my last article I wrote about a Blazor demo application using the server side hosting model. I promised that a larger series of articles on Blazor will follow. This is the first article in this series and I’ve decided to start from the most fundamental concern when building a new application: how o I architect my application?
When it comes to Blazor this is actually still an empty field and the role of the wider community is right now to work out some architectural concepts and best practices. I’m aware of a MVVM approach to Blazor, which seems really nice and probably very familiar to the developers with experience in developing desktop applications. I know it’s a matter of perception but this approach doesn’t seem very natural to me. Probably due to my lack of experience in the field of desktop applications and due to the fact that Blazor is in the end a single page application framework and as such it probably has its own particularities.
Instead, I was thinking of using an approach inspired by other single page application frameworks. Since I have some experience with Angular I thought to adopt some Angular architecture principles and implement them in Blazor. That’s what I’m doing in my demo app, which is very much still work in progress. However, till now this approach seems to work smooth and doesn’t pose to many difficulties. So let’s dive right into it.
Folder structure in Blazor apps
In Angular there are some clear best practices on how to organize folders. Features should be organized in modules and modules should have their own folder. In Blazor we don’t really have the concept of modules, but I think it makes sense to keep the idea of one folder per feature. Hence we can create one folder for each feature that we want to have in our Blazor app and put all code belonging to that feature in that specific folder. Therefore, I have a folder called “Features” and in that folder I have another folder for each feature.
If we take the “Login” feature as example, we’ll notice that I’ve put there all code related to that features. Besides the component itself, I also have two “model” classes that are actually used only within that component.
There are some clear advantages using this approach. First of all it is very easy to guess where you’ll find the code you are looking for based on the feature you are referring to in the application. Let’s imagine that somebody finds a bug in the data table where repositories are listed. If you want to start working on it, it’s already clear that you’ll find the code related to this bug in the “Repositories” feature.
Another advantage is that using this approach you’ll get the flattest folder structure possible. If we use convention based folder naming (what we usually do in MVC apps) you probably noticed that once the application grows, the folder structure gets deeper and deeper. Hence, overall I feel that this approach is useful.
Split markup and C# code in separate files
We can achieve this in Blazor using inheritance. Some might say that this introduces coupling and as we know, coupling is bad. But in this case coupling is good in my opinion, because a component is nothing else than a self-contained chunk of user interface (UI), such as a page, dialog, or form, that happens to also contain some business logic. Therefore, a component includes HTML markup and the processing logic (C#). We have a markup language and a programming language that in a certain way belong together, even if they for sure are used to achieve total different goals.
Having them in one file is in my opinion not optimal at all when you go outside demo projects. In real projects a simple data grid could have tens of lines of markup (maybe more). Having the C# code at the end or beginning of the markup is not very friendly for my taste. So yes, I would say that components contain two fundamental parts so it makes sense to split them in separate files. But these parts also logically belong together. So coupling in this case makes total sense for me. That’s exactly the same way Angular components couple markup, TypeScript code and CSS. All of them are in separate files, but belong to the same component.
“Core” and “shared” in Blazor
The whole idea of “core” and “shared” in Angular is very useful in my opinion. Therefore it’s also a point that we can re-use in Blazor applications. The main responsibility of the “Core” folder is to contain all application wide services. In other words, services that are used by all (or almost all) components. In the demo app I have for now two such services: the data service and the app state service. Those services are injected in most of the components. One of them is responsible to interact with the GitHub API and the other is responsible to keep track of the application state.
In the “Shared” folder we can put re-usable components. In Blazor these will mostly non-routed components like buttons that you can re-use each time you need a button. For now I put the sidebar and navigation menu there. I’m aware that these components are not really “re-usable” taking into consideration that they are actually only used on the layout. But for now placing them there might be useful just to demonstrate what type of components we might want to put there.
Container presentation pattern in Blazor
This one is extremely important in my opinion because it helps us to reduce the number of calls to the back end API and keep it clean when it comes to which components are actually allowed to change the state of the data. In this pattern we have a parent component, also called a container, and one or more child components, also called presentation components. The important principle here is that only the container component is responsible for working with data. Presentation component shouldn’t care about the data. They simply get it as a parameter and display it in the UI. If the data changes based on a user’s input, the presentation component should just notify the container about the change and the container component should decide what to do.
The report details feature in the demo app is an example for this scenario. The repo details component acts as the container. Hence, this is where we use our data retrieval service to retrieve the needed data. Chunks of the retrieved data is passed to the repo branches components and repo issues component as parameters. These two components act as presentation components as they won’t interact with the data service at all.
One drawback here is that these presentation components can’t be routed components. So we can’t simply navigate to the, as they need data from their parent to work. That’s why this pattern is surely not something we should aim for every scenario where we have parent and child components.
That’s it for now. These architectural principles proved to be efficient till now. At least for me. My work on the demo app will continue since I want to cover a lot more common scenarios like component communication. But I thing that this architectural approach to Blazor could actually be useful for scalable Blazor applications.
How useful was this post?
Click on a star to rate it!
Average rating / 5. Vote count: