Live Chat Icon For mobile
Live Chat Icon

Blazor FAQ - General

Find answers for the most frequently asked questions
Expand All Collapse All

Stored procedures are pieces of reusable code that you can save in a database data dictionary. They help you extract, edit, and remove data from a database without writing the code to do so again and again. It also saves your time, lessens your workload, and increases your productivity.

Follow these steps to use stored procedures in a Blazor application:

  1. Create a new Blazor application and add the Microsoft.EntityFrameworkCore and Microsoft.EntityFrameworkCore.SqlServer NuGet packages using the NuGet package manager.

  2. Create a class named Empclass.cs in the Data folder and define the properties that are already in the database table.
    [Empclass.cs]

    public class EmpClass
    {
       [Key]
       public int Empid { get; set; }
       public string Empname { get; set; }
       public int Salary { get; set; }
    }

  3. Add the virtual property for the DbSet from Empclass to display records in the database under the Data folder.
    [ApplicationDbContext.cs]

    public class ApplicationDbContext : DbContext
    {
       public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
       {}
       public virtual DbSet<EmpClass> DisplayRecords { get; set; }
    }

  4. Connect the SQL Server database to the Blazor application by choosing (View –> Server Explorer). Right-click the Data Connections and choose Add connection in Visual Studio. Add your server name and DB name to connect the database to the Blazor application.

    The database is now connected to the Blazor application.

  5. Add the connection strings configurations to the appsetting.json file.
    [appsetting.json]

    {
      "ConnectionStrings": {
        "Myconnection": "Data Source={{Server_Name}};Initial Catalog={{DataBase_Name}};Integrated Security=True"
      },
      "Logging": {
        // . . .
      },
      "AllowedHosts": "*"
    }

  6. Create an Empservices class in the Services folder and define the FromSqlRaw extension method to execute a stored procedure.
    [Empservices.cs]

    using System.Linq;
    using {{Your_App_Name}}.Data;
    using Microsoft.EntityFrameworkCore;
    public class Empservices
        {
            protected readonly ApplicationDbContext _dbcontext;
     
            public Empservices(ApplicationDbContext _db)
            {
                _dbcontext = _db;
            }
     
            public EmpClass[] GetEmpDetails()
            {
                EmpClass[] empobj;
                // Here "exec Employee" is a stored procedure of SQL Server Database.
                empobj = _dbcontext.DisplayRecords.FromSqlRaw("exec Employee").ToArray();
                return empobj;
            }
        }

  7. Add the DbContext configuration to the Startup.cs file.
    [Startup.cs]

    using Microsoft.EntityFrameworkCore;
    using {{Your_App_Name}}.Services;
    public class Startup
    {
      public void ConfigureServices(IServiceCollection services)
       {
          services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Myconnection")));
          services.AddScoped<Empservices>();
       }
       // . . .
    }

  8. Now call the GetEmpDetails() method in the Index.razor file and the table to display the database records.
    [Index.razor]

    @page "/"
    @using {{Your_App_Name}}.Data
    @using {{Your_App_Name}}.Services
    @inherits OwningComponentBase<Empservices>
     
    <table border="1">
        <tr>
            <th>Empid</th>
            <th>Empname</th>
            <th>Salary</th>
        </tr>
        @foreach(var emp in empdetails)
        {
         <tr>
             <td>@emp.Empid</td>
             <td>@emp.Empname</td>
             <td>@emp.Salary</td>
         </tr>
        }
    </table>
     
    @code {
        EmpClass[] empdetails;
        protected override void OnInitialized()
        {
            // Here Service property is inherited from OwningComponentBase.
            empdetails = Service.GetEmpDetails();
        }
    }

  9. Press Ctrl + F5 to run the application and see the output in the following image.

Permalink

The Dispose method is used to avoid memory leaks and allows proper garbage collection. Implement the IDisposable interface in the component and call the Dispose method. If the framework calls the Dispose method, the component is removed from the UI and unmanaged resources can be released.

The following example demonstrates the disposal of Timer in the counter page.

[Counter.Razor]

@page "/counter"
@using System.Timers
@implements IDisposable

<h1>Counter with Timer disposal</h1>

<p>Current count: @currentCount</p>

@code {
    private int currentCount = 0;
    private Timer timerObj = new(1000);

    protected override void OnInitialized()
    {
        timerObj.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timerObj.Start();
    }

    private void OnTimerCallback()
    {
        InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        timerObj?.Dispose();
    }
}    
Permalink

A progressive web application (PWA) is usually a single-page application (SPA) used to create a Blazor WebAssembly application to work offline. It runs in its own app window and independent of network speed.

Follow these steps to create a Blazor WebAssembly PWA application to work offline.

  1. Create a Blazor WebAssembly application with a progressive web application configuration.

  2. Press Ctrl + F5 to run the application. Users have the option of installing the app.

  3. Once the app is installed, the app appears in its own window without an address bar.

  4. To run the application offline:

    1. Publish the app using this documentation.
    2. Deploy the app to a server that supports HTTPS and access the app in a browser at its secure HTTPS address.
    3. Run the deployed application in the browser and open the browser’s dev tools.
    4. Open the network tab in the browser dev tool and set the throttle setting to offline mode.
    5. Refresh the application. It still loads in offline mode, also.
  5. Refer to this link for more details.

Permalink

To use two-way binding in a Blazor component, add the bind attribute to a field. Two-way data binding pushes the changes to the component, gets the data from the component end, and updates its own data accordingly.

In the following example, we created a Select component and implemented two-way binding to the parent component.

Create a Select component in the Pages folder.

[SelectComponent.razor]

<div>
    <select id="Item" class="form-control-sm" @bind="@ListItem">
        @foreach (var list in SelectList)
        {
            @if (ListItem != null && String.Equals(list, ListItem, StringComparison.OrdinalIgnoreCase))
            {
                <option selected value="@list">@list</option>
            }
            else
            {
                <option value="@list">@list</option>
            }
        }
    </select>
</div>

@code {
    public IEnumerable<string> SelectList = new List<string>()
    {
        "List 1",
        "List 2",
        "List 3",
        "List 4",
        "List 5"
     };

    private string listItem { get; set; }

    [Parameter]
    public string ListItem
    {
        get { return listItem; }
        set {
            if (listItem != value)
            {
                listItem = value;
                if (ListItemChanged.HasDelegate)
                {
                    ListItemChanged.InvokeAsync(value);
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> ListItemChanged { get; set; }
}

Now define the Select component to in the Index.razor page and implement the two-way binding using the @bind attribute.

[Index.razor]

@page "/"

<div>
    <label>Bind Value</label>
    <input type="text" @bind="@Content" @bind:event="oninput" />
    <p>@Content</p>
</div>

<div>
    <SelectComponent @bind-ListItem="@Content" />
</div>

@code {
    [Parameter]
    public string Content { get; set; } = string.Empty;

}

Refer to this link for more details.

Permalink

To apply custom CSS style to a Blazor component, create a custom CSS file in your Razor page with the name of razorpage.css (i.e. Index.razor.css) and add your styles.

[Index.razor.css]

h1 {
        color: red;
        font-style: italic;
        text-shadow: 2px 2px 2px gray;
    }

You can also define the custom CSS styles in the <style> section of Razor pages.

[Index.razor]

@page "/"

<h1>Blazor App</h1>

<style>
h1 {
        color: red;
        font-style: italic;
        text-shadow: 2px 2px 2px gray;
    }
</style>
Permalink

To create a custom validation component in Blazor, follow these code steps:

  1. Create a Blazor Server or WebAssembly application and install the System.ComponentModel.Annotations NuGet package using NuGet Package Manager.

  2. Now, create a new custom validation class in the Pages folder and restrict the user to enter only “Blazor” in the password field.
    [CustomValidatorAttribute.cs]

    using System.ComponentModel.DataAnnotations;
     
    namespace {{Your_App_Name}}.Pages
    {
        public class CustomValidationAttribute : ValidationAttribute
        {
            public string ValidPassword { get; set; }
     
            protected override ValidationResult IsValid(object password, ValidationContext validationContext)
            {
                var content = password.ToString().ToLower();
                if (content.Equals(ValidPassword.ToLower()))
                {
                    return null;
                }
                return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
            }
        }
    }

  3. Use the created custom validator attribute in the Razor component. Provide the error message and valid password properties for validation.
    [Index.razor]

    @page "/"
    @using System.ComponentModel.DataAnnotations
     
    <EditForm style="width:470px;" Model="_login" OnValidSubmit="Submit">
        <DataAnnotationsValidator />
        <div class="form-group row">
            <label for="name" class="col-md-2 col-form-label">Name:</label>
            <div class="col-md-10">
                <InputText id="name" class="form-control" @bind-Value="_login.UserName" />
                <ValidationMessage For="@(() => _login.UserName)" />
            </div>
        </div>
     
        <div class="form-group row">
            <label for="supplier" class="col-md-2 col-form-label">Password:</label>
            <div class="col-md-10">
                <InputText id="supplier" class="form-control" @bind-Value="_login.Password" />
                <ValidationMessage For="@(() => _login.Password)" />
            </div>
        </div>
     
        <div class="row">
            <div class="col-md-12 text-right">
                <button type="submit" class="btn btn-success">Submit</button>
            </div>
        </div>
    </EditForm>
     
    @code {
        private Login _login = new Login();
     
        public void Submit()
        {
            Console.WriteLine($"User name is {_login.UserName} and password is {_login.Password}");
        }
     
        public class Login
        {
            [Required]
            public string UserName { get; set; }
            [Required]
            [CustomValidation(ErrorMessage = "The entered password is wrong ", ValidPassword = "Blazor")]
            public string Password { get; set; }
        }
    }

  4. Refer to the following output image for the custom validator.

    Refer to this link for more details.

Permalink

Using C# conditional preprocessor directives and predefined constants, you can check the Blazor target framework version. For example, if the framework targets .NET 5.0, the code is compiled only in that specified condition. Follow these steps to check the Blazor target framework version.

[Index.razor]

@page "/"

<h1>@blazorVersion</h1>

@code {
    private string blazorVersion { get; set; }

    protected override void OnInitialized()
    {
#if NET5_0
        blazorVersion = "Blazor App version is .NET5.0";
#elif NETCOREAPP3_1
        blazorVersion = "Blazor App version is netcoreapp3.1";
#endif
    }
}

Refer to this link for more details.

Permalink

Calling the StateHasChanged() method in Blazor, you can be notified that the state has been changed and re-render the components to push their changes to the browser using SignalR. The following example demonstrates how the Counter component is pushing the increment count data automatically using the Timer function and updating the UI in the browser by calling the StateHasChanged() method in the InvokeAsync action.

[Counter.razor]

@page "/counter"
@using System.Timers

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;
    private Timer time;

    private void IncrementCount()
    {
        currentCount++;
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            time = new Timer();
            //Set the time interval.
            time.Interval = 1000;
            time.Elapsed += OnTimeInterval;
            time.AutoReset = true;
            // Start the timer.
            time.Enabled = true;
        }
        base.OnAfterRender(firstRender);
    }

    Private async void OnTimeInterval(object sender, ElapsedEventArgs e)
    {
        IncrementCount();
        await InvokeAsync(() => StateHasChanged());
    }

    public void Dispose()
    {
        // While navigating to other components, Dispose method will be called and clean up the Timer function.
        time?.Dispose();
    }
}

Refer to this link for more details.

Permalink

Use HttpContext through the IHttpContextAccessor interface to get the user agent details in a Blazor Server application. The following example demonstrates how to use HttpContent to get the user agent and IP address details by default.
Extend the AddHttpContextAccessor() configuration to the ConfigureServices method in the Startup.cs file.

[Startup.cs]

public void ConfigureServices(IServiceCollection services)
{
    // . . .
    services.AddHttpContextAccessor();
}

[Index.razor]

@page "/"
@using Microsoft.AspNetCore.Http
@inject IHttpContextAccessor httpContextAccessor

<p>UserAgent = @UserAgent</p>
<p>IPAddress = @IPAddress</p>

@code {
    public string UserAgent { get; set; }
    public string IPAddress { get; set; }

    protected override void OnInitialized()
    {
        UserAgent = httpContextAccessor.HttpContext.Request.Headers["User-Agent"];
        IPAddress = httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
    }
}

Refer to this link for more details.

Permalink

In a Blazor Server app, the default RenderMode is ServerPrerendered. When the component is rendering with the ServerPrerendered render mode, the component is initially rendering statically as part of the page.

On executing the first time, it is rendered as an MVC component directly when the page is requested and handled by “_Host” which is specified in “_Host.cshtml”.

@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))

Then the resources are loaded with the blazor.server.js script and start rendering a second time. Then the Razor pages are loaded as a Blazor component.

Note: If you are changing the RenderMode to Server, the lifecycle method executes only once.

Refer to this link for details.

Permalink

Use the System.Timers.Timer class to wait until the user has finished typing in the text field. The onkeyup event triggers for each key press and resets the timer until the last timer raises the OnUserFinish event.

[Index.razor]

@page "/"
@using System.Timers;

<input type="text" @bind-value="dataValue" @bind-value:event="oninput" @onkeyup="@OnValueChange" />
<p>@Content</p>

@code {
    private string dataValue { get; set; }
    private string Content { get; set; }
    private Timer timerObj;

    protected override void OnInitialized()
    {
        timerObj = new Timer(1500);
        timerObj.Elapsed += OnUserFinish;
        timerObj.AutoReset = false;
    }

    private void OnValueChange(KeyboardEventArgs e)
    {
        // remove previous one
        timerObj.Stop();
        // new timer
        timerObj.Start();
    }

    private void OnUserFinish(Object source, ElapsedEventArgs e)
    {
        InvokeAsync(() =>
        {
            Content = $"Typed text: {dataValue}";
            StateHasChanged();
        });
    }
}
Permalink

In the following example, we’ve animated state transitions using CSS in a Blazor app.

When the state is changed, adding and removing the property values for every state transition is animated.

Create a separate reusable component (.razor) in the Pages folder and add the animation.

[Pages/AnimeState.razor]


<div class="container @(IsShown?"spin-in":"fade-out")">
    <span>@(Name??"")</span>
</div>

<style>
    .container{
        display:inline-block;
        width:@width;
        height:@height;
        color:white;
        background-color:blue;
    }

    .fade-out{
       animation: fade @AnimationTime linear forwards;
    }

    .spin-in{
       animation: spin @AnimationTime linear forwards;
    }

    @@keyframes fade {
      0%   {opacity:1;}
      99%  {width:@width; height:@height;}
      100% {width:0px;height:0px; opacity:0;}
    }

    @@keyframes spin {
      0%   {width:0px;height:0px; transform: rotate(0deg);}
      99%  {width:@width; height:@height;}
      100% {width:@width;height:@height;transform: rotate(1440deg);}
    }
</style>

