Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor WebAssembly Environment Variables

I'm currently working on a .NET Standard 2.1 Blazor WebAssembly application. I try to include or exclude Stylesheets according to an environment variable.

In .NET Core there are usually Environment Tag Helpers like in the following example:

<environment include="Development">
    <link rel="stylesheet" href="css/style.css" type="text/css" />
</environment>

<environment exclude="Development">
    <link rel="stylesheet" href="css/style.min.css" type="text/css" />
</environment>

This works perfectly fine in a Blazor Server application, but doesn't in Blazor WASm, as this is client-side code.

Thus I try to find a good solution to include/exclude Style sheets according to the Environment variable in Blazor WebAssembly.

My current approach is to call a JavaScript helper method from my Blazor WASm Program.cs file with JSInterop and remove the Stylesheets according to the environment variable:

await jsInterop.InvokeVoidAsync("helpers.setup", "Development");

My JavaScript on the client looks like this:

window.helpers = {
    setup: (environment) => {

        if (environment === "Development") {
            // remove production styles
        }

        if (environment !== "Development") {
            // remove development styles
        }
    }
};

The problem with this solution is, I want to put my styles into my header file and group them into a <section> element or something similar - which doesn't work in valid HTML5.

How do you handle your Development/Production environment in Blazor WebAssembly?

How can you exclude or include specific CSS files according to the set environment variable in the project settings (launchsettings.json)?

like image 828
azzurro123 Avatar asked Jul 23 '20 10:07

azzurro123


People also ask

Which is better Blazor server or WebAssembly?

The Blazor Server hosting model offers several benefits: Download size is significantly smaller than a Blazor WebAssembly app, and the app loads much faster. The app takes full advantage of server capabilities, including the use of .NET Core APIs.

Does Blazor WebAssembly use SignalR?

Blazor Server. With the Blazor Server hosting model, the app is executed on the server from within an ASP.NET Core app. UI updates, event handling, and JavaScript calls are handled over a SignalR connection using the WebSockets protocol.

Is Blazor WebAssembly secure?

Blazor WebAssembly apps are secured in the same manner as single-page applications (SPAs). There are several approaches for authenticating users to SPAs, but the most common and comprehensive approach is to use an implementation based on the OAuth 2.0 protocol, such as OpenID Connect (OIDC).

Is Blazor WebAssembly stateless?

Blazor Server is a stateful app framework.


1 Answers

Disclaimer:

This is just something I tried that seems to work. I could not find any documentation supporting doing it this way, nor anything saying not to do it this way. if there is any official documentation please let me know.

The documentation state:

When running an app locally, the environment defaults to Development. When the app is published, the environment defaults to Production.

Further down it does mention how to set the environment via the web.config that gets generated when publishing the file to IIS. There are also references to Use multiple environments in ASP.NET Core. and Host and deploy ASP.NET Core Blazor WebAssembly

However this is what I did.

Looking at the Program.cs file that was generated by the new web assembly project template, the builder is created by WebAssemblyHostBuilder.CreateDefault(args); This must mean that all the default services must already be registered in the services container.

This would include the IWebAssemblyHostEnvironment configuration service.

The next line down builder.RootComponents.Add<App>("app"); adds the App <app></app> root component that is used in the index.html file.

So, Why not try to create a Head <head></head> component and see what happens.

I created a Head razor component and named it Head.razor containing all the html that would usually live between the <head></head> tags.

@using Microsoft.AspNetCore.Components.WebAssembly.Hosting
@inject IWebAssemblyHostEnvironment hostEnv

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />

@*Check the environment value*@
@if (hostEnv.IsDevelopment())
{
    <title>BlazorWasmApp - In Debug</title>
    <link href="css/debug.css" rel="stylesheet" />
}
else
{
    <title>BlazorWasmApp - Not Debug</title>
    <link href="css/live.css" rel="stylesheet" />
}

@code {}

Because it is a component you can inject the IWebAssemblyHostEnvironment and check the .IsDevelopment(),.IsProduction() etc.. extension method values.

I left the original <head> tag as is in the index.html file as the content of the <head>...gets overwritten...</head> seems to be completely overwritten.

<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorWasmApp</title>
    <base href="/" />
    <link href="css/app.css" rel="stylesheet" />
</head>
<body>
    <app>Loading...</app>    
...
...

Also leaving the <head>tag with the reference to the cs/app.css file does not change the way it looks when the app is Loading....

I registered the Head class to the builder.RootComponents collection in the Program class.

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);            
    builder.RootComponents.Add<App>("app");

    //Add the Head to root components
    builder.RootComponents.Add<Head>("head");            
            
    builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });           
    await builder.Build().RunAsync();
}

I added 2 css files to the wwwroot/css folder debug.css and live.css each containing a simple body { background-color:*red or blue* } style.

In the launchSettings.json file, in the profiles section, set the IIS Express : environmentVariables : ASPNETCORE_ENVIRONMENT to "Development" and under the [YourAppName] : environmentVariables : ASPNETCORE_ENVIRONMENT to "Production".

"profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
    },
    "BlazorWasmApp": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Production"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
    }
  }

When launching the app with the IIS Express profile (Development) the background is red and when launching the app with [YourAppName] profile (Production) the background is blue.

When looking at the <head></head> tags using the developer tools the content of the head tag contains the css references according to the environment.

IIS Express:

Red Dev

BlazorWasmApp (my app profile):

Blue Prod

like image 168
CobyC Avatar answered Sep 18 '22 08:09

CobyC