Blazor: Easily switch between client side and server side execution

Blazor as part of ASP.Net Core 3.0 will be shipping in approximately a month. As a generally available release Blazor is supported with server side execution. Even though client side execution is possible, it will remain in a preview state for at least the remainder of the year. Even if the intent for your project is to target server side there are some useful aspects to host your project in wasm on the client. Notably, the ability to use the browser development tools to understand just what your carefully crafted css is actually doing is priceless. If you are going to target the wasm deployment of your project it is still useful to change to server side for debugging at this point in time.

The source code for this project is available on BitBucket at https://bitbucket.org/MarkStegaOHI/blazor-cse-sse/src/master/. This post will just highlight the key aspects of making the switch easy. It is probably best to clone the repository and follow along using Visual Studio 2019 16.3.0 Preview 3.0 and ASP.Net Core 3.0 Preview 9. The project will be updated to ASP.Net Core 3.0 when it is released.

Solution configurations

There are four configurations in the solution. Using the Visual Studio configuration manager you can choose between debug and release and also between client side & server side execution. The key differences in each configuration is the definition of either ClientSideExecution or ServerSideExecution and DEBUG or RELEASE defined constants. So making the switch is as simple as choosing the desired project configuration.

Solution projects

The names of the projects may seem a bit odd; Just understand that this project was pared down from a very large project ‘in progress’ and in the large project the names make sense. The solution is architected in an MVVM style. Most of what appears in the demo project is simply the collection of view components in their simplest form.

GeneralComponents

This project is a Net Standard 2.0 Razor Class Library and implements the UI and backing logic. OptimiserComponents contains the usual Blazor suspects of MainLayout.razor, NavMenu.razor, and the _Imports.razor files as well as other useful components. These projects do not change with the server or client side execution.

Optimiser.Blazor

This project is the Blazor stub defined by program.cs & startup.cs with the packages of “Microsoft.AspNetCore.Blazor” and “Microsoft.AspNetCore.Blazor.Build”. It is only invoked for a client side execution, it is totally ignored for server side execution.

Optimiser.Web

This project is an ASP.Net Core 3.0 server. It uses the defined constants to determine if it is going to host the Blazor project on the server or to simply act as a launch pad for the client side assets. In real life the server presents a REST api for use by the client in either mode. The key to the switch is in startup.cs where the methods Startup and Configure are customized via the defined constants. This project is always the startup project in VS.

Further enhancements

It would be easy to add the development web server and a copy of the wwwroot folder from the Optimiser.Web project to the Optimiser.Blazor project. This would allow a third ‘mode’ of execution which would be to select the Optimiser.Blazor project as startup. But since that is just another client side execution scenario it is only mentioned here as a possibility.

Blazor: Two way data binding workaround with date input

Blazor is an experimental framework that implements many essential elements of a C#/HTML/CSS framework. See https://blazor.net/index.html for details.

Two way data binding is available for many elements but two notable missing elements are the input elements radio buttons and  dates as of Blazor 0.5.1. The radio button issue has a clean workaround by jsakamoto in https://dev.to/j_sakamoto/workaround-how-to-two-way-data-binding-of-radio-button-input-with-blazor-spa-v050-31fd. This post offers a workaround for dates.

Start with a definition of the date field in your cshtml file like:

<input type="date" onchange="@SelectedDateChanged" id="scheduleDate"/>

In the code-behind file define SelectedDateChanged and OnAfterRenderAsync as

        protected DateTime pSelectedDate { get; set; }
        protected async void SelectedDateChanged()
        {
            string selectedDateAsString = await JSRuntime.Current.InvokeAsync("customizationJsFunctions.getSelectedDate");
            try
            {
                pSelectedDate = Convert.ToDateTime(selectedDateAsString);
            }
            catch
            {
                pSelectedDate = DateTime.Now;
            }
            StateHasChanged();
        }


        protected override async Task OnAfterRenderAsync()
        { 
            if (pSelectedDate != DateTime.MinValue)
            {
                string selectedDateAsString = pSelectedDate.ToString("yyyy-MM-dd");

                await JSRuntime.Current.InvokeAsync("customizationJsFunctions.setSelectedDate", selectedDateAsString);
            }
        }

As you can see there are two calls to JSInterop. Define the following script:

    <script>
        window.customizationJsFunctions = {
            getSelectedDate: function () {
                return document.getElementById("scheduleDate").value;
            },
            setSelectedDate: function (selectedDate) {
                document.getElementById("scheduleDate").value = selectedDate;
                return "OK";
            }
        };
    </script>

And with this you have the equivalent functionality of data binding with the input date element.

Silverlight 5.0 and https Extended Validation

I’ve set up a web application for a client and ran into a problem with https Extended Validation. The site design called for use of extended validation in order to provide an extra layer of comfort for the end users. I spun up the site only to have the following displayed in Chrome and Firefox:


ChromeError

FirefoxError

IE was OK:

IEShoodFail


Not a very successful display of the EV work. Chrome was actually quite helpful with an extended message about a file that was downloaded. So it took some work with the Chrome developer tools to discover that the root of the problem was an image that was being downloaded from Microsoft. If you look at the .aspx or .html page created to host a Silverlight app, the Silverlight plugin has an image that is displayed if Silverlight is not installed (<img src=”https://go.microsoft.com/fwlink/?LinkId=161376″ alt=”Get Microsoft Silverlight” style=”border-style:none”/>). This clearly breaks the EV check as information would come from a non-validated site. The solution is simple. Simply host the image on the web site with the desired EV, ala (<img src=”SLMedallion_ENU.png” alt=”Get Microsoft Silverlight” style=”border-style: none”/>)

Now the browsers show up like this:
ChromeGood
FirefoxGood
IEStillBad

So Chrome, Firefox, & IE do the right thing and have the EV shown as the company name in green (URL mostly redacted).

[EDIT 2015-10-02] When this post was written all three browsers showed an EV failure when an element in the HTML was from a non-EV site (April 2012). Retested on October 2015 with current browser versions and the behavior is now correct across all three browsers when EV succeeds. However, IE shows success when both Firefox & Chrome show extended validation issues in the original test. Given that the image is not actually rendered it isn’t really clear which behavior is correct. <ms>