@code {
    string width = "100px";
    string height = "20px";

    [Parameter] public string Name { get; set; }
    [Parameter] public string AnimationTime { get; set; }
    [Parameter] public bool IsShown { get; set; }
}

Add the AnimeState.razor component and define the property value to be animated when the state has been changed.

[Index.razor]

@page "/"

<button class="btn btn-primary" @onclick="OnButtonClick">Switch</button>
<AnimeState Name="Blazor" AnimationTime="2s" IsShown=@isShown />
<span>State transition Animation</span>
@code{
    bool isShown = true;

    private void OnButtonClick() 
    {
        isShown = !isShown;
    }
}
Permalink

By using browser storage in Blazor, we can save and load data within a component. The following example demonstrates that the counter value is updated with a button click and the count value stored in local storage. When you refresh the page, the saved data will load from the browser local storage.

[Index.razor]

@page "/"
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage LocalStorage

@if (isCount)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button class="btn btn-primary" @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

@code {
    private int currentCount;
    private bool isCount;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            isCount = true;
            // Get the count value into browser local storage.
            var countValue = await LocalStorage.GetAsync<int>("countValue");
            // Loaded the browser local storage value to currentCount.
            currentCount = countValue.Success ? countValue.Value : 0;
            StateHasChanged();
        }
    }

    private async Task IncrementCount()
    {
        currentCount++;
        // Set the count value in browser local storage.
        await LocalStorage.SetAsync("countValue", currentCount);
    }
}

Refer to this link for more details.

Permalink

IndexedDB is used for the client-side storage of data and files. Follow these steps to use IndexedDB in Blazor WebAssembly:

  1. Create a Blazor WebAssembly app and install the Reshiru.Blazor.IndexedDB.Framework NuGet package using the NuGet package manager.

  2. Set up the IIndexedDbFactory configuration service in your Program.cs file and set it as scoped.
    [Program.cs]

    using Blazor.IndexedDB.Framework;
    public class Program
    {
       public static async Task Main(string[] args)
       {
               builder.Services.AddScoped<IIndexedDbFactory, IndexedDbFactory>();
         }
    }

  3. Now add the properties inside the class to store and process data in the Data folder.
    [IndexDb.cs]  

    using Blazor.IndexedDB.Framework;
    using Microsoft.JSInterop;
    using System.ComponentModel.DataAnnotations;
     
    namespace {{Your_App_Name}}.Data
    {
        public class IndexDb : IndexedDb
        {
            public IndexDb (IJSRuntime JSRuntime, string name, int version) : base(JSRuntime, name, version) { }
     
         public IndexedSet<Employee> Employees { get; set; }
        }
     
        public class Employee
        {
            [Key]
            public long Id { get; set; }
     
            [Required]
            public string FirstName { get; set; }
     
            [Required]
            public string LastName { get; set; }
        }
    }

  4. Add the namespace for the IndexedDB in _Import.razor file.
    [_Import.razor]

    @using Blazor.IndexedDB.Framework
    @using {{Your_App_Name}}.Data

  5. Add the Razor component to add and store the data using IndexedDB in the Index.razor file.
    [Index.razor]

    @page "/"
    @inject IIndexedDbFactory DbFactory
     
    <h1>Employees</h1>
    @if (employ != null)
    {
        <table class="table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>First name</th>
                    <th>Last name</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var employee in employ)
                {
                    <tr>
                        <td>@employee.Id</td>
                        <td>@employee.FirstName</td>
                        <td>@employee.LastName</td>
                        <td><button @onclick="@(() => DeleteForm(employee))">Delete</button></td>
                    </tr>
                }
            </tbody>
        </table>
    }
     
    <fieldset>
        <legend>Add new person</legend>
        <EditForm Model="@newEmployee" OnValidSubmit="@SaveForm">
            <InputText placeholder="First name" @bind-Value="@newEmployee.FirstName" />
            <InputText placeholder="Last name" @bind-Value="@newEmployee.LastName" />
            <button type="submit">Add</button>
            <p><ValidationSummary /></p>
            <DataAnnotationsValidator />
        </EditForm>
    </fieldset>
     
    @code {
        Employee newEmployee = new Employee();
        List<Employee> employ;
     
        protected async Task OnInitializedAsync()
        {
            using var db = await DbFactory.Create<ExampleDb>();
            employ = db.Employees.ToList();
        }
     
        async Task SaveForm()
        {
            // Add employee details.
        }
     
        async Task DeleteForm(Employee person)
        {
            // Delete the employee.
        }
    }

  6. Refer to this blog for more details.

Permalink

Follow these steps to add a Blazor WebAssembly project to an existing ASP.NET Core application:

  1. Create a ASP.NET Core application and Blazor WebAssembly application separately.

  2. Install the Microsoft.AspNetCore.Components.WebAssembly.Server NuGet package in the ASP.NET Core application and add the Blazor WebAssembly application project reference to the ASP.NET Core application.
    [AspNetCoreApp.csproj]

    <Project Sdk="Microsoft.NET.Sdk.Web">
       <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0" />
      </ItemGroup>
     
      <ItemGroup>
        <ProjectReference Include="..\BlazorWasmApp\BlazorWasmApp.csproj" />
      </ItemGroup>
     
    </Project>

  3. Add the following configurations the Startup.cs file in the ASP.NET Core app to include Blazor WebAssembly.
    [Startup.cs]

    public class Startup
    {
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
           if (env.IsDevelopment())
           {
                        app.UseWebAssemblyDebugging();
           }
        
                 app.UseBlazorFrameworkFiles();
          app.UseEndpoints(endpoints =>
          {
              endpoints.MapFallbackToFile("index.html");
                    });
          }
    }

  4. Add inspectUri in the ASP.NET Core app launchSettings.json file.
    [launchSettings.json]

    "profiles": {
        "IIS Express": {
          "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
                },
     
         "AspNetCoreApp": {
          "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
          }
    }

Permalink

Blazor authentication is implemented to determine who a particular user is. Blazor follows the existing ASP.NET Core authentication mechanisms to show a user’s identity.
Follow these steps to implement authentication within Blazor WebAssembly:

  1. Create a Blazor WebAssembly app with individual user account authentication in Visual Studio 2019.

  2. Install the NuGet package named “Microsoft.AspNetCore.Components.WebAssembly.Authentication” using the NuGet package manager.

  3. To support the authenticating service, add the AddOidcAuthentication service configuration to the Program.cs file.
    [Program.cs]

    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    . . .
     
    public class Program
     {
        public static async Task Main(string[] args)
        {
                         builder.Services.AddOidcAuthentication(options =>
          {
            builder.Configuration.Bind("Auth0", options.ProviderOptions);
            options.ProviderOptions.ResponseType = "code";
          });
        }
      }

  4. In wwwroot/appsettings.json file, replace the Authority and Client ID placeholders with the proper values taken from the Auth0 dashboard.
    Note: Use Auth0; it will let you integrate authentication for configuring your application. Refer to this link for how to configure the application.
    [wwwroot/appsetting.json]

    {
      "Auth0": {
        "Authority": "https://<YOUR_AUTH0_DOMAIN>",
        "ClientId": "<YOUR_CLIENT_ID>"
      }
    }

  5. Add the authentication service script reference to the index.html file, which handles the low-level details of the OIDC protocol.
    [index.html]

    <body>
     
        //. . .
     
        <script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js">
        </script>
        
    </body>

  6. Add CascadingAuthenticationState and AuthorizeRouteView to display the page matching the specified route only if the user is authorized. Otherwise, it redirects to the Login page.
    [App.razor]

    <CascadingAuthenticationState>
       
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <Authorizing>
                    <p>Loading...</p>
                </Authorizing>
                <NotAuthorized>
                    <p>You're not authorized to reach this page. You need to log in.</p>
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>       
            <p>Sorry, there's nothing at this address.</p>        
        </NotFound>
    </Router>
    </CascadingAuthenticationState>

  7. Create a Razor component to allow the user to log in to be authenticated in the Shared folder.
    [Shared/LoginControl.razor]

    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
     
    @inject NavigationManager UriHelper
    @inject SignOutSessionStateManager SignOutManager
     
    <AuthorizeView>
        <Authorized>
            Hello, @context.User.Identity.Name!
            <a href="#" @onclick="OnClickEvent">Log out</a>
        </Authorized>
        <NotAuthorized>
            <a href="authentication/login">Log in</a>
        </NotAuthorized>
    </AuthorizeView>
     
    @code{
        private async Task OnClickEvent(MouseEventArgs args)
        {
            await SignOutManager.SetSignOutState();
            UriHelper.NavigateTo("authentication/logout");
        }
    }

  8. Reference the LoginControl page in the MainLayout.razor page.
    [MainLayout.razor]

    <div class="main">
            <div class="top-row px-4 auth">
                <LoginControl />
                <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
            </div>
     
            <div class="content px-4">
                @Body
            </div>
        </div>

  9. Create an Authentication.razor component in the Pages folder to authenticate the user when logging in and out of the app.
    [Pages/Authentication.razor]

    @page "/authentication/{action}"
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @using Microsoft.Extensions.Configuration
     
    @inject NavigationManager UriHelper
    @inject IConfiguration Config
     
    <RemoteAuthenticatorView Action="@Action">
        <LogOut>
            @{
                var authority = (string)Config["Auth0:Authority"];
                var clientId = (string)Config["Auth0:ClientId"];
     
                UriHelper.NavigateTo($"{authority}/v2/logout?client_id={clientId}");
            }
        </LogOut>
    </RemoteAuthenticatorView>
     
    @code{
        [Parameter]
        public string Action { get; set; }
    }

  10. Now display the authorized content when the app is authorized. If the app is not authorized, display the “Not Authorized” message to the user.
    [Index.razor]

    @page "/"
     
    <AuthorizeView>
        <Authorized>
            <h1>Hello, @context.User.Identity.Name !</h1>
     
            <p>Welcome to your new app.</p>
        </Authorized>
        <NotAuthorized>
            <p>Not Authorized</p>
        </NotAuthorized>
    </AuthorizeView>

  11. Press Ctrl + F5 to run the application and click Log in in the header to authenticate the user.

  12. Refer to this documentation for more details.

Permalink

Blazor allows JavaScript isolation in standard JavaScript modules. JavaScript isolation provides the following benefits:

  • JavaScript code is allowed to load only specified components.
  • Imported JavaScript does not affect any global namespace.
  • Library and component consumers are not required to import the related JavaScript.
Follow these steps to implement JavaScript isolation in Blazor:

  1. Create an export JavaScript function in the wwwroot/script folder.
    [isolationScript.js]

    export function jsIsolation(value) {
        console.log(value);
    }

  2. Import the JavaScript function using the IJSRuntime.InvokeAsync method in Blazor and call the JavaScript method on button click event.
    [Index.razor]

    @page "/"
    @inject IJSRuntime JSRuntime
     
    Enter text:<input @bind="content" />
    <button class="btn btn-primary" @onclick="OnClickButton">Click</button>
     
    @code {
        private string content { get; set; }
     
        private async void OnClickButton()
        {
            var jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./script/isolationScript.js"); 
            await jsModule.InvokeVoidAsync("jsIsolation", content);
        }
    }
    The JavaScript code file loads only during a button click event. It will not load again and again for each button click. 

    Refer to this documentation for more details.

Permalink

Blazor authentication is implemented to determine who a particular user is. Blazor follows the existing ASP.NET Core authentication mechanisms to show a user’s identity.
Follow these steps to implement authentication with OpenID Connect in Blazor:

  1. Create Blazor application

    Create a Blazor Server app and install a NuGet package named “Microsoft.AspNetCore.Authentication.OpenIdConnect” using the NuGet package manager.

  2. Add OIDC and authentication configuration

    Add OpenID Connect and cookie authentication service configuration to the Blazor Server app in the Startup.cs file.
    [Startup.cs]

    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.IdentityModel.Tokens;
     
    namespace BlazorServerApp
    {
        public class Startup
        {
          . . .
          . . .
          public void ConfigureServices(IServiceCollection services)
          {
                      . . .
                      . . .
                      services.AddAuthentication(opt =>
                {
                    opt.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    opt.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                }).AddCookie().AddOpenIdConnect("oidc", options =>
                    {
                    options.Authority = "https://demo.identityserver.io/";
                    options.ClientId = "interactive.confidential.short";
                    options.ClientSecret = "secret";
                    options.ResponseType = "code";
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.UseTokenLifetime = false;
                    options.Scope.Add("openid");
                    options.Scope.Add("profile");
                    options.TokenValidationParameters = new TokenValidationParameters{ NameClaimType = "name" };
     
                    options.Events = new OpenIdConnectEvents
                    {
                        OnAccessDenied = context =>
                        {
                            context.HandleResponse();
                            context.Response.Redirect("/");
                            return Task.CompletedTask;
                        }
                    };
                });
             }
     
             public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
             {
                 . . .
                 . . .
                                app.UseAuthentication();
                 app.UseAuthorization();
                         }
               }
     }

  3. Add AuthorizeRouteView to the App.razor file

    Add AuthorizeRouteView to display the page matching the specified route only if the user is authorized.
    [App.razor]

    @inject NavigationManager UriHelper
     
    <CascadingAuthenticationState>
        <Router AppAssembly="@typeof(Program).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        @{
                            var returnUrl = UriHelper.ToBaseRelativePath(UriHelper.Uri);
                            UriHelper.NavigateTo($"login?redirectUri={returnUrl}", forceLoad: true);
                        }
                    </NotAuthorized>
                    <Authorizing>
                        Loading...
                    </Authorizing>
                </AuthorizeRouteView>
            </Found>
            <NotFound>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p>Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    </CascadingAuthenticationState>

  4. Add buttons

    Add Log out and Log in buttons to authorize the user in the header section.
    [MainLayout.razor]

    <div class="top-row px-4">
                <AuthorizeView>
                    <Authorized>
                        <form method="get" action="logout">
                            <button type="submit" class="nav-link btn btn-link">Log out</button>
                        </form>
                    </Authorized>
                    <NotAuthorized>
                        <a href="login?redirectUri=/">Log in</a>
                    </NotAuthorized>
                </AuthorizeView>
                <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
            </div>

  5. Redirect requests to log in or log out users

    Create Razor pages for login (Login.cshtml.cs) and logout (Logout.cshtml.cs) redirection requests to IdentityServer for authorization under the Pages folder.
    [Login.cshtml.cs]

    using Microsoft.AspNetCore.Authentication;
     
    namespace BlazorServerApp.Pages
    {
        public class LoginModel : PageModel
        {
            public async Task OnGet(string redirectUri)
            {
                await HttpContext.ChallengeAsync("oidc", new AuthenticationProperties { RedirectUri = redirectUri });
            }
        }
    }
    [Logout.cshtml.cs]
    using Microsoft.AspNetCore.Authentication;
     
    namespace BlazorServerApp.Pages
    {
        public class LogoutModel : PageModel
        {
            public async Task<IActionResult> OnGetAsync()
            {
                await HttpContext.SignOutAsync();
                return Redirect("/");
            }
        }
    }

  6. Show authorized content in Razor component

    Following is the code to display the authorized content when the app is authorized. If the app is not authorized, it displays the “Not Authorized” message to the user.
    [Index.razor]

    @page "/"
     
    <AuthorizeView>
        <Authorized>
            <h1>Hello, @context.User.Identity.Name !</h1>
     
            <p>Welcome to your new app.</p>
        </Authorized>
        <NotAuthorized>
            <p>Not Authorized</p>
        </NotAuthorized>
    </AuthorizeView>

  7. Run the application

    Press Ctrl + F5 to run the application and click Log in in the header to authenticate the user.

    You can download the reference sample on GitHub.

