.NET 5 was released recently, with boatloads of goodies.
Blazor got some attention in this release, and I had some free time to play with it.
There’s good news and bad news…
I wanted to make something that COULD potentially be used for something and ended up with this:
This isn’t to detail how to Blazor, or compare between Server and Webassembly implementations, or performance.
It’s just about File –> New Project and spinning up some basic Use Cases and how that felt.
The initial setup experience is fairly nice.
Projects are scaffolded out with useful yet minimal setup, e.g. Some basic components as a reminder of how to do things, Bootstrap included to reduce requirements on custom styling.
The finished project structure is below, and much of it was there to begin with. I just added some files.
Currently, there’s no hot reloading for Blazor Server :(
There is dotnet watch
which watches and rebuilds on change, but it’s essentially doing a rebuild, so it’s a bit slow.
It also seems to be a bit flakey, missing/skipping changes, but that could be configuration and I didn’t explore too much.
For my simple project, the build/rebuild cycle in VS isn’t too bad, but I can imagine in large, slow-to-build projects that this would be unacceptable.
VS gives up when I rename a .razor
file, requiring a “turn it off and back on again”.
This also happens every time I add a code-behind file for razor. (This may have been fixed in VS 16.8.2)
The CSS intellisense is a bit out of date (could be fixable, I haven’t dug) along with some of the built in components.InputText
is an input
set to text along with extra defaults and config, but it’s intellisense doesn’t support placeholder
, BUT you can just put it there and it’ll work correctly.
Bootstrap is included by default, which can take a lot of fuss out of the first version or a spike.
Sharing CSS can probably be done a few ways, but I went with the Sass @import
directive.
MyComponent.razor
can have a MyComponent.razor.css
and any styles in there are scoped to the component.
Is this CSS Modules? I’m not sure.
SASS compilation is easily supported by things like
WebCompiler and
Delegate.SassBuilder, anything that hooks in and compiles to CSS before Blazor gets involved.
I went with Delegate.SassBuilder
as it’s a nuget package that doesn’t require IDE setup.
sassc.exe
inDelegate.SassBuilder
didn’t support colour transparency or sass functions and requires updating :/
CSS also needed additional setup out of the box.
In _Host.cshtml
which manages the main html skeleton, we need <link href="MyProject.styles.css" rel="stylesheet">
to pull in those scoped modules.
The modules also need to be set to content, which can be done in csproj using blob patterns:
<ItemGroup>
<None Remove="Pages\*.razor.css" />
</ItemGroup>
<ItemGroup>
<Content Include="Pages\*.razor.css" />
</ItemGroup>
I’m not 100% why we need a
None
ANDContent
there…
SASS changes sometimes need a project rebuild as well, but not always…
Databinding is available in Blazor and seems pretty cool.
It’s a bit undiscoverable though.
Below is a form:
<EditForm>
<DataAnnotationsValidator />
<InputText ... />
<ValidationSummary />
</EditForm>
Those “validator” bits are key, and there’s no templates or prompts for that.
Validation is done through attributes on data models, shown below:
I find the Razor side of databinding a bit less intuitive.
Some text input examples:
<!-- This two way binds the input to the model using OnChange (i.e. only sets when unfocussed), nothing fancy -->
<InputText @bind-value="SomeModelValue" placeholder="Enter some text..." />
<!-- This two way binds the input to the model using OnInput i.e. basically keydown, but also registers keydown to something else -->
<!-- I used this as a debounced search box. OnInput keeps the model up to date, and onkeydown does debouncing with System.Timer -->
<input @bind="@SomeModelValue" @bind:event="oninput" @onkeydown="OnTextChanged" />
There’s also onchange
and @onchange
… I don’t know what the first one is for, but the second one is the one that takes a delegate.
It’s not all niggly annoyances though!
DI is supported in Razor files via @inject <serviceName> name
and can then be used in the markup.
I found it most useful for NavigationManager
which is how you trigger navigations from code.
_imports.cshtml
is where common usings
can live. Data models, injected services, extension methods, etc are good here.InvokeAsync(() => DoThing())
to marshall.@page
directive at the top of the page. No intellisense :(@code {}
blocks in .razor
files OR code-behind with a MyComponent.razor.cs
with a public partial class MyComponent
in it..razor
is top level, with scss, css, and cs all hiding under it.There are many little niggles plus the massive lack of hot-reload, but ultimately it was a successful trek into Blazor.
It’s quite different to my normal web dev, so many of my frustrations were centered on not knowing Razor syntax, or how to bind properly, etc.
Does it offset not having to write Javascript?
It might, time will tell.