Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run Blazor WASM as Blazor Server-Side

Problem

Blazor WASM could've been easily preferred over Blazor Server-Side without its downsides development-wise. Currently, Blazor WASM doesn't support a full-featured debugging experience and has a very slow startup. This slows down development much more than with Blazor Server-Side. Though I honestly personally think that the debugging experience slows down the development much more than the slow startup.

Proposed Solution

NOTE: I included the "proposed" word in there because I'm not sure about the downsides that this solution can cause, so feel free to comment on my answer below.

The solution is to simply create an additional Blazor Server-Side project then reference the Blazor WASM project to the Blazor Server-Side project. Afterwards, add some tweaks to the Startup and the _Host.cshtml of the Blazor Server-Side to properly use the Blazor WASM razor files and the wwwroot files. See my proposed answer below for a step-by-step explanation for this solution.

In simpler terms, this solution just adds and configures the Blazor Server-Side project without making any changes and any significant code duplication to the Blazor WASM project.

like image 754
DaaWaan Avatar asked Sep 06 '20 17:09

DaaWaan


People also ask

Which is better Blazor server or Blazor 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.

Is Wasm client-side?

Blazor WebAssembly (WASM) apps run client-side in the browser on a WebAssembly-based . NET runtime. The Blazor app, its dependencies, and the . NET runtime are downloaded to the browser.


2 Answers

NOTE: In this example, I'm using Visual Studio 2019 16.7.2 and the version of the templates are currently at 3.1.8

  1. Create a Blazor WASM project. Either the ASP.NET Core Hosted or the Standalone option will work fine but they will have different configurations later that will be discussed. The rest of the options won't have any effect. In this example, I'll go with the ASP.NET Core Hosted to explain later about having API Controllers. Also create the Blazor Server-Side project afterwards.

    Create ASP.NET Core Hosted Blazor WASM Project Create Blazor Server-Side project


  1. As of this moment, your project structure should be similar to the first screenshot below.

    Delete the highlighted items in the Blazor Server-Side project shown in the second screenshot below.

    enter image description hereItems to remove from the Blazor Server-Side project


  1. Reference the Blazor WASM project to the Blazor Server-Side project.

    • ASP.NET Core Hosted - Reference both the BlazorWasm.Client & BlazorWasm.Server project.
    • Standalone - Reference the single Blazor WASM project as is.

  1. Go to the Startup class of the Blazor Server-Side project. In the ConfigureServices(), remove the WeatherForecastService together with the BlazorServer.Data namespace then add a service for the HttpClient to be used by the razor files from the Blazor WASM project.

    services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(sp.GetRequiredService<NavigationManager>().BaseUri) });
    

    NOTE In production, I don't suggest creating an instance of the HttpClient. Use the IHttpClientFactory instead. Visit this article Use IHttpClientFactory to implement resilient HTTP requests.

    For ASP.NET Core WASM Projects

    In the Configure(), map the controllers' endpoints. This will use the controllers in the X.Server/BlazorWasm.Server project.

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        ...
    });
    

  1. Go to the _Host.cshtml in the /Pages folder of the Blazor Server-Side project. Change the reference of the css/site.css to css/app.css since the filenames for the main css file for the Blazor WASM project are different.

    <link href="css/site.css" rel="stylesheet" /> <!-- Previous -->
    <link href="css/app.css" rel="stylesheet" /> <!-- New -->
    

  1. Lastly, change the App in the type attribute of the component tag and refer to the App razor class file in the Blazor WASM project. In this example, the App class is found in the BlazorWasm.Client project:

    <component type="typeof(App)" render-mode="ServerPrerendered" /> <!-- Previous -->
    <component type="typeof(BlazorWasm.Client.App)" render-mode="ServerPrerendered" /> <!-- New -->
    

That's it! When you run the Blazor Server-Side project, it should load without the "Loading ..." text.

  • No changes made to the Blazor WASM project(s) and no significant code duplication made.
  • The only things to change are the references and the launchSettings.json & appsettings.json.
  • As for the configurations in the Startup for the Blazor Server-Side, you can just create extension methods in the Blazor WASM project(s) and use them in the Blazor Server-Side project.

NOTE: I honestly think this is ideally(?) only for debugging during development since the WASM razor files won't fully utilize the capability of a true Blazor Server-Side because it would still use HTTP Requests.

Blazor WASM Project running as Blazor Server-Side


Hoping for feedbacks down below! :DD

like image 66
DaaWaan Avatar answered Oct 10 '22 21:10

DaaWaan


I would suggest an alternate way. There are other drawbacks to referring to WASM project from a server project, but personally I think it is an architecturally inelegant solution.

There are some critical areas where Blazor Server and WASM differ :

  1. Authentication: Blazor server allows you to customize access to specific areas at runtime. In WASM, the authorization happens in one go and the app code is sent in its entirety.
  2. Database is access : Blazor server allows direct access to EF core entities (since the code executes only on the server). In blazor, it is realistically not possible to access any database directly. It is also highly discouraged because you would be sending connection strings to the client. Hence you need to write a separate web API for data access. 3.Settings files : you can have as many settings files in server-side blazor. Client side blazor loads only appsettings.json by default. A special mechanism is required to include multiple .json files.

Therefore, for most applications (and definitely the ones that require database access) you will not be able to share 100% codebase between WASM and Server-side.

Here is what you should do instead:

  1. For the points mentioned above, (auth, but mostly db access), create a data access service dependency (say IDataAccessLayer). One implementation will access the database directly (to be used in server side) The other implementation will access the database through an HttpClient (to be used in blazor WASM).

  2. Now, put your entire app in an RCL. Call it "BlazorAppRCL". This RCL obviously does not have Startup.cs and Program.cs

  3. Create a project for server and client specific db access implementation

  4. Now, you have the following set of projects:

For Server Side: BlazorServer (has only settings + Program.cs + Startup.cs). It refers to the RCL + Server specific implementation of IDataAccessLayer

For hosted WASM: BlazorWebAPI : For database access, it has API to access database BlazorClientDAL : WASM specific implementation of IDataAccessLayer BlazorWASM : Blazor WASM project All three refer to your BlazorAppRCL.

The crux is to use DI/ inversion of control pattern to address the divergence between WASM and Server. This way, you can have a both instances WASM and Server instances with minimal code divergence. Note that the WASM WebAPI can simply use the server side blazor's implementation od IDataAccessLayer as it is. So beyond API related overhead, additional coding is not necessary.

like image 1
Mayur Ekbote Avatar answered Oct 10 '22 22:10

Mayur Ekbote