Permalink

Cookies are created by the application and passed to the user’s web browser when the user submits the request. The web browser passes the cookie back to the application to indicate that the user is authenticated. When the user logs out, the cookie is removed.
Follow these steps to set a cookie and read that cookie with authentication in Blazor.

  1. Configure the cookie authentication services in the Startup.cs file.
    [Startup.cs]

    public class Startup
    {
       . . .
       . . .
     
       public void ConfigureServices(IServiceCollection services)
       {
          . . .
          . . .
          services.AddAuthentication("Cookies").AddCookie();
       }
       public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
       {
          . . .
          . . .
          app.UseAuthentication();
          app.UseAuthorization();
     
          app.UseEndpoints(endpoints =>
          {
             endpoints.MapControllers();
             . . .
             . . .
          });
       } 
    }

  2. Now, add a controller page to set the cookie to the browser and redirect the URL.
    [CookieController.cs]

    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Threading.Tasks;
     
    namespace blazorcookie
    {
        [Route("/[controller]")]
        [ApiController]
        public class CookieController : ControllerBase
        {
            [HttpPost]
            public async Task<ActionResult> Login([FromForm] string name)
            {
                ClaimsIdentity claimsIdentity = new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier, name)
                }, "auth");
                ClaimsPrincipal claims = new ClaimsPrincipal(claimsIdentity);
                await HttpContext.SignInAsync(claims);
                return Redirect("/");
            }
        }
    }

  3. To use the authorized view, configure the CascadingAuthenticationState component in the App.razor file. This will let you check the authentication state inside the Blazor application.
    [ App.razor ]

    <CascadingAuthenticationState>
        <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
            . . .
            . . .
            . . .
        </Router>
    </CascadingAuthenticationState>

  4. Use form action to call the cookie controller to set the cookie and have it read by AuthorizeView user name.
    [Index.razor]

    @page "/"
     
    <AuthorizeView>
        <Authorized>
            <h1>Hello @context.User.Claims.First().Value</h1>
        </Authorized>
    </AuthorizeView>
     
    <form action="cookie" method="post">
        <input type="text" name="name" />
        <input type="submit" />
    </form>

  5. Run the application and submit the form request. You will find an authentication cookie with the scheme “Cookies,” which was specified in the ConfigureServices() method of the Startup class.


    Refer to this blog post for more details and download the sample on GitHub.

Permalink

Blazor Server is a stateful application framework that maintains a connection to the server. Its state will occur in the server memory known as circuit. We can preserve the state in Blazor server-side three ways:

  • Server-side storage
  • URL
  • Browser storage

The following example demonstrates how to preserve the state in Blazor server-side using browser storage.

Install the Blazored.SessionStorage NuGet package in the NuGet package manager to store the session data in Blazor. Add the Blazored SessionStorage configuration to the Blazor Server app.

[Startup.cs]

using Blazored.SessionStorage;
public class Startup
{
        public void ConfigureServices(IServiceCollection services)
    {
       //. . .
       services.AddBlazoredSessionStorage();
    }
}

[Index.razor]

@page "/"
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

<button class="btn btn-primary" @onclick="Clear">Clear Session</button>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await sessionStorage.SetItemAsync("ID", "2021");
        await sessionStorage.SetItemAsync("Name", "John Smith");
    }
    public async void Clear()
    {
        // This will clear the session data.
        await sessionStorage.ClearAsync();
    }
}

Refer to this documentation for details.

Permalink

The background long-running tasks are cancelled by using the CancellationToken object in Blazor. If an application downloads the data to render in view and then you navigate to another page, the CancellationToken cancels the download by using the cancel() method. Call the cancel() method by using the Dispose() method to cancel the background running task.

In the following example, the background running task in the FetchData.razor component is cancelled when a user navigates to other pages in Blazor.
[FetchData.razor]

@using System.Threading
@implements IDisposable

// . . .
@code {
    private CancellationTokenSource cancellationToken = new CancellationTokenSource();

    protected override async Task OnInitializedAsync()
    {
        forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json", cancellationToken.Token);
    }

    public void Dispose()
    {
        cancellationToken?.Cancel();
        cancellationToken?.Dispose();
    }
    // . . .
}

Refer to this documentation for more details.

Permalink

Blazor CSS isolation is a process that occurs at build time. By using CSS isolation, you can use CSS files or specific components in your app only and not globally. The CSS selectors are rewritten by Blazor to match markup rendered by the component. These rewritten CSS files are loaded as static assets in the {{Your_App_Name}}.styles.css.
The static file name is referenced inside the tag of the host file.
[_Host.cshtml] / [index.html]

<head>
    // . . .
    <link href="{{Your_App_Name}}.styles.css" rel="stylesheet" />
</head>
Follow these steps to enable CSS isolation for a Blazor application.

  1. Create a Blazor Server or WebAssembly application.

  2. To enable CSS isolation, create a razor.css file matching the .razor file for the component in the same folder.
    For example, if your component is named “Isolate.razor,” create a file alongside the component named “Isolate.razor.css.” The Isolate.razor.css file is placed in the same folder as the Isolate.razor component.
    [Pages/Isolate.razor]

    @page "/isolate"
     
    <h1>Hello, World</h1>
    <p>Welcome to your new app</p>
    [Pages/Isolate.razor.css]
    h1 {
        color: blue;
        font-style: italic;
        text-shadow: 2px 2px 2px gray;
    }
    The Isolate.razor.css styles work only for the Isolate.razor component. Refer to this documentation for more details.  

Permalink

LocationChangedis an event handler that will fire when the navigation location has been changed. The following example uses a JavaScript interop function to alert the user when the navigation location changes.

@inject NavigationManager UriHelper
@inject IJSRuntime JSRuntime

@code {
    protected override void OnInitialized()
    {
        UriHelper.LocationChanged += DetectNavigation;
    }

    private void DetectNavigation(object sender, LocationChangedEventArgs e)
    {
        JSRuntime.InvokeVoidAsync("alert", "Navigation event triggered");
    }
}

Refer to this documentation for more details.

Permalink

To redirect users to your login page when their session has expired, create a RedirectLogin Razor component and implement the AuthenticationState to check whether sessions are expired or valid.
Follow these steps to redirect to a login page when sessions time out in Blazor:

  1. Create a RedirectLogin component to redirect users to a login page when their session has expired.
    RedirectLogin.razor]

    @inject NavigationManager UriHelper
     
    @code {
        [CascadingParameter]
        public Task<AuthenticationState> StateAuthenticate { get; set; }
     
        protected override async Task OnInitializedAsync()
        {
            var authenticationState = await StateAuthenticate;
            if (authenticationState?.User?.Identity is null || !authenticationState.User.Identity.IsAuthenticated)
            {
                var returnUri = UriHelper.ToBaseRelativePath(UriHelper.Uri);
                if (string.IsNullOrWhiteSpace(returnUri))
                {
                    UriHelper.NavigateTo("YourLoginPath", true);
                }
                else
                {
                    UriHelper.NavigateTo($"YourLoginPath?returnUrl={returnUri}", true);
                }
            }
        }
    }

  2. Now, initialize the RedirectLogin component in App.razor to identify whether a session is expired or valid.
    [App.razor]

    <Router AppAssembly="@typeof(Program).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        <RedirectLogin />
                    </NotAuthorized>
                    // . . .
                </AuthorizeRouteView>
            </Found>
            // . . .
        </Router>

Permalink

To redirect to the login page when a user is not authenticated in Blazor WebAssembly:

  • Create a login page component.
  • Add the login page component to the NotAuthorized tag.
Follow these steps to redirect to the login page if the user is not authenticated:

  1. Create a login page component for redirection.
    [LoginRedirect.razor]

    @inject NavigationManager UriHelper
    @code {
        protected override void OnInitialized()
        {
            UriHelper.NavigateTo("login");
        }
    }

  2. Now add the LoginRedirect component to the NotAuthorized tag to redirect to the login page if the user is not authorized.
    [App.razor]

    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        <LoginRedirect />
                    </NotAuthorized>
                </AuthorizeRouteView>
            </Found>
            <NotFound>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p>Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    Refer to this documentation for more details.

Permalink

To convert the date and time to a client’s or user’s time zone in Blazor Server, use the JavaScript function to get the current offset time difference from UTC in minutes using the new Date().getTimezoneOffset() method in Blazor using JavaScript Interop. Display the local time by the current offset time difference.
Follow these steps to convert the server time zone to the user’s time zone.

  1. Add the JavaScript function using JS Interop. Get the current offset time from UTC in minutes using the new Date().getTimezoneOffset() method.
    [_Host.razor]

    <body>
         @*Requires render-server mode as "Server" while initializing the component to execute JavaScript in OnInitializedAsync.*@
         <component type="typeof(App)" render-mode="Server" />
          . . . 
          . . . 
     
       <script>
            function GetTimezoneValue() {
                // Returns the time difference in minutes between UTC time and local time.
                return new Date().getTimezoneOffset();
            }
        </script>
    </body >

  2. Now display the UTC time and calculate the user time by using the offset time difference.
    [Index.razor]

    @page "/"
    @inject IJSRuntime JsRuntime
    <h1>Current DateTime</h1>
     
    <p>Now (UTC): @DateTimeOffset.UtcNow.ToString()</p>
    <p>Now (local): @localTime.ToString()</p>
     
    @code {
        private DateTimeOffset localTime;
        private TimeSpan? userTime;
     
        protected override async Task OnInitializedAsync()
        {
            if (userTime == null)
            {
                int timeDiffer = await JsRuntime.InvokeAsync<int>("GetTimezoneValue");
                userTime = TimeSpan.FromMinutes(-timeDiffer);
            }
     
            // Converting to local time using UTC and local time minute difference.
            localTime = DateTimeOffset.UtcNow.ToOffset(userTime.Value);
        }
    }
    Refer to this link for more details.

Permalink

To get the current data and time from client, use the date object (new Date()) in JavaScript using JavaScript Interop. It will return the browser’s date and time. Following is the code to get the current date and time from the client in Blazor WebAssembly.

[Index.razor] 

@page "/" 
@inject IJSRuntime JsRuntime 
 
<p id="date-time"></p> 
 
@code { 
    protected async override Task OnAfterRenderAsync(bool firstRender) 
    { 
        if (firstRender) 
        { 
            await JsRuntime.InvokeVoidAsync("GetDateTime"); 
        } 
    } 
} 

[index.html]

<body>  
      . . .  
      . . .  
 
   <script> 
        function GetDateTime() { 
           // Date object will return browser's date and time by default in JavaScript. 
           document.getElementById("date-time").innerHTML = new Date(); 
        } 
    </script> 
</body >
Permalink

