Friday, 8 March 2019

Blazor Configuration The AspNetCore Way


I've seen a bit of conversation recently about how you can use configuration in a Blazor (WASM) application and some of the implementations seem a bit convoluted, especially when you consider that AspNet Core already handles it...

So, I don't think it is advisable, but if you really want to...

Create new Blazor project

dotnet new blazor -o BlazorIsAwesome

Update to Blazor 0.9

Update your package references to the latest version as the templates still reference old versions and we all know bleeding edge is best, right?

*Currently the latest version is 0.9.0-preview3-19154-02*

Add AspNetCore packages

You will need the standard Asp.Net Core packages for configuration

<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.2.0" />

THIS ALONE IS REASON ENOUGH NOT TO DO THIS - THINK OF THE PAYLOAD

Configure your app

Open up Startup.cs and add some Using statements to bring in the namespaces required.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using System.ComponentModel;

Now we can pull in the configuration to our ConfigureServices method

public void ConfigureServices(IServiceCollection services)
{
var fileProvider = new EmbeddedFileProvider(this.GetType().Assembly);
var configuration = new ConfigurationBuilder()
.AddJsonFile(provider: fileProvider, 
path: "appsettings.json", 
optional: true, 
reloadOnChange: false) 
.Build();
services.AddSingleton<IConfiguration>(configuration);
}

Let's take a look at what that is doing...

We are creating an EmbeddedFileProvider - this comes from the Microsoft.Extensions.FileProviders package - which will give us access to the appsettings.json for our project.

Then we build our configuration using that file provider  and tell it to find the appsettings.json file which is an embedded resource in our Blazor app. 

We say it is optional and not to reload on change - as there's no way an embedded resource is going to change.

Finally we add the configuration to our services collection, so it can be injected into the app wherever it is needed.

An Embedded Appsettings.json

Add a new appsettings.json file to the project - don't put it in wwwroot!

Add some settings - in this case I'm just adding a title:

{ "Title" : "My Blazor App (appsettings.json)" }

You set the appsettings.json as an embedded resource by selecting it, pressing F4 and changing the property "Build Action" to "Embedded resource" 

For the hard-core coders, you can also do this in csproj

<ItemGroup>
  <Content Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
  <EmbeddedResource Include="appsettings.json">
    <CopyToOutputDirectory>Never</CopyToOutputDirectory>
  </EmbeddedResource>
</ItemGroup>

Now Let's Use This Thing

To make use of the configuration we have added, we need to inject an IConfiguration object into the code

I'm going to use Index.cshtml for this:

@page "/"
@using Microsoft.Extensions.Configuration
@inject IConfiguration  configuration

<h1>@configuration["Title"]</h1>

I have added a using statement to bring in the Configuration namespace.
I injected the IConfiguration object from the DI container.
Finally, I grab the "Title" from configuration and place it in an <h1> 





Saturday, 2 March 2019

CSS In Your Razor Component is Broken


The current preview of Razor Components (0.8.0-preview-19104-04) broke the ability to ship content files from a component library. The ASP.NET team will fix it, but in the meantime, what can you do?

You've heard of CSS in JS? 
Let's try CSS in Components.
It's not what it sounds like.

CSS In Components

Instead of shipping a CSS file, just create a CSS component

Here's my Razor Component's CSS

BlazorScrollBarCSS.cshtml
Notice it is a Razor View, not a CSS file.

Now, in my BlazorScrollBar component, I can reference the classes from the CSS component and ship the CSS as part of the library again.

All the consuming project needs to do is place the CSS component somewhere in it's pages, for example, in App.cshtml.


This seems like a reasonable short term solution for supplying CSS with your components, until the problem is resolved.

Additional Benefit

Because the CSS is now encapsulated as a component, we can allow the consuming project more control over whether the CSS is required.

I have a parameter on my BlazorScrollBar component 


...and an if statement in the Component markup


So, the consumer has the choice, they can manually include the CSS by placing the CSS component somewhere in their app, they can have the ScrollBar component include the CSS in it's own markup, or they can choose not to use my CSS.