Coding the Integration of Multiple Blazor Apps

Blazor and Telerik

In this article, I will demonstrate how to make three Blazor applications work seamlessly on the same subdomain for the user. Here are the requirements for the application (this application is available for evaluation at https://blazor.jsmotta.com):

This solution’s requirement is the integration of three Telerik UI for Blazor applications in the same subdomain with user transparency.

To meet the requirements of integrating three Blazor applications within the same subdomain (blazor.jsmotta.com, app1.blazor.jsmotta.com, and app2.blazor.jsmotta.com) seamlessly for the user, as well as ensuring that login occurs in the main application (blazor.jsmotta.com) and a token is shared with the other instances, and guaranteeing that each instance runs in a distinct IIS application pool, the following guidelines are necessary:

  • Subdomains and Redirection: The three Blazor applications must be configured to respond to the specified subdomains (blazor.jsmotta.com, app1.blazor.jsmotta.com, and app2.blazor.jsmotta.com). Any request made to these subdomains should be transparently redirected to the corresponding instance of the Blazor application.
  • Single Sign-On (SSO): The system must implement a Single Sign-On (SSO) mechanism in the main application (blazor.jsmotta.com). The user logs in once to this application and obtains an authentication token valid for all Blazor applications within the subdomain. This token must be securely and transparently shared with the other Blazor instances.
  • IIS application pool isolation: Each instance of the Blazor applications (blazor.jsmotta.com, app1.blazor.jsmotta.com, and app2.blazor.jsmotta.com) must be deployed in a separate and isolated IIS application pool. It ensures that the performance and availability of one application do not affect the others. Isolation also helps prevent configuration and resource conflicts.
  • Monitoring and scaling: A continuous monitoring system should be configured to detect performance, security, or availability issues. An automatic scaling mechanism should also be implemented to handle traffic spikes, ensuring a consistent user experience.

With these guidelines, the three Blazor applications can work harmoniously within the same subdomain, ensuring a seamless user experience and meeting the system’s isolation and security requirements for proper functioning.

Hands-on

Let’s begin by creating the Telerik UI for Blazor applications. Use the Visual Studio -> Extensions -> Telerik -> Telerik UI for Blazor -> Create New Telerik Project.

Follow the instructions and choose the .NET and templates.

We will have the flexibility to mix Server and WebAssembly projects. Here’s how we structure the projects in this sample.

Project structure

We are in the process of developing a C# connector library to facilitate connection and token sharing.

To configure the TelerikBlazorAppMain, you should modify the Program.cs file to utilize the HubConnector as follows:

builder.Services.AddSingleton<HubConnector.Hub>();

On MainLayout.razor on Shared directory, add links for the App1 and App2:

new DrawerItem() { Text = "App1", Icon = SvgIcon.Cart, Url = "/goapp/1" },
new DrawerItem() { Text = "App2", Icon = SvgIcon.Cart, Url = "/goapp/2" },

On the project directory Pages, create a razor page named GoApp.razor with this code:

@page "/goapp/{Id}"
@inject NavigationManager NavigationManager
@inject HubConnector.Hub HubConnector;
@code
{
    [Parameter] public string? Id { get; set; }

    protected override void OnInitialized()
    {
        var appBase = Id ?? "";

        HubConnector.GoApp(appBase, NavigationManager);
    }
}

The “Id” parameter redirects to the destination within the GoApp method. Please note that in this sample, the token is not accurate, making this a suitable location to implement and pass a token for authorization.

In the other project samples, namely TelerikBlazorApp1.Client and TelerikBlazorApp2.Client, you should include the HubConnector service in the Program.cs:

builder.Services.AddSingleton<HubConnector.Hub>();

In the TelerikBlazorApp1 project on NavaMenu.razor, this method is invoked as follows:

new MenuItem()
{
    Text = "Dashboard",
    Url = HubConnector.Url(0),
},
new MenuItem()
{
    Text = "App2",
    Url = HubConnector.Url(2),
},

The primary project in this sample is called the Dashboard, or when the ID equals zero (0).

Within the TelerikBlazorApp2 project, this method is invoked in the following manner:

<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
    <div class="container">
        <NavLink class="navbar-brand" [email protected](0)>Dashboard</NavLink>
        <NavLink class="navbar-brand" [email protected](1)>App1</NavLink>
    </div>
</nav>

The HubConnector

The connector library is a shared component between all projects with a common token sharing for authorization.

Below is the code for Hub.cs:

using Microsoft.AspNetCore.Components;

namespace HubConnector
{
    public class Hub
    {
        const string PBaseSystem = "blazor.jsmotta.com";    

        public void GoApp(string appBase, NavigationManager navigationManager)
        {
            if (appBase != "0" &&
                appBase != "1" &&
                appBase != "2")
            {
                throw new Exception("Id not exists!");
            }        

            var options = new NavigationOptions()
            {
                ForceLoad = false,
                HistoryEntryState = navigationManager.Uri,
                ReplaceHistoryEntry = true
            };        

            string appUrl;
            if (appBase.Equals("0"))
            {
                appUrl = $"https://{PBaseSystem}";
                navigationManager.NavigateTo(appUrl, options);
                return;
            }

            appUrl = $"https://app{appBase}.{PBaseSystem}";

            navigationManager.NavigateTo($"{appUrl}/?token={EncryptedToken()}", options);
        }

        public string Url(int appBase)
        {
            return appBase.ToString().Equals("0") ? $"https://{PBaseSystem}" : $"https://app{appBase}.{PBaseSystem}";
        }

        public string EncryptedToken()
        {
            // Create Fake Token
            return "afkLkasjOwelKAo41Asdiqwkl231sdJL23u";
        }
    }
}

The GoApp() and Url() methods can incorporate token-based authentication. This sample primarily aims to showcase the seamless integration of three Telerik UI for Blazor applications operating within the same subdomain, blazor.jsmotta.com. In this sample, the token is transmitted to the URL.

Finally, you should add the code below to the Program.cs of the Main project and on the *.Server projects to run on IIS. Note that they must run in distinct application pools.

builder.Services.Configure<IISOptions>(options =>
{
    options.ForwardClientCertificate = false;
});

To configure OutOfProcess mode for IIS, you should include the following code snippet within the PropertyGroup section of your .csproj files (Main and *.Server):

<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>

Navigating on the Sample

This solution is working on https://blazor.jsmotta.com, and the source code is available on GitHub: https://github.com/jssmotta/TelerikMultiBlazorIntegration23. Below, we have a YouTube video demonstrating the navigation.

Conclusion

In this post, I’m excited to share an alternative approach for running Blazor applications in separate instances within the same subdomain context. While there are several ways to handle multiple Blazor WebAssembly applications on the Internet, I decided to explore the world of Terlik UI for Blazor.

Other questions should be considered when implementing a solution like this: What will be the monitoring system to detect performance, security, and availability issues?

If you’d like to explore this implementation further or have a friendly chat about it, feel free to connect with me on LinkedIn. I’m always here to discuss and learn together!


Similar Articles