Google reCaptcha is a process that helps to protect websites form spam and abuse. To implement Google reCaptcha in Blazor, refer to the Google reCaptcha script link the WebAssembly app and render the reCaptcha by calling the JavaScript function.
Follow these steps to implement Google reCaptcha in Blazor WebAssembly.

  1. Add the Google reCaptcha renderer function in a separate JavaScript file under the wwwroot folder.
    [googlereCaptcha.js]

    function googleRecaptcha(dotNetObject, selector, sitekeyValue) {
        return grecaptcha.render(selector, {
            'sitekey': sitekeyValue,
            'callback': (response) => { dotNetObject.invokeMethodAsync('CallbackOnSuccess', response); },
            'expired-callback': () => { dotNetObject.invokeMethodAsync('CallbackOnExpired', response); }
        });
    };
     
    function getResponse(response) {
        return grecaptcha.getResponse(response);
    }

  2. Add the reCaptcha script link and reference the reCaptcha.js file source in index.html.
    [index.html]

    <body> 
          . . . 
          . . . 
     
       <script src="googlereCaptcha.js"></script>
       <!-- reCaptcha rendering script -->
       <script src="https://www.google.com/recaptcha/api.js"></script>
    </body >

  3. Now call the rendering reCaptcha function in JavaScript from the Razor page using JavaScript Interop and show the reCaptcha response on button click.
    Note: To start using reCaptcha, you need to generate the API site key for your site. Refer to this link to generate the site key.
    [Index.razor]  

    @page "/"
    @inject IJSRuntime JSRuntime
    @using System.ComponentModel
     
    <h3>Google reCAPTCHA</h3>
     
    <div id="google_recaptcha "></div>
     
    <button class="btn btn-primary" @onclick="ShowResponse">Show Response</button>
     
    <br />
     
    <p>@captchaResponse</p>
     
    @code {
        private string captchaResponse;
     
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await JSRuntime.InvokeAsync<int>("googleRecaptcha", DotNetObjectReference.Create(this), "google_recaptcha ", "your-sitekey");
            }
            await base.OnAfterRenderAsync(firstRender);
        }
     
        [JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
        public void CallbackOnSuccess(string response)
        {
            captchaResponse = response;
        }
     
        [JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
        public void CallbackOnExpired(string response)
        {
            //...
        }
     
     
        private void ShowResponse()
        {
            captchaResponse = $"The response for the Google reCAPTCHA widget: {captchaResponse}";
        }
    }



Permalink

You call a JavaScript function with parameters using JavaScript Interop.

Syntax:

JsRuntime.InvokeVoidAsync("JS method name", "parameters");

Follow this code to call a JavaScript method with parameters in Blazor WebAssembly

[Index.razor]

@page "/"
@inject IJSRuntime JsRuntime

@code {
    protected override async void OnInitialized()
    {
        string content = "JavaScript function called with parameter";
        await JsRuntime.InvokeVoidAsync("jsFunction", content);
    }
}

[index.html]

<body> 
      . . . 
      . . . 

   <script>
        function jsFunction(value) {
            // Parameter value has been passed here.
            console.log(value);
        };
    </script>
</body >

Refer to this documentation for more information.

Permalink

Close a browser window from a page in Blazor WebAssembly using JavaScript Interop with the window.close() method. The window.close() method closes the currently opened window.

In the following example, open a new browser window and close it using the window.close() method with a button onclick event.

[Index.razor]

@page "/"
@inject IJSRuntime JsRuntime

<button @onclick="@(e => OnButtonClick("open"))">Open Window</button>
<button @onclick="@(e => OnButtonClick("close"))">Close Window</button>

@code {        
    private void OnButtonClick(string value)
    {
        JsRuntime.InvokeVoidAsync($"window.{value}");
    }
}
Permalink

Use the HttpClient class with the GetFromJsonAsync() method to read a JSON file in Blazor WebAssembly. Follow these steps to read the JSON file.

Create or load a JSON file under the wwwroot folder. For example, here we have created a simple employee.json file and read its values in a Razor component.

[wwwroot/employee.json]

[{"id": "emp1"}, {"id": "emp2"}, {"id": "emp3"}]

[Index.razor]

@page "/"
@inject HttpClient Http

@if (employees == null)
{
    <p>Loading...</p>
}
else
{
    @foreach (var employee in employees) 
    { 
        <p>Employee ID: @employee.Id</p>
    }
}


@code {
    private Employee[] employees;

    protected override async Task OnInitializedAsync()
    {
        employees = await Http.GetFromJsonAsync<Employee[]>("employee.json");
    }

    public class Employee
    {
        public string Id { get; set; }
    }
}

Refer to this documentation for more details.

Permalink

Get a user agent in Blazor WebAssembly using JavaScript Interop with the navigator.userAgent property.

[Index.razor]

@page "/"
@inject IJSRuntime JsRuntime

<p>@userAgent</p>

@code {

    private string userAgent { get; set; }

    protected override async Task OnInitializedAsync()
    {
        userAgent = await JsRuntime.InvokeAsync<string>("getUserAgent");
        
    }
}

[index.html]

<body> 
      . . . 
      . . . 
   <script>
        window.getUserAgent = () => {
            return navigator.userAgent;
        };
    </script> 
</body > 
Permalink

When we run a Blazor application with a SQL Server localdb for storing authentication data, by following these steps we can implement SQLite in it:

  • Update the NuGet package.
  • Modify the Startup.cs file and connection string.
  • Modify the database migration code.

Updating the NuGet package:
Remove the Microsoft.EntityFrameWorkCore.SqlServer NuGet package from the current package manager and add the Microsoft.EntityFrameWorkCore.Sqlite package.

Modifying the Startup.cs file:
Change the Startup.cs file from options.UseSqlServer to options.UseSqlite.

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.EntityFrameworkCore;
…………………. . .
namespace BlazSqlite
{
    public class Startup
    {
………………… . . 
public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SqlDbContext>(options =>
                options.UseSqlite(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)…………… . }

Modify the connection string in the AppSettings.json file.

DataSource=<yourdbname>.db” (points to your sqlite database file)

Modifying the database migration code:
Modify the database migration code to avoid the errors that would occur after performing the previous steps.
Change the “00000000000000_CreateIdentitySchema.cs” file as follows.

“.HasAnnotation(“SqlServer:ValueGenerationStrategy”, SqlServerValueGenerationStrategy.IdentityColumn)” or “.Annotation(“SqlServer:ValueGenerationStrategy”, SqlServerValueGenerationStrategy.IdentityColumn)”

to “.HasAnnotation(“Sqlite:Autoincrement”, true)” or “.Annotation(“Sqlite:Autoincrement”, true)”

Run the app and start registering a new user for authentication.
Refer to this link to learn how to create a SQL database with a Blazor Server application.
Refer to this link for more information about authentication with SQLite and Blazor.

Permalink

When using Blazor WebAssembly to enforce Office 365 authentication, it is necessary to include the tenant ID and client ID in the appsettings.json file, which can be found under your Azure account.

In Azure AD, a tenant is a dedicated Azure service instance that a company receives and owns after signing up for a Microsoft cloud service such as Azure or Microsoft 365. Each tenant ID is distinct and separate from other tenants.

Procedure outline

  1. Create a new environment in Power Apps and note the web API service root URL.
  2. Register your Azure account.
  3. Create a WebAssembly app using Azure AD for authentication.
  4. Update the callback URL in the app to run the app.
  5. Grant API permissions to access data from the dataverse and modify the code to display the data in the app.

Please refer to this link for a detailed explanation of the implementation of Office 365 authentication.

Permalink

The routing interception concept is sometimes used to restrict user access to some page or link if they did some work or made some changes on a specific page.
In the following code, we use the NavigateTo() method to intercept routing inside the If condition. The routing happens according to the values passed in the condition.

  1. Create the class file [RouteData.cs].

     …………………. ..
    namespace BlazorApp.Data
    {
        public class RouteData
        {
            public string Textfield { get; set; }
        }
    }

  2. Add a new class to [Startup.cs].

    …………….. . 
    public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
                services.AddServerSideBlazor();
                services.AddSingleton<WeatherForecastService>();
                services.AddScoped <Data.RouteData>
             }

  3. Add the following code to the [Index.razor] page.

     @page "/" 
    @inject Data.RouteData RouteData
     <p>Type the text below to allow Home page intercepting</p>
        <textarea @bind="RouteData.Textfield"></textarea>

  4. Check the condition and allow the navigation process in the [NavMenu.razor] page as shown.

    @inject NavigationManager NavigationManager
    @inject Data.RouteData RouteData
    <div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
        <ul class="nav flex-column">
            <li class="nav-item px-3">
                <NavLink class="nav-link" @onclick="Navigate" Match="NavLinkMatch.All">
                    <span class="oi oi-home" aria-hidden="true"></span> Home
                </NavLink>
            </li>
                      ……………………. . .
        </ul>
    </div>
    @code {
        private bool collapseNavMenu = true;
        private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
        private void ToggleNavMenu()
        {
            collapseNavMenu = !collapseNavMenu;
        }
               private void Navigate()
        {
            if (RouteData.Textfield == null)
            NavigationManager.NavigateTo("");
        }
    ………………… . . .

  5. Output

    Home page routing is intercepted when you type text in the text area. When the text area value is null, the app navigates to the home page.

Permalink

We can use NavigationManager, which has a built-in LocationChanged event that will be triggered when the user navigates away from the current page.
In the following code, we use an alert JS function by adding the IJSRuntime to show the user has navigated by overriding the OnInitialized() method through the alert message.

[Index.razor]

@page "/"
@inject NavigationManager nav
@inject IJSRuntime JSRuntime
<h1>Detect Navigation events</h1>
@code {
    protected override void OnInitialized()
    {
        nav.LocationChanged += (o, e) =>
        {
           JSRuntime.InvokeVoidAsync("alert", "User has navigated to other page");
        };  }}

When the user navigates from the home page to the counter page or vice versa, the alert message stating “User has navigated to other page” will be shown.

Permalink

We generally use authentication for specific pages to prevent access by unauthorized users. In the case that we do want a specific page to be accessed by any users, not only authorized users, we will use the anonymous users category.

To make a Blazor page accessible by all users, use [AllowAnonymous] with @attribute code in the _Imports.razor file in your app.

[_Imports.razor]

@attribute [AllowAnonymous]

By doing this users can access the secured page (here we secured the fetch data) without a login.

Permalink

As the Blazor client runs in the browser, both user authorization and authentication for WebAssembly will be completely handled by the back-end API.
The back-end web API must handle the authorization on every API call, and it tells the Blazor app whether the user is authenticated and has resource access. It enables your Blazor app to show the correct context to the user.

  1. Create a Blazor WebAssembly app using Visual Studio 2019 with ASP.NET Core hosting enabled.

  2. Reorganize the folder names according to usage:

    • Sample.Server is renamed to Sample.Api as we are going to use this as our API.
    • Sample.Client is renamed to Sample.WebApp.
    • Sample.Shared is renamed to Sample.Common.

  3. In the Sample.Common folder, create a Models folder, and move the generated WeatherForecast class to this folder and change its namespace to Sample.Models. Add the AuthorizedUser class in the Models folder under the Sample.Shared folder.

    namespace Sample.Common
    {
        public class AuthorizedUser
        {
            public string Name { get; set; }
            public string Roles { get; set; }
        }

  4. Add a new SettingsController file in the Sample.Api folder.

    using Sample.Models;
    using Microsoft.AspNetCore.Mvc;
     
    namespace Sample.Api.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class SettingsController : ControllerBase
        {
            [HttpGet("user")]
            public AuthorizedUser GetUser()
            {
                return new AuthorizedUser();
     
                // User signed in:
                //return new AuthorizedUser { Name = "UserName" };
            }
        }
    }

  5. Prepare your Sample.WebApp

    1. Install the NuGet package Microsoft.AspNetCore.Components.Authorization.

    2. Add the installed package in the _Imports.razor file.

    3. Wrap the <CascadingAuthenticationState> in the App.razor file.

    4.  <CascadingAuthenticationState>
          <Router AppAssembly="@typeof(Program).Assembly">
              ...
          </Router>
      </CascadingAuthenticationState>

    5. Add a Service folder and add a ClientAuthorizationService class in it.

    6. using Sample.Models;
      using Microsoft.AspNetCore.Components;
      using Microsoft.AspNetCore.Components.Authorization;
       
      using System;
      using System.Collections.Generic;
      using System.Net.Http;
      using System.Security.Claims;
      using System.Threading.Tasks;
       
      namespace Sample.WebApp.Services
      {
          public class ClientAuthorizationService : AuthenticationStateProvider
          {
              private const string AuthenticationType = "BackEnd";
              private readonly HttpClient _httpClient;
             public ClientAuthorizationService(HttpClient httpClient)
          {
               if (httpClient == null) throw new ArgumentNullException(nameof(httpClient));
               _httpClient = httpClient;
              }
             public string ApiUriGetAuthorizedUser { get; set; }
       
             public string ApiUriSignIn { get; set; }
       
             public string ApiUriSignOut { get; set; }
       
              public AuthorizedUser AuthorizedUser { get; private set; } = new AuthorizedUser();
           public override async Task<AuthenticationState> GetAuthenticationStateAsync()
         {
        ClaimsPrincipal user;
        if (!string.IsNullOrEmpty(ApiUriGetAuthorizedUser))
        AuthorizedUser = await _httpClient.GetJsonAsync<AuthorizedUser>(ApiUriGetAuthorizedUser);
        if (string.IsNullOrEmpty(AuthorizedUser.Name))     {
                      user = new ClaimsPrincipal();
                 }
        else   {
       var identity = new ClaimsIdentity(CreateClaims(AuthorizedUser), AuthenticationType);
        user = new ClaimsPrincipal(identity);
       }
      return new AuthenticationState(user);
         }
       
        private static IEnumerable<Claim> CreateClaims(AuthorizedUser authorizedUser)
          {      yield return new Claim(ClaimTypes.Name, authorizedUser.Name);
       
            var roles = authorizedUser.Roles?.Split(',') ?? new string[0];
      foreach (var role in roles)
       yield return new Claim(ClaimTypes.Role,role.Trim());
      }
      }
      }

    7. Add the following code in the Program.cs file.

    8. using Microsoft.AspNetCore.Components.Authorization;
      using System.Net.Http;
      ...
       public static async Task Main(string[] args)
      {
          var builder = WebAssemblyHostBuilder.CreateDefault(args);
       
          builder.Services.AddAuthorizationCore();
          builder.Services.AddScoped<ClientAuthorizationService>(CreateAuthorizationService);
          builder.Services.AddScoped<AuthenticationStateProvider>(sp => sp.GetRequiredService<ClientAuthorizationService>());
          builder.Services.AddOptions();
          ...
       private static ClientAuthorizationService CreateAuthorizationService(IServiceProvider serviceProvider){
          var httpClient = serviceProvider.GetRequiredService<HttpClient>();
          var service = new ClientAuthorizationService(httpClient)
          {
              ApiUriGetAuthorizedUser = "api/settings/user",
       
              ApiUriSignIn = "AzureADB2C/Account/SignIn",
              ApiUriSignOut = "AzureADB2C/Account/SignOut",
          };
          return service;
      }

    9. Create a new Razor component SignInDisplay.razor in the shared folder.

    10. @using Sample.WebApp.Services
      @inject ClientAuthorizationService AuthorizationService
      <AuthorizeView>
          <Authorized>
              <div>
                  <span class="form-control">@AuthorizationService.AuthorizedUser.Name</span>
              </div>
              <div>
                  <a class="btn btn-outline-primary" href="@AuthorizationService.ApiUriSignOut">Sign Out</a>
              </div>
          </Authorized>
          <NotAuthorized>
              <div>
                  <a class="btn btn-outline-primary" href="@AuthorizationService.ApiUriSignIn">Sign In</a>
              </div>
          </NotAuthorized>
      </AuthorizeView>

    11. In the Shared/MainLayout page, add the following code.

    12. <div class="top-row px-4 auth">
      <SignInDisplay />
      </div>

  6. Run the app with Sample.Api as the startup file and see the output as follows.

    Since Windows authorization is not yet implemented in the API, If you click the Sign In button, you will be rerouted to a page stating, “Sorry, there’s nothing at this address.” When you change the code in the GetUser() method in the SettingsController to include the name of the user, the app will be shown as follows.

  7. Refer to this link for more information.

Permalink

Role-based authorization is a declarative way of limiting resource access that first appeared in ASP.NET (pre-Core). In order for the user to access certain resources, developers must specify a role that the user belongs to. This is done by using the [Authorize] attribute. Users can have a single role or multiple roles depending on the backing store used. The following procedure explains how to implement role-based authorization.

  1. Create a Blazor WebAssembly app and add the following role service in the Startup class under ConfigureServices.

     public void ConfigureServices(IServiceCollection services)
            {
             ………………….. .
                services.AddDefaultIdentity<IdentityUser>()
                        .AddRoles<IdentityRole>()
                        .AddEntityFrameworkStores<ApplicationDbContext>();}

  2. Add specific roles in your database by overriding the OnModelCreating method of ApplicationDBContext. The User and Admin roles are added in the following code.

     public class ApplicationDbContext : IdentityDbContext
            {
                public ApplicationDbContext(DbContextOptions options) : base(options)
                {
                }
     
                protected override void OnModelCreating(ModelBuilder builder)
                {
                    base.OnModelCreating(builder);
     
                    builder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "User", NormalizedName = "USER", Id = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() });
                    builder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "ADMIN", Id = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() });
                }
            }
    Once the roles are added, generate a migration and apply it to your database.

  3. Add – Migration SeedRoles
    Update-Database
  4. Add users to the roles by updating the action on the Accounts controller. All new users are added to the User role, except for the admin email.
    [AccountsController.cs]

    [HttpPost]
            public async Task<IActionResult> Post([FromBody]RegisterModel model)
            {
                var newUser = new IdentityUser { UserName = model.Email, Email = model.Email };
                var result = await _userManager.CreateAsync(newUser, model.Password);
                if (!result.Succeeded)
                {
                    var errors = result.Errors.Select(x => x.Description);
                    return BadRequest(new RegisterResult { Successful = false, Errors = errors });
                }  
                await _userManager.AddToRoleAsync(newUser, "User");
                if (newUser.Email.StartsWith("admin"))
                {
                    await _userManager.AddToRoleAsync(newUser, "Admin");
                }
                return Ok(new RegisterResult { Successful = true });
            }
  5. Update the Login method in the LoginController.
    Add roles as claims to the JSON web token (JWT) since we are assigning new users to roles at signup, so we need to pass this information to Blazor. Add the following code in the Login method.

  6. Current users can be taken through UserManager, which is used to get their roles.
    public async Task<IActionResult> Login([FromBody] LoginModel login)
    {
    …………….. .
    var user = await _signInManager.UserManager.FindByEmailAsync(login.Email);
                var roles = await _signInManager.UserManager.GetRolesAsync(user);
                var claims = new List<Claim>();
     
                claims.Add(new Claim(ClaimTypes.Name, login.Email));
                       
                 foreach (var role in roles)
                {
                    claims.Add(new Claim(ClaimTypes.Role, role));
                }
    …………….. . .
    }

  7. Add roles in client-side Blazor.
    Once the new users are signed up, we have to get those roles via JWT. To do this, we add the following code in the ParseClaimsFromJwt method, which will take JWT, decode it, extract claims, and return it.

    private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
            {
                var claims = new List<Claim>();
                var payload = jwt.Split('.')[1];
                var jsonBytes = ParseBase64WithoutPadding(payload);
                var keyValuePairs = JsonSerializer.Parse<Dictionary<string, object>>(jsonBytes);
     
                keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
     
                if (roles != null)
                {
                    if (roles.ToString().Trim().StartsWith("["))
                    {
                        var parsedRoles = JsonSerializer.Parse<string[]>(roles.ToString());
     
                        foreach (var parsedRole in parsedRoles)
                        {
                            claims.Add(new Claim(ClaimTypes.Role, parsedRole));
                        }
                    }
                    else
                    {
                        claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
                    }
     
                    keyValuePairs.Remove(ClaimTypes.Role);
                }
     
                claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
     
                return claims;
            }
     
            private byte[] ParseBase64WithoutPadding(string base64)
            {
                switch (base64.Length % 4)
                {
                    case 2: base64 += "=="; break;
                    case 3: base64 += "="; break;
                }
                return Convert.FromBase64String(base64);
            }
    We have to check that the first character is [, indicating it’s a JSON array. If the role claim is present and if the [ character is found, then we have to extract the individual role names from the roles entered. We have to loop these role names and add each as a claim, but if the role is not an array, then it is added as a single role claim.

    To call ParseClaimsFromJwt, we need to update the MarkUserAsAuthenticated method as shown.
    public void MarkUserAsAuthenticated(string token)
            {
                var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
                var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
     
                NotifyAuthenticationStateChanged(authState);
            }

  8. Update the Login method on the AuthService to pass the token rather than the email when calling MarkUserAsAuthenticated.

    public async Task<LoginResult> Login(LoginModel loginModel)
            {
    ……………. .
                var result = await _httpClient.PostJsonAsync<LoginResult>("api/Login", loginModel);
     
                if (result.Successful)
                {
                    await _localStorage.SetItemAsync("authToken", result.Token);
                    ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(result.Token);
                    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", result.Token);
     
                    return result;
                }
     
                return result;
            }

  9. Apply role-based authentication to the API.
    We can allow access to a specific page by an admin user alone through the Authorize attribute as shown.

    namespace BlazorWebAssembly.Server.Controllers
    {
        …………. . .
     
        public class SampleDataController : Controller
        {
             …… . .
            [Authorize(Roles = "Admin")]
            [HttpGet("[action]")]
            public IEnumerable<WeatherForecast> WeatherForecasts()
            {
                var rng = new Random();
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary = Summaries[rng.Next(Summaries.Length)]
                });
            }
        }

  10. Apply role-based authentication in the Blazor page.
    Use the @attribute directive with the [Authorize] attribute in a Blazor page to restrict the user access to specific pages.
    The following code allows the admin user alone to see the fetchdata page.

    @page "/fetchdata"
    @attribute [Authorize(Roles = "Admin")]
    @using BlazorAuthorization.Shared

    When we log in using accounts other than admin, we are unable to load the fetchdata page.

  11. We can also add role-based authorization using the AuthorizeView component in the Index.razor page as shown in the following code.

    <AuthorizeView Roles="User">
        <p>You can only see this if you satisfy the IsUser policy.</p>
    </AuthorizeView>  
    <AuthorizeView Roles="Admin">
        <p>You can only see this if you satisfy the IsAdmin policy.</p>
    </AuthorizeView>

    The output text is shown according to the accounts (admin/user) the user is signed in as.
    Refer to this link for further information about role-based authorization in Blazor WebAssembly.

Permalink

Google authentication is a process by which the user can use their Google accounts to get authorized to access particular data. Follow this procedure to implement Google authentication.

  1. Prerequisites
    • Visual Studio 2019
    • .NET Core 3.1
  2. Create a Blazor Server app by clicking the option on the Create a new project page as shown.

    Set the Authentication Type as Individual Accounts and then click Create.

  3. Go to Tools > NuGet Package Manager > Package Manager Console. Before running the app, we have to perform migration by running the following command in the Package Manager Console.

  4. Update-Database


    To configure a Google API Console project, check whether SSL is enabled by right-clicking the project name, selecting Properties, and selecting the Debug property. We need this URL for configuration.

  5. To create a Google API Console project, follow these steps.

    1. Go to https://developers.google.com/identity/sign-in/web/sign-in#before_you_begin.

    2. Click the Credentials page link under the topic “Create authorization credentials.” Sign in with your Google account and create a project by providing a project name.

    3. Click Create Credentials and select OAuth client ID.

    4. Select the Application type and type the name of the OAuth ID and the redirect URI (localhost URL given to enable SSL in your app) as shown.


    5. Click Create and note your client ID and client secret, which are important for Google authentication.

  6. Install the Google Authentication middleware NuGet package by typing the following command in the Package Manager Console.

  7. Microsoft.AspNetCore.Authentication.Google

  8. Configure the Blazor app to use Google authentication. Right-click the project, select Manage User Secrets, and type the following code.

    {  "Authentication:Google:ClientId": "your Google client ID",
      "Authentication:Google:ClientSecret": "your Google client secret"}

  9. Open the Startup.cs file and add the following code under the ConfigureServices method.

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddAuthentication().AddGoogle(googleOptions =>
                {
                    googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
                    googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
                });

  10. Note the following about this code:

    • The AddGoogle() method is used to configure the authentication process in our application.

    • ClientID and ClientSecret will be read from the secrets.json file by the code.

  11. Add Google authorization to the Blazor page.
    Use the Authorize attribute by using the @ directive in a Blazor page to restrict unauthorized users.

     @page "/fetchdata"
    @attribute [Authorize]
    @using Microsoft.AspNetCore.Authorization
    This code will allow the authorized user alone to see the fetchdata page

  12. Output

    The following image shows the output after running the application.

  13. The following image shows the output after clicking Login to navigate to the authorization page.

    The following image shows the output after the user is authorized using their Google account.

Permalink

Blazor applications are component-based. Blazor components can be used in existing ASP.NET MVC applications. Follow these steps to learn how Blazor components are used in the view page of an MVC application.

  1. Prerequisites:
    • Visual Studio 2019
    • .NET Core 3.1
  2. Create a ASP.NET MVC application.

    Open Visual Studio 2019 and select ASP.NET Core Web App (Model-View-Controller) in the Create a new project page and configure the project as shown.

  3. Add the reference Microsoft.AspNetCore.Components in your dependencies.

  4. Add the Blazor component folder in the View/Shared folder.

    Then add a Razor component inside the Component folder.

  5. Add the following code to the created Component.razor file.

    @using Microsoft.AspNetCore.Components
        <h3>Blazor Component in MVC</h3>
        <button @onclick="Test" class="btn btn-dark">Click to get answer</button>
        <br />
        <div >@Data </div>
    @code {
        [Parameter]  
        public string Data { get; set; } = string.Empty;
           private void Test()
        {
            Data = "Button Clicked";
        }

  6. Add the script reference to the _Layout.cshtml file.

    <base href="~/" />
    <script src="_framework/blazor.server.js"></script>

  7. Create an _Imports.razor file in the Component folder and add the following namespaces to the _Imports.razor file to access component features over your components in the application.

    @using System.Net.Http
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.Forms
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.Web
    @using Microsoft.JSInterop
    @using System.IO
  8. Add services.AddServerSideBlazor() under the ConfigureServices method and add endpoints.MapBlazorHub(); under the Configure method in the Startup.cs file.

    ………………… . .
    namespace blazinmvc
    {
        public class Startup
        {
            ……………… . .
           
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddServerSideBlazor();
                services.AddControllersWithViews();
            }
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {            …………….. . .
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Home}/{action=Index}/{id?}");
                    endpoints.MapBlazorHub();
                });
            }
        }
    }

  9. To render components on the View page, add the following code in the Index.cshtml page in the Views folder.

    @{
        ViewData["Title"] = "Home Page";
    }
    <div >
    @(await Html.RenderComponentAsync<blazinmvc.Views.Shared.Component.Component>(RenderMode.ServerPrerendered,new {  Data= " Hello World " }))
    </div>

  10. Run the application.

    After button click

  11. In the component page, we use the button to change the text defined in the Index.cshtml page inside the component rendering. Clicking the button will change the text shown on the Home page.

