I was recently asked to make a spike1 to evaluate the feasibility of implementing a micro frontends architecture with Blazor Server.
I'll tell you right now that it was a failure; but let's go in order, first analyzing the declension of the term failure and the reasons that led me to use it and then try to recapitulate what emerged from this exploration that led me to this conclusion.
I really like the definition he gives Treccani.
Riconoscere l'inutilità dei propri sforzi, l'impossibilità e incapacità di raggiungere gli scopi fissati, rinunciando definitivamente alla lotta, all'azione.
-- Treccani
Which translated, hoping to do it correctly, would be "Recognizing the futility of one's efforts, the impossibility and inability to achieve the set goals, definitely giving up the struggle, action."
I find it particularly proper because it uses the term fixed scopes, and so what are those purposes?
Context matters.
Nothing is done by accident, and this is certainly no exception. The work done is part of a larger context involving the need to migrate a number of ASP.NET MVC 5 applications to ASP.NET Core combined with a desire to make the current architecture more flexible by introducing the concept of modular-programming2.
Without getting around too much, the ultimate goal was to measure the feasibility of "realizing" a micro frontends architecture rendered server-side thanks to Blazor Server.
In this regard on Martin Fowler's blog there is a nice article by Cam Jackson in which an overview of this architecture is given and from which I have translated their definition of micro frontends
An architectural style where independently deliverable frontend applications are composed into a greater whole.
I put realize in quotes since the deployment of the various sites would only ever be done in a unified manner.
Perhaps we would address this issue in a future post.
Not all donuts come out with a hole.
Don't you know what it means?
A clear explanation of what this Italian saying means I found in Clozemaster at point 4.
Anyway, in two words it means that despite failure there is still something left to eat!
Getting straight to the point, the main reason for the failure is related to the inability to give complete autonomy to the teams, for two main distinct reasons.
Homonymy in support for pages and views Razor.
To compose the site each frontends is contained within a Razor class library which also holds the view that is responsible for doing hosting of the Blazor application.
This is made possible by the functionality exposed by the SDK that allows a web app to use Razor views, pages, or layouts from class libraries and, as defined in the official documentation, in case of homonymy, precedence is given to the view, page, layout present in the web app.
In my case I am in a situation like this
where both modules internally make use of layouts contained at the /Pages/Shared/_Layout.cshtml
path.
Here, what would happen in this case is that one of the two teams would be displeased since, if it went well it would see its application rendered inside another layout, in the worst case one part or all of the views would go wrong (e.g., a view tries to enhance a section not declared in the layout).
And we note well that both modules executed independently would behave as expected.
Routes, the basic route that does not want to work.
I have that at least I could not get it to work.
Again, following the principle of autonomy, the desired was to separate the module routes from the container routes, for example within Module A we would find /
or /index
while from the container perspective the routes would be /module-a/
or /module-a/index
.
What I found was a "short blanket," when internal navigation within the module worked, route generation using Anchor Tag Helper did not work (remember that this spike is the result of a migration process), as I used the middleware UsePathBaseMiddleware
for the implementation of the requirement.
This resulted in the generation of links within the module to the outside always adding the /module-a
at the top of the address even as the link should have simply pointed to the container.
Otherwise using middleware I would have been forced to use the module name at the top of all @page
directives.
Conclusions.
Summing up what has been done and reasoning with a cool mind I could say that something good we can still take home, in fact, by not enabling support for Razor pages and views in a RCL3 and avoiding the use of Anchor Tag Helper in the HTML markup that contributes to view rendering we would not run into these problems.
-
A spike is a product development method originating from extreme programming that uses the simplest possible program to explore potential solutions. Source Wikipedia. ↩
-
Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each holds everything necessary to execute only one aspect of the desired functionality. Source Wikipedia. ↩
-
Razor Class libraries (RCLs) were introduced in ASP.NET Core 2.1 as a way to package and distribute UI components to be referenced and consumed within a host application. ↩
Top comments (1)
Coming from a JavaScript background I was surprised to see how straightforward Blazor is to learn if you follow the docs.