Permalink

Since there is no built-in functionality for saving files in Blazor, it is necessary to write the function in JavaScript and then invoke the JavaScript function from C# code in Blazor. In this solution, we have used JavaScript interop for file saving and generation in client-side Blazor.

  1. Create a new JavaScript file, saveFile.js, in the wwwroot folder and add the following code.
    [saveFile.js]

    function saveFile(file, Content) {
    var link = document.createElement('a');
    link.download = name;
    link.href = "data:text/plain;charset=utf-8," + encodeURIComponent(Content)
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    }

  2. Reference the new script file in the index.html page as shown.
    [index.html]

    <body>
        ………………………… . .
        <script src="_framework/blazor.webassembly.js"></script>
        <script src="saveFile.js"></script>
    </body>

  3. Invoke the JavaScript function in a new Razor page.
    [Savefile.razor]

    page "/savefile"
     
    @inject IJSRuntime JSRuntime
     
    <h1>Blazor Save & Generate File</h1><textarea @bind="fileContent"
    style="width:150px;height:100px" />
     
    <button @onclick="SaveFile">SaveFile</button>
     
    <button @onclick="DownloadFile">GenerateFile</button>
     
    @code {
     
        string Content;
     
        string fileContent;
     
        string fileName = "file.txt";
     
        public  void SaveFile()
        {
           Content = fileContent;
        }
        public async void DownloadFile()
        {
            await JSRuntime.InvokeAsync<object>("saveFile",fileName,Content);
       }
    }

  4. Run the app. Save and generate the file in text format.

Permalink

In Blazor, there is no significant difference between using these two attributes. The @bind attribute is a shorthand of the @bind-value attribute and its delegate will trigger the ValueChanged event of the component.
The usage of both the @bind and @bind-value attributes in the following code examples are functionally equivalent.

@bind

<input type="text" @bind="user" />

@bind-value

<input type="text" @bind-value="user" @bind-value:event="onchange"/>
Permalink

We can bind a drop-down list in Blazor WebAssembly using the <select> tag and bind the values to the drop-down list using the @bind attribute in the tag. In the following code example, we have bind a country list along with its country codes. On changing the dropdown list, the codes corresponding to the country will appear below.

[Index.razor]

@page "/"

<p>Select country from the DropDownList</p>

<select class="form-control" @bind="@SelectedCountryID">

        @foreach (var country in CountryList)
        {
            <option value="@country.Code"> @country.Name </option>
        }
        
</select>
<br/>
    <p>@SelectedCountryID</p>

    @code {

        string selectedCountryID;

        string SelectedCountryID
        {
            get => selectedCountryID;
            set {selectedCountryID = value;}
        }

        List<Country> CountryList = new List<Country>() { new Country ("IND", "India"),new Country ("USA", "United States"),new Country ("UK", "United Kingdom")};

        public class Country
        {

            public Country(string code, string name)
            {
                Code = code;
                Name = name;
            }
            public string Code { get; set; }
            public string Name { get; set; }

        }
    }

Note: We also have our Syncfusion Dropdown List component. Please refer to the demo link for more information about our product.

Permalink
  • Blazor WebAssembly can run client-side C# code directly in the browser.
  • The Blazor application, as well as its dependencies and the .NET runtime, are all downloaded to the browser.
  • The application runs on the browser’s UI thread directly. The same method handles both UI notifications and event management.
  • We can re-use code and libraries from the server-side parts of the application while .NET runs on WebAssembly.
Permalink

Using MVC in a Blazor application is not yet possible, but we have an option to migrate an existing ASP.NET MVC application to a Blazor Server application.

Permalink

Browser history can be accessed in Blazor using the window’s popstate event, which is fired when the user navigates the session history. We use the history API to get the history changes in the browser, and we can manually move to a specific page using back(), forward(), go().
When routing takes place in the application or browser, you can use the following code to store the current location:

Window.history.pushState({ prevUrl: window.location.href }, null, newpath)

To retrieve the previous URL, use the following code in your new route:

Window.history.state.prevUrl

Refer to this link for more information about the popstate event.
Refer to this link for more information about the history API.

Permalink

To get the page referrer of where the user came from, follow these steps:

  1. Create a JavaScript function as a separate file in your application (~/wwwroot/interop.js).

    function getPageReferrer()
     {
        return document.referrer;
    }

  2. Add the script reference in the ~/wwwroot/index.html file of the Blazor WebAssembly application.

     <script src="~/interop.js"></script> 

  3. Invoke the JavaScript function using the IJSRuntime service in a Razor page.

     @page "/"
    @inject IJSRuntime JSRuntime
    @code {
    protected override async Task OnInitializedAsync()
    {
    var pageReferrer = await jJSRuntime.InvokeAsync<string>("getPageReferrer");
    }
    }

Permalink

Unit testing is a level of software testing that is used by developers to ensure that the implemented logic meets the requirements and behaves as expected. The following example uses the bUnit testing library for Blazor components to write comprehensive and stable unit test cases. It allows you to write test cases in C# or Razor syntax to verify outcomes with semantic HTML diffing and comparison logic.

Follow the steps below to test Blazor components.

  1. Create a simple Blazor Server/WebAssembly application.

  2. In Visual Studio 2019, right-click on the project solution and select the Add > New Project option.


     Add-New-project-in-VS-2019

  3. Select NUnit Test Project (.NET Core) and click Next button.

    NUnit Test Project

  4. Enter the project name and then click Create button. The created project will be displayed like the following.

    Created Project

  5. Open the NuGet manager for BlazorTest and search with the keyword bunit.web. The result will be displayed as seen in the following screenshot. Select bunit.web and install it.

    Nuget Manager Window

  6. Right-click on BlazorTest project dependencies and add the project reference BlazorServerApp.

  7. Now, write a test case for a Razor component.

    1. Add a Razor component to your Blazor project.

      [Index.razor]

       
      @page "/"
       
      <h3>Hello World</h3>
       
      <button class="btn btn-primary" @onclick="OnButtonClick">Ping Me</button>
       
      @if (IsVisible)
      {
          <h5>Blazor component is clicked.</h5>
      }
       
      @code {
       
          public bool IsVisible { get; set; }
          protected void OnButtonClick()
          {
              IsVisible = true;
          }
      }

    2. Add the following test cases in your created test project file [UnitTest1.cs] to test the Blazor components.

      [UnitTest1.cs]


      using NUnit.Framework;
      using Bunit;
       
      namespace TestProject1
      {
          public class Tests
          {
              [SetUp]
              public void Setup()
              {
              }
       
              [Test]
              public void Test1()
              {
                  // Arrange
                  using var context = new Bunit.TestContext();
       
                  // Act
                  var cut = context.RenderComponent<BlazorServerApp.Pages.Index>();
                  cut.Find("button").Click();
       
                  // Assert
                  cut.Find("h5").MarkupMatches("<h5>Blazor component is clicked.</h5>");
              }
          }
      }

    3. Then select the View > Test Explorer options in Visual Studio 2019 and run the test.

    4. Now you will see the list of test methods. The test run is successful, and the test case passes. You can also alter the test case if it fails.

Refer to “Unit test a Blazor component” for more details and download the sample here.

Permalink

Blazor prerendering is a process where web page elements are built and compiled on the server and static HTML is hosted in WebAssembly (client side). When Razor pages load, components are prerendered at the same time. This process improves page loading by making it faster for SPAs (single page applications), which improves search engine optimization.

Follow the steps below to create a prerender Blazor WebAssembly app.

  1. Create a new Blazor WebAssembly application using the .NET CLI.

    dotnet new blazorwasm -o BlazorPrerendering.Client

  2. Add a new empty ASP.NET Core Web App to host the project.

    dotnet new web -o BlazorPrerendering.Server


    The solution should now look like this.


  3. Now, add the WebAssembly (client side) project reference in the host server project file (BlazorPrerendering.Server.csproj) and also include the NuGet package (Microsoft.AspNetCore.Components.WebAssembly.Server) using NuGet Package Manager.

    [BlazorPrerendering.Server.csproj]

     <Project Sdk="Microsoft.NET.Sdk.Web">
     
     . . .
     . . .
     
      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.1" />
      </ItemGroup>
     
      <ItemGroup>
        <ProjectReference Include="..\BlazorPrerendering.Client\BlazorPrerendering.Client.csproj" />
      </ItemGroup>
     
     
    </Project>

  4. Configure the host in the host server project Startup.cs file.

    [BlazorPrerendering.Server/Startup.cs]

    namespace BlazorPrerendering.Server
    {
        public class Startup
        {
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddRazorPages();
     
                services.AddSingleton<HttpClient>(sp =>
                {
                    // Get the address that the app is currently running at
                    var server = sp.GetRequiredService<IServer>();
                    var addressFeature = server.Features.Get<IServerAddressesFeature>();
                    string baseAddress = addressFeature.Addresses.First();
                    return new HttpClient { BaseAddress = new Uri(baseAddress) };
                });
            }
           
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    // Call UseDeveloperExceptionPage on the app builder in the Development environment. 
                    app.UseDeveloperExceptionPage();
                    app.UseWebAssemblyDebugging();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                    app.UseHsts();
                }
     
                app.UseHttpsRedirection();
                // Call UseBlazorFrameworkFiles on the app builder.
                app.UseBlazorFrameworkFiles();
                app.UseStaticFiles();
                app.UseRouting();
     
                // Change the fallback from the index.html file
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapRazorPages();
                    endpoints.MapControllers();
                    endpoints.MapFallbackToPage("/_Host");
                });
            }
     
        }
    }

  5. Now, you need to create a folder called Pages in the root of the host server project and create a razor page file called _Host.cshtml with the following code.

    [BlazorPrerendering.Server/Pages/_Host.cshtml]

     @page "/"
    @namespace BlazorPrerendering.Server.Pages
    // Need to enable Tag Helpers on the Razor Page
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
     
    <!DOCTYPE html>
    <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>Prerendering client-side Blazor</title>
        <base href="~/" />
        <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
        <link href="css/app.css" rel="stylesheet" />
        <link href="BlazorPrerendering.Client.styles.css" rel="stylesheet" />
     
    </head>
    <body>
        <component type="typeof(BlazorPrerendering.Client.App)" render-mode="WebAssemblyPrerendered" />
     
        <div id="blazor-error-ui">
            An unhandled error has occurred.
            <a href="" class="reload">Reload</a>
            <a class="dismiss">🗙</a>
        </div>
     
        <script src="_framework/blazor.webassembly.js"></script>
    </body>
    </html>

  6. Now, remove the default static wwwroot/index.html file from the Blazor WebAssembly client project.

  7. Delete the following line in Program.cs in the client project.

    [BlazorPrerendering.Client /Program.cs]

     builder.RootComponents.Add<App>("#app"); 


    Now run the application, and you will find the prerendered Blazor WebAssembly app.

Refer to “Prerender and integrate ASP.NET Core Razor components” for more details.

Permalink

In the following example, the cookie consent banner temple will display to notify you to accept cookies. Follow the below steps to create a consent cookie in Blazor.

1. Configure the HttpContextAccessor and CookiePolicyOptions to the startup file to create a consent cookie.

[Startup.cs]

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

public class Startup
    {
       . . .
       . . .
       public void ConfigureServices(IServiceCollection services)
        {
           . . .
                        .   .   .
                         services.Configure<CookiePolicyOptions>(options =>
            {
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            services.AddHttpContextAccessor();
        }
               public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
          . . .
                      .   .   .
                       app.UseCookiePolicy();
         }
           }

2. Now, add the Cookie consent banner template as a Razor component under the Shared folder.

[ConsentCookie.razor]

@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Http

@inject IHttpContextAccessor Http
@inject IJSRuntime JSRuntime


@if (showBanner)
{
    <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
        Consent to set cookies.
        <button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString" @onclick="AcceptMessage">
            Accept Cookie
        </button>
    </div>
}
@code {
    ITrackingConsentFeature consentFeature;
    bool showBanner;
    string cookieString;

    protected override void OnInitialized()
    {
        consentFeature = Http.HttpContext.Features.Get<ITrackingConsentFeature>();
        showBanner = !consentFeature?.CanTrack ?? false;
        cookieString = consentFeature?.CreateConsentCookie();
    }

    private void AcceptMessage()
    {
        // JsInterop call to store the consent cookies.
        JSRuntime.InvokeVoidAsync("CookieFunction.acceptMessage", cookieString);
    }
}

3. Add the JavaScript function in the _Host.cshtml file to store the cookie.

[_Host.cshtml]

<body>
      . . .
      . . .

      <script>
        window.CookieFunction = {
            acceptMessage: function (cookieString) {
                document.cookie = cookieString;
            }
        };    
   </script>
</body>

4. Refer to the cookie consent banner template Razor component in the MainLayout.razor file.

[MainLayout.razor]

<div class="page">
    . . .
    . . .

    <div class="main">
        . . .
        . . .
        <ConsentCookie />

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>

5. Run the application, and you will find the consent cookie banner.

6. Now, click the Accept cookie button to store the cookie in the browser.

Permalink

Blazor doesn’t manipulate the DOM directly at C# side. You cancall the JavaScript method by using JavaScript Interop to get an element by ID or class.

  • The getElementsByClassName() method returns a collection of all elements in the document with the specified class names.
  • The getElementById() method returns a collection of all elements in the document with the specified ID names.

[Index.razor]

@page "/"
@inject IJSRuntime JsRuntime

<h1 id="headingElement">Hello, world!</h1>

<p class="para-element">Welcome to your new app.</p>

@code {
    protected override async void OnAfterRender(bool firstRender)
    {
        await JsRuntime.InvokeVoidAsync("elementId");
    }
}

[_Host.cshtml]

<body>
      . . .
      . . .

      <script>
        function elementId() {
            // Get element with the specified ID name
            var idValue = document.getElementById("headingElement");
            console.log(idValue.innerHTML);
            // Get element with the specified Class name
            var classValue = document.getElementsByClassName("para-element");
            console.log(classValue[0].innerHTML);
        }
    </script>
</body>

Refer to “Call JavaScript functions from .NET methods in ASP.NET Core Blazor” for more details.

Permalink

Configure the logger in the builder in the Program.Main configuration file. Add a package reference for Microsoft.Extensions.Logging.Configuration to the Blazor app’s project file using the NuGet package manager.

Now, add the namespace as Microsoft.Extensions.Logging to Program.cs and add the builder logging configuration. This configuration will prevent the logging info in the browser console.

[Program.cs]

using Microsoft.Extensions.Logging;
. . .
. . .
public class Program
    {
        public static async Task Main(string[] args)
        {
            . . .
            . . .
         Builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));
         
        }
    }

Refer to “Logging configuration” for more details.

Permalink

In Blazor, you can call a JavaScript method using JavaScript interop to scroll the page to the top position.

In the following code, the button event triggers when the button is clicked and scrolls to the page top.

[Index.razor]

@page "/"
@inject IJSRuntime JsRuntime

<div style="background-color:lightgrey;padding:60px 60px 1000px">
    <h2>Blazor App</h2>
    This example demonstrates how to scroll to the top based on the button click event.<br />
    Scroll down and click the button; it scrolls to the top position.
</div>
<div><br />
<button @onclick="OnButtonClick" class="btn btn-primary">Click Button</button>
</div>

@code {

    private async void OnButtonClick()
    {
        await JsRuntime.InvokeVoidAsync("OnScrollEvent");
    }
}

[_Host.cshtml]

<body>
. . .
. . .
<script>
        // When the user clicks the button, the page scrolls to the top
        function OnScrollEvent() {
            document.documentElement.scrollTop = 0;
        }
    </script>
</body>

Permalink

Follow the below steps to convert an existing Blazor Server project into a Blazor WebAssembly project.

Prerequisites:

  • .NET Core 3.1/.NET 5.0
  • Visual Studio 2019

1. Open the existing Blazor Server app project file (.csproj) and add the Blazor WebAssembly SDK and package references.

[BlazorServerApp.csproj]

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
   . . .
   . . .

   <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.4" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.4" PrivateAssets="all" />
    <PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
  </ItemGroup>

</Project>

2. Delete the Startup.cs file configuration in the existing Blazor Server app and add the required WebAssembly configurations to the Program.cs file. Add the following code for WebAssembly configuration.

[Program.cs]

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Threading.Tasks;

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

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

            await builder.Build().RunAsync();
        }
    }
}

3. Now add the below namespace to your converting application in the _Import.razor file.

[_Import.razor]

@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.WebAssembly.Http

4. Delete the _Host.cshtml, Error.cshtml, and Error.cshtm.cs files under the Pages folder and create an index.html file and add the below code snippet under wwwroot/index.html file.

[index.html]

<!DOCTYPE html>
<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>{{Your_Application_Name}}</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
    <link href="{{Your_Application_Name}}.styles.css" rel="stylesheet" />
</head>

<body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

5. Now, run the application. The existing Blazor Server project is now converted into a Blazor WebAssembly project.

Permalink

In Blazor, you can call a JavaScript method using JavaScript interop to copy the input element text to the clipboard.

In the following code, the text entered into the text box will be copied by clicking the button, and it will be displayed in the alert box.

[Index.razor]

@page "/"
@inject IJSRuntime JSRuntime

<div class="form-inline">
    <input id="form-control" type="text" value="Hello World" />
    <button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard">Copy</button>
</div>

@code {
    private async Task CopyTextToClipboard()
    {
        await JSRuntime.InvokeVoidAsync("copyClipboard");
    }
}

[_Host.cshtml]

<body>
. . .
.    .   .
<script>
        function copyClipboard() {
            /* Get the text field */
            var copyText = document.getElementById("form-control");
            /* Select the text field */
            copyText.select();
            /* Copy the text inside the text field */
            document.execCommand("copy");
            /* Alert the copied text */
            alert("Copied the text: " + copyText.value);
        }
    </script>
</body>
Permalink

As opposed to how session cookies work, when opening a page in a new tab or window, a new session occurs with the browsing context. To access the browser sessionStorage in Blazor apps, write custom

code or use a third-party package. The accessed data can be stored in localStorage and sessionStorage. Know that localStorage is scoped to the user’s browser. If the user reloads the page or closes and reopens the browser, the state persists. Session storage is similar to local storage, but data in the session storage will be cleared after the session.

Install the Blazored.SessionStorage Nuget package in the NuGet package manager to store the session data in Blazor. Add the Blazored SessionStorage configuration to the WebAssembly app.

[Program.cs]

using Blazored.SessionStorage;
. . .
. . .

public class Program
    {
        public static async Task Main(string[] args)
        {
            . . .
            . . .

            builder.Services.AddBlazoredSessionStorage();
            
        }
    }

[Index.razor]

@page "/"
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage

<h2>@Name</h2>
<button class="btn btn-primary" @onclick="Clear">Clear Session</button>
@code {
    public string Name;
    protected override async Task OnInitializedAsync()
    {
        await sessionStorage.SetItemAsync("ID", "20019");
        await sessionStorage.SetItemAsync("Name", "John Smith");
        Name = "ID: " + await sessionStorage.GetItemAsync<string>("ID") + "Name : " + await sessionStorage.GetItemAsync<string>("Name");
    }
    public async void Clear()
    {
        //this will clear the session data
        await sessionStorage.ClearAsync();
    }
}

Refer to the GitHub SessionStorage repository for more details.

Permalink

RenderFragment is a delegate that renders a UI segment. So, it does not have an Empty state. It can be null, which is equivalent to empty in the sense that it will produce no rendered output. In the following example, see that the RenderFragments are in a null state or contain a value.

@if (childContent != null) 
{ 
    <p>@childContent</p> 
} 
else 
{ 
    <p>RenderFragment is null</p> 
} 
  
<button class="btn btn-primary" @onclick="OnButtonClick">Click</button> @*RenderFragment is null by default, click the button to update the RenderFragment*@ 
  
@code { 
    private string textContent = "Welcome to your new Blazor app."; 
    private RenderFragment childContent { get; set; } 
     
    private void OnButtonClick() 
    { 
        childContent = BuildRenderTree => BuildRenderTree.AddContent(1, textContent); 
    } 
} 
Permalink

An <iframe> tag is known as an inline frame or frame within a frame. It’s an HTML element that allows documents to be embedded within the current page. The following example illustrates how to embed a URL inside an iframe in the Blazor app.

[Index.razor]

@page "/" 

<iframe width="560" height="315" src="https://blazor.net" frameborder="0" allowfullscreen></iframe>
Permalink

Blazor virtualization is a technique for limiting UI rendering to just the parts that are currently visible. It improves the perceived performance of component rendering using the Blazor framework’s built-in virtualization support with the virtualize component. When you are using a long list-item component with a loop, you can use virtualization for better performance.

Use the Virtualize component when:

  • A set of data items in a loop needs to be rendered.
  • Many items can’t be seen when scrolling.
  • Items to be rendered are equal in size.

Prerequisites:

  • .NET 5.0 and above.
  • Visual Studio 2019 Preview 3 (v16.8) or greater.

Follow the below example to achieve this.

[Index.razor]

@page "/"

<Virtualize Items="employees" Context="employee">
    <tr>
        <td>@employee.EmployeeId</td>
        <td>@employee.Salary</td>
    </tr>
</Virtualize>

@code {

    private List<Employee> employees;

    protected override async Task OnInitializedAsync()
    {
        employees = await EmployeeDetails();
    }

    private async Task<List<Employee>> EmployeeDetails()
    {
        List<Employee> empList = new List<Employee>();

        for (int i = 1; i <= 30; i++)
        {
            var emp = new Employee()
            {
                EmployeeId = $"EmpID - {i}",
                Salary = $"Salary - {i * 100}",
            };

            empList.Add(emp);
        }
        return await Task.FromResult(empList);
    }

    public class Employee
    {
        public string EmployeeId { get; set; }
        public string Salary { get; set; }
    }
}

Refer to “ASP.NET Core Blazor component virtualization” for more details.

Permalink

You can read static or local files by creating HttpClient Get calls. The GetStringAsync method sends a request to the specific URI and returns the response body as a string in an async operation.

@inject HttpClient Http

@code {

    protected override async Task OnInitializedAsync()
    {
        var content = await Http.GetStringAsync(request Uri);

    }
}

Please refer to “HttpClient Class” for more details.

Permalink

RenderFragment is used to render components or content at run time in Blazor. The RenderFragment class allows you to create the required content or component in a dynamic manner at runtime. In the following code example, the content is created at runtime on OnInitialized.

[Index.razor]

@page "/"

@childContent

@code {
    private string textContent = "Welcome to your new Blazor app.";
    private RenderFragment childContent { get; set; }

    private RenderFragment AddContent() => builder =>
    {
        builder.AddContent(1, textContent);
    };

    protected override void OnInitialized()
    {
        childContent = AddContent();
    }
}

Refer to ASP.NET Core Blazor templated components” for more details.

Permalink

To localize the text in a Blazor WebAssembly (client-side) app, follow these steps:

1. Create a Blazor WebAssembly project and add the Microsoft.Extensions.Localization NuGet package using NuGet Package Manager.

2. Add the culture resource files in the Shared/ResourceFiles folder and add a drop-down menu to switch between localized text.

[CultureDropDown.razor]

@using  System.Globalization
@inject IJSRuntime JSRuntime
@inject NavigationManager UrlHelpers

<strong>Culture:</strong>
<select class="form.control" @bind="Culture" style="width: 140px; margin-left: 10px;">
    @foreach (var culture in supportedCultures)
    {
        <option value="@culture">@culture.DisplayName</option>
    }
</select>

@code
{
    CultureInfo[] supportedCultures = new[]
    {
        new CultureInfo("en-US"),
        new CultureInfo("es-ES"),
        new CultureInfo("de")
    };

    CultureInfo Culture
    {
        get => CultureInfo.CurrentCulture;
        set
        {
            if (CultureInfo.CurrentCulture != value)
            {
                var jsInvoke = (IJSInProcessRuntime)JSRuntime;
                jsInvoke.InvokeVoid("blazorCulture.set", value.Name);

                UrlHelpers.NavigateTo(UrlHelpers.Uri, true);
            }
        }
    }
}

[MainLayout.razor]

<div class="top-row px-4">
      <CultureDropDown />
      . . .
 </div>

3. Now add the localization configuration and get the current locale’s culture using JSInterop, which is stored in browser window’s local storage.

[Program.cs]

…
using Microsoft.JSInterop;
using System.Threading.Tasks;

namespace BlazorLocaleWASM
{
  public class Program
  {
     public static async Task Main(string[] args)
     {
        …
        …
                builder.Services.AddLocalization();
                var host = builder.Build();
        var jsInterop = host.Services.GetRequiredService<IJSRuntime>();
        var result = await jsInterop.InvokeAsync<string>("blazorCulture.get");
        if (result != null)
        {
          var culture = new CultureInfo(result);
          CultureInfo.DefaultThreadCurrentCulture = culture;
          CultureInfo.DefaultThreadCurrentUICulture = culture;
        }

        await host.RunAsync();
    }
  }
}

[index.html]

<html>

<head>
    . . .
    . . .
</head>

<body>
  ...
     . . .
<script>
        window.blazorCulture = {
            get: () => window.localStorage['BlazorCulture'],
            set: (value) => window.localStorage['BlazorCulture'] = value
        };
    </script>
</body>

</html>

4. Add the text/content for localization in the Index.razor file.

[Index.Razor]

@page "/"
@using BlazorLocaleWASM.Shared.ResourceFiles
@inject Microsoft.Extensions.Localization.IStringLocalizer<Resource> Locale

<h1>@Locale["Hello world"]</h1>

@Locale["Welcome to your new app"]

<SurveyPrompt Title="How is Blazor working for you?" />

5. By default, Blazor WebAssembly carries minimal globalization resources required to display values, such as dates and currency, in the user’s culture. Applications that must support dynamically changing the culture should configure BlazorWebAssemblyLoadAllGlobalizationData in the project file.

[Project file]

<PropertyGroup>        <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

6. Run the application.

You can download the reference sample here.

Please refer to this link for more information.

Permalink

Follow these steps to create a Blazor WebAssembly (client-side) application using a command-line interface (CLI).

  1. Create a Blazor WebAssembly App in CLI

    Open a command prompt where you want your project to be located and run the following command.

    dotnet new blazorwasm -o BlazorWebAssemblyApp

    Blazor WASM CLI

  2. Navigate to Blazor WebAssembly App

    Run the cd BlazorWebAssemblyApp command to navigate to the BlazorWebAssemblyApp folder.

  3. Run the application.

    The dotnet run command runs the application. See the following output in the default browser.

    wasm cli host

Note: If you have installed multiple SDK versions and need a specific framework version (e.g., net5.0, netcoreapp3.1) project, then add the -f flag to the dotnet new blazorwasm command. Refer here for the available flag options.

Permalink

Follow these steps to create a Blazor Server application using a command-line interface (CLI).

  1. Create a Blazor Server App in CLI

    Open a command prompt where you want your project to be located and run the following command.

    dotnet new blazorserver -o BlazorServerApp

    blazorserver cli

  2. Navigate to Blazor Server App

    Run the cd BlazorServerApp command to navigate to the BlazorServerApp folder.

  3. Run the apllication.

    The dotnet run command runs the application. See the following output in the default browser.

    server-cli-output

Refer to this documentation for more details.

Permalink

Follow the step-by-step procedure below to create a Blazor Server Application in Visual Studio 2019.

  1. Download and install Visual Studio 2019

    Download and install the latest version of Visual Studio 2019 with the ASP.NET and web development workload.

  2. Create a new project

    Open Visual Studio 2019 and click Create a new project . create new project

  3. Select Blazor app from the template

    Select Blazor App from the template list and click the Next button.
    blazor template

  4. Configuring the project

    The project configuration window will pop up. Click the Create button to create a new project with the default project configuration.
    Blazor server configure

  5. Choose Blazor Server App

    Select a target framework based on your requirement, choose the Blazor Server App from the dashboard, and then click Create to create a new Blazor Server application.

    Blazor server template

  6. Blazor Server App structure

    Now the Blazor Server App is created, and the structure look like the following image.
    Server structure

  7. Run the application.

    Press Ctrl + F5 to run the application and find the output in default browser.
    server output

Refer to this link for more details.

Permalink

Follow the step-by-step procedure below to create a Blazor WebAssembly (client-side) application in Visual Studio 2019.

  1. Download and install Visual Studio 2019

    Download and install the latest version of Visual Studio 2019 with the ASP.NET and web development workload.

  2. Create a new project

    Open Visual Studio 2019 and select Create a new project .
    create new project

  3. Select Blazor app from the template

    Select Blazor App from the template list and click the Next. blazor template

  4. Configuring the project

    The project configuration window will pop up. Click Create button to create a new project with the default project configuration.
    Blazor server configure

  5. Choose Blazor WebAssembly App

    Select a target framework based on your requirements, choose Blazor WebAssembly App from the dashboard, and then click Create to create a new Blazor WebAssembly application.

    blazor wasm template

  6. Blazor WebAssembly App structure

    Now the Blazor WebAssemblyApp is created, and the structure look like in the below image.
    wasm structure

  7. Run the application.

    Press ctrl + F5 to run the application and see the below output in default browser.
    wasm output

Refer to this link for more details.

Permalink

Data annotation localization in Blazor server-side and WebAssembly (client-side) apps is achieved by referencing the Resource class localized string. Follow these steps to achieve this:

  1. Add the required localized error messages to the Resource file in the Resource folder.
  2. In the validation attribute, set the ErrorMessageResourceType as typeof(Resource).
  3. Assign the required validation message to the ErrorMessageResourceName property.

[Index.razor]

@page "/"
@using {{ApplicationName}}.Resource
@using System.ComponentModel.DataAnnotations;

<EditForm Model="@_employee" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText id="name" @bind-Value="_employee.Name" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    public class Employee
    {
        [Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(Resource))]
        [StringLength(5, ErrorMessageResourceName = "LengthError", ErrorMessageResourceType = typeof(Resource))]
        public string Name { get; set; }
    }

    private Employee _employee = new Employee();

    private void HandleValidSubmit()
    {
        Console.WriteLine("OnValidSubmit");
    }
}
Permalink

To use jQuery UI components in a Blazor application, follow these steps:

  1. Add jQuery reference to host the page

    Add jQuery and its UI component script and style references in the ~/_Host.cshtml file.

  2. Initialize the jQuery component

    Initialize the jQuery components in the OnAfterRender lifecycle method in your Blazor application by using the JavaScript Interop’s InvokeVoidAsync method.

Refer to the following code samples.

[_Host.cshtml]

….
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="~/script.js"></script>
….

[Index.razor]

@page "/"
@inject IJSRuntime jsRuntime

    <div id="top">
        <a href="#section1">Go Section 1</a>
        <a href="#section2">Go Section 2</a>
        <a href="#section3">Go Section 3</a>
    </div><br>
    <div id="section1">
        In the web project, pagination is a very important part where huge numbers of records are listed from the
        database. In that case, Ajax pagination is a preferable way because it will help to improve the User
        Interface
        of your website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class.
        Pagination class helps to generate the pagination links and get the records from the database using Ajax.In
        the
        web project, pagination is a very important part where huge numbers of records are listed from the database.
        In
        that case, Ajax pagination is a preferable way because it will help to improve the User Interface of your
        website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class. Pagination
        class
        helps to generate the pagination links and get the records from the database using Ajax.
    </div>
    <br /><br />
    <div id="section2">
        <a href="#top">BackToTop</a><br />
        In the web project, pagination is a very important part where huge numbers of records are listed from the
        database. In that case, Ajax pagination is a preferable way because it will help to improve the User
        Interface
        of your website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class.
        Pagination class helps to generate the pagination links and get the records from the database using Ajax.In
        the
        web project, pagination is a very important part where huge numbers of records are listed from the database.
        In
        that case, Ajax pagination is a preferable way because it will help to improve the User Interface of your
        website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class. Pagination
        class
        helps to generate the pagination links and get the records from the database using Ajax.
    </div>
    <br /><br />
    <div id="section3">
        <a href="#top">BackToTop</a><br />
        In the web project, pagination is a very important part where huge numbers of records are listed from the database. In that case, Ajax pagination is a preferable way because it will help to improve the User Interface of your website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class.

Pagination class helps to generate the pagination links and get the records from the database using Ajax. In the
        web project, pagination is a very important part where huge numbers of records are listed from the database.
        In
        that case, Ajax pagination is a preferable way because it will help to improve the User Interface of your website. You'll easily be able to implement the Ajax pagination with our PHP Pagination class. Pagination
        class
        helps to generate the pagination links and get the records from the database using Ajax.
    </div>


@code {
    protected override async void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            await jsRuntime.InvokeVoidAsync("renderjQuery");
        }
        base.OnAfterRender(firstRender);
    }
}

[script.js]

function renderjQuery() {
    $('a[href*=\\#]:not([href=\\#])').on('click', function () {
        var target = $(this.hash);
        target = target.length ? target : $('[name=' + this.hash.substr(1) + ']');
        if (target) {
            $('html,body').animate({
                scrollTop: target.offset().top
            }, 1000);
            return false;
        }
    });
}
Permalink

DateTime.Now.ToShortDateString() and DateTime.Now.ToLongDateString() are methods that return the current culture date format. The string returned by the ToShortDateString and ToLongDateString methods are culture-sensitive. It reflects the pattern defined by the current culture’s date format. You can get the current culture date format by using either of the following methods.

<h2>@DateTime.Now.ToShortDateString()</h2>

or

<h2>@DateTime.Now.ToLongDateString()</h2>

Refer to this link for more details.

Permalink

You can customize the loading text in a Blazor WebAssembly application by editing the tag for target framework version 3.* or the
tag for target framework version 5.* in the index.html page. In the following example, I have customized the loading text while loading.

[index.html] for target framework version 3.*

<body>
    <app>
        <div style="position:absolute; top:30vh; width:100%; text-align:center">
            <h1> Blazor WASM Application</h1>
            <p>The application is loading...</p>
        </div>
    </app>
    . . .
    . . .
</body>

[index.html] for target framework version 5.*

<body>
    <div id="app">
        <div style="position:absolute; top:30vh; width:100%; text-align:center">
            <h1> Blazor WASM Application </h1>
            <p>The application is loading...</p>
        </div>
    </div>
    . . .
    . . .
</body>

Refer to this link for more details.

Permalink

In the following example, LoadingScreen will display a loading message while data is loaded asynchronously. Once the data has been loaded, it replaces the loading message with the actual content.

[LoadingScreen.razor]

@if (contentLoaded)
{
    @ChildContent
}
else
{
     <div style="position:absolute; top:30vh; width:100%; text-align:center">
         <h3>Blazor Server Application</h3>
         <p>The application is loading...</p>
     </div>
}

@code {

    bool contentLoaded;

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(4000);
        contentLoaded = true;
    }
}

Wrap the Router in the LoadingScreen to show the loading screen in the Blazor app.

[App.razor]

<LoadingScreen>
       <Router . . .
                . . .
                . . .
        </Router>
</LoadingScreen>

Please refer to this link for more details.

Permalink

Languages are changed by using localization in the Blazor server-side application. In the following example, the languages are changed from English to French and vice versa by clicking a button.

[Startup.cs]

public class Startup
    {
      . . .
      . . .
              public void ConfigureServices(IServiceCollection services)
        {
            . . .
            services.AddLocalization();
            services.AddLocalization(options => options.ResourcesPath = "Resources");
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
          . . .
                     var localizeOptions = new RequestLocalizationOptions()
                .SetDefaultCulture("en-US")
                .AddSupportedCultures("en-US", "fr-FR")
                .AddSupportedUICultures("en-US", "fr-FR");

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

[Culture.cs]

. . .
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace BlazorAppLocale
{
    [Route("/[controller]")]
    [ApiController]
    public class Culture : ControllerBase
    {
        public ActionResult SetCulture()
        {
            IRequestCultureFeature culture = HttpContext.Features.Get<IRequestCultureFeature>();
            Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(new string[] { "en-US", "fr-FR" }
                    .Where(option => option != culture.RequestCulture.Culture.Name)
                    .FirstOrDefault())));

            return Redirect("/");
        }
    }
}

Add the culture resource files in the Resources/Pages folder.

[Index.razor]

@page "/"
@inject Microsoft.Extensions.Localization.IStringLocalizer<Resource> locale

<h1>@locale["Hello World"]</h1>

@locale["Welcome to your new app."]

<SurveyPrompt Title="How is Blazor working for you?" />

Add the button for changing the language.

[MainLayout.razor]

@inject NavigationManager UriHelper

<div class="top-row px-4"> 
    <button class="btn btn-secondary" @onclick="OnSelected">Change Language</button>
</div>

@code {

    private void OnSelected()
    {
        UriHelper.NavigateTo("Culture", true);
    }
}

You can download the reference sample here.

Please refer to this link for more information.

Permalink

Blazor has a built-in InputFile component from .NET 5.0 that can be used to upload files to the server. You can check the file size in the OnChange event and upload or prevent uploading the files to the server.

[Index.razor]

@page “/”

<h3>File Upload</h3>

<InputFile OnChange=”OnInputFileChange” />

@if (file?.Size < 1000000)
{
    <p>Name: @file.Name</p>
    <p>Size in bytes: @file.Size</p>
    <p>Last modified date: @file.LastModified.DateTime.ToShortDateString()</p>
    <p>Content type (not always supplied by the browser): @file.ContentType</p>
}
else
{
    <p>File size exceeds more than 1MB</p>
}

@code {
    IBrowserFile file;

    void OnInputFileChange(InputFileChangeEventArgs e)
    {
        file = e.File;
        if (e.File.Size < 1000000)
        {
            // Upload files to the server from here
        }
    }
}

Note: Syncfusion offers a feature-rich, easy-to-use File Upload component for Blazor. You can check it out here.

Permalink

Raw HTML can be rendered in Blazor by using MarkupString. You can define the property and pass it to a parameter by using MarkupString.

[Index.razor]

@page "/"

<button class='btn btn-primary' @onclick="OnClickButtonEvent">Counter</button>

@((MarkupString)MyMarkup)

@code { 
    private int count = 0;
    public string MyMarkup;

    public void OnClickButtonEvent()
    {
        ++count;
        MyMarkup = "<div>Current count: <span style=\"color:red\"><b>" + @count + "</b></span></div>";
    }
}
Permalink

Yes, you can host and deploy the blazor server-side application without using Azure but by using AWS or Firebase. Here you can find the steps for hosting the blazor application using AWS.

  • Create the Blazor application 
  • Publish the application using the context menu from the Solution in Solution Explorer in Visual Studio.
  • Click Publish. If there is no error, your application will be published successfully.

Host the application to AWS: https://topswagcode.com/2019/03/05/Hosting-Blazor-Apps/#AWS

Host the application to Firebase: https://dzone.com/articles/hosting-a-blazor-application-on-firebase 

Permalink

You need to add the Response Caching Middleware to the service collection in the startup class.

public void ConfigureServices(IServiceCollection services)
    {
       services.AddResponseCaching();
    }

Then, you can configure the app to use the middleware with the UseResponseCaching extension method, which adds the middleware to the Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseResponseCaching();   
 }

Refer to this thread for more information.

Permalink

The AuthorizeView component supports policy-based authorization. You can use the Policy parameter for policy-based authorization.

<AuthorizeView Policy="IsShowContent">
   <p>You can only see the content if enabled the IsShowContent policy.</p>
</AuthorizeView>

Policy based authorization in Asp.Net Core

The policies are registered in the application Startup classes ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthorization(config =>
        {
            config.AddPolicy("IsShowContent", policy => policy.RequireClaim("IsShowContent", "true"));
        });
    }
Permalink

The Blazor framework includes synchronous and asynchronous lifecycle methods. You can load the full page asynchronously using the below methods,

  • OnInitializedAsync – It is invoked when the component is ready to start and has received its initial parameters from its parent in the render tree.
protected override async Task OnInitializedAsync()
{
await ...
}
  • OnParametersSetAsync – It is invoked when the component is initialized and has received its first set of parameters from its parent component.
protected override async Task OnParametersSetAsync()
{
    await ...
}
  • OnAfterRenderAsync – It is invoked after a component has finished rendering. The firstRender is set to true at first time when the component instance is rendered.
protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await ...
    }
}

Permalink

A Progressive Web Application is a Single Page Application that uses modern browser APIs, and  performs like a desktop app. It can work offline and load instantly, and independent of network speed.

Find the steps for create PWA with blazor app:

  • Create a project from the PWA template
  • Run the application, after creating the app
  • After it launched in the browser, there we have the option for installing the app (PWA)

  • Once installed, the app appears in its own window without an address bar.

Please refer to the documentation link for more details: https://docs.microsoft.com/en-us/aspnet/core/blazor/progressive-web-app?view=aspnetcore-3.1&tabs=visual-studio#create-a-project-from-the-pwa-template

Permalink

You can refresh the Blazor component using the SignalR concept without reloading the page. When using SignalR, saving the changes in one page notifies the changes made to other clients. During the notification process, call the data loading method to reload the changes made to that component without reloading the entire page.

@code{

    public List<Order> Orders { get; set; }
    private HubConnection hubConnection;

    protected override void OnInitialized()
    {
        hubConnection = new HubConnectionBuilder()
        .WithUrl(NavigationManager.ToAbsoluteUri("/chathub"))
        .Build();

        hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            LoadData(); //update the data
            StateHasChanged();//Refresh the component using updated data
        });

       await hubConnection.StartAsync();

    }

    protected async void LoadData()
    {
        //load all the orders from the server.
    }
}

Please refer to the documentation link for more details: https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr-blazor-webassembly?view=aspnetcore-3.1&tabs=visual-studio

Permalink

From .NET 5 Preview 7, Blazor components trim insignificant whitespaces to achieve better performance. This has been implemented as a result of the finding that 40% of the rendering time is consumed by whitespace nodes. If whitespace nodes removal causes unexpected behavior, you can simply enable it by using the @preservewhitespace directive.

@using System.Linq

@preservewhitespace true
 
<ul>
    @foreach (var item in forecasts)
    {
        <li>
            Temperature: @item.TemperatureC
        </li>
    }
</ul>
 
@code {
    private WeatherForecast[] forecasts;
 
    protected override void OnInitialized()
    {
        forecasts = Enumerable.Range(1, 10).Select(x => new WeatherForecast()
        {
            TemperatureC = x
        }).ToArray();
    }
 
    public class WeatherForecast
    {

        public int TemperatureC { get; set; }
 
    }
}

More details about preservewhitespace directive can be found here.

Permalink

You can use the IHttpContextAccessor.HttpContext.Response.HasStarted property to check whether the application is pre-rendering or not.  HasStarted specifies that the response header has been sent to the client. If HasStarted is set to false, it means that the application is still pre-rendering and client connection is not yet established.

Refer to the following code sample.

@using Microsoft.AspNetCore.Http;
 
<button @onclick="@onClick"> Click </button>
 
@code {
    [Inject]
    protected IHttpContextAccessor httpContextAccessor { get; set; }
 
    private void onClick()
    {
        var isPreRendering = !this.httpContextAccessor.HttpContext.Response.HasStarted;
    }
}

The HttpContextAccessor service should be registered by calling the AddHttpContextAccessor method in the Startup.cs.


public class Startup
{
    . . . . .
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();
        services.AddHttpContextAccessor();
    }
    . . . . . 
}

Permalink

Configurations loaded by the Blazor WebAssembly can be accessed by injecting IConfiguration services. Using IConfiguration, the values from wwwroot/appsettings.json and wwwroot/appsettings.{ENVIRONMENT}.json files can be accessed.

wwwroot/appsettings.json

{
  "message":  "Blazor is awesome."   
}

Index.razor

@inject Microsoft.Extensions.Configuration.IConfiguration config
 
<span>@config["message"]</span>

More information about configuration can be found here.

Permalink

You can check whether the current app is Blazor server-side or web assembly using the “IJSInProcessRuntime” interface. In the following example, I have checked whether the app is a web assembly or server side on button click.

<button @onclick="@onClick"> Click </button>

@code {

    [Inject]
    protected IJSRuntime jsRuntime { get; set; }

    private void onClick()
    {
        var isWebAssembly = this.jsRuntime is IJSInProcessRuntime;
    }
}
Permalink

A page is reloaded/refreshed automatically at a specified interval using “NavigationManager” in OnAfterRender() method. Here the NavigateTo(“url”, forceLoad: true) method, is used to force load the browser based on the URI.

@inject NavigationManager uriHelper;

@using System.Threading;

<h1>Hello, world!</h1>

Welcome to your new app.

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            var timer = new Timer(new TimerCallback(_ =>
            {
                uriHelper.NavigateTo(uriHelper.Uri, forceLoad: true);
            }), null, 2000, 2000);
        }
    }
}
Permalink

In Blazor, “StateHasChanged” is used to re-render a page. When changes are detected in components, a page is refreshed. In the following example, a button click increments the count on time interval automatically.

@using System.Threading;

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {

    private int currentCount = 0;

    private void IncrementCount()
    {
        var timer = new Timer(new TimerCallback(_ =>
        {
            currentCount++;
            InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }), null, 1000, 1000);
    }
}
Permalink

Autocomplete enables the user to predict the value. The browser will show options to fill the field when a user starts typing in a field, based on earlier typed values. The code example shows how to enable autocomplete using an input element.

<input id="name" type="text" autocomplete="on" />

If you want to enable the autocomplete from your own database or own set of options, you can go with third party components such as Syncfusion Autocomplete.

Permalink

The HTML “progress” element is used to show the progress. In the following code example, start and stop of progress can be executed on button click.

<progress value="@progressValue" max="100" style="width: 100%">@(progressValue.ToString() + " %")</progress>

<button @onclick="@startProgress">Start</button>

@code {

    private int progressValue { get; set; }

    private void startProgress()
    {
            for (int i = 0; i < 1000; i++)
            {
                this.progressValue = i;
            }
    }
 
}
Permalink

In Blazor server server side application, CircuitOptions detailed error is shown using AddServerSideBlazor().AddCircuitOptions() method. This displays the details of the circuit error in the browser. Find the code snippet to enable the circuit option.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor().AddCircuitOptions(e=> {
        e.DetailedErrors = true;
    });
}
Permalink

You can show the confirmation dialog box before deleting a row in a table. The following code example shows the confirmation dialog box on delete button click.

<button @onclick="@onDelete">Delete</button>

@if (Show)
{
    <div class="modal" tabindex="-1" role="dialog" style="display: @(Show ? "block" : "none")">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Confirm Dialog</h5>
                </div>
                <div class="modal-body">
                    <p>You have unsaved changes in this page. Do you still want to leave this page? </p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" @onclick="@(()=> this.Show=false)">Ok</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="@(()=> this.Show=false)">Close</button>
                </div>
            </div>
        </div>
    </div>
}
@code {

    public bool Show { get; set; } = false;

    private void onDelete()
    {
        this.Show = true;
    }
}
Permalink

To upload files in Blazor applications, install the NuGet package, BlazorInputFile. This package has the component, Blazor input file that is used to upload files.
You also need to include the input file scripts in HTML and add BlazorInputs to the _Imports.razor file.

[_Host.cshtml]

  <script src="_content/BlazorInputFile/inputfile.js"></script>
[index.razor]

@page "/upload"

<h3>Upload</h3>

<InputFile OnChange="HandleFileSelected"  class="btn-primary"/>

@if (file != null)
{
    <p>Name: @file.Name</p>
    <p>Size in bytes: @file.Size</p>
    <p>Last modified date: @file.LastModified.ToShortDateString()</p>
    <p>Content type (not always supplied by the browser): @file.Type</p>
}

@code {
    IFileListEntry file;

    void HandleFileSelected(IFileListEntry[] files)
    {
        file = files.FirstOrDefault();
    }
}

You can handle multiple file uploads by adding multiple attribute to the InputFile component.

@page "/multiupload"

<h3>Multiple File Upload</h3>

<InputFile multiple OnChange="HandleFileSelected"  class="btn-primary"/>

@if (file != null)
{
   <p>Name: @file.Name</p>
   <p>Size in bytes: @file.Size</p>
    <p>Last modified date: @file.LastModified.ToShortDateString()</p>
    <p>Content type (not always supplied by the browser): @file.Type</p>
}

@code {
    IFileListEntry file;

    void HandleFileSelected(IFileListEntry[] files)
    {
        file = files.FirstOrDefault();
    }
}

Please refer to this link here for more information on file uploading in Blazor.

Note: Syncfusion offers feature rich as well as easy to use file upload component. For more information, please check the link.

Permalink

Blazor detects the UI changes in common scenarios like EventCallback (button click, dropdown select, etc.), and refreshes the component. However, there are some situations in an app where a UI refresh needs to be triggered manually to re-render the component. The StateHasChanged method is used to force re-render a component UI.

@using System.Threading;

<h1>@Count</h1>

<button @onclick=@StartCountdown>Start Timer</button>

@functions {
    private int Count { get; set; } = 10;

    void StartCountdown()
    {
        var timer = new Timer(new TimerCallback(_ =>
        {
            if (Count > 0)
            {
                Count--;

                // Note that the following line is necessary because otherwise
                // Blazor would not recognize the state change and not refresh the UI
                InvokeAsync(() =>
                {

                    StateHasChanged();
                });
            }
        }), null, 1000, 1000);
    }
}
Permalink

Share with

Share on twitter
Share on facebook
Share on linkedin

Couldn't find the FAQs you're looking for?

Please submit your question and answer.