DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Coding
  3. Languages
  4. Blazor: .NET in the Browser, Part 1

Blazor: .NET in the Browser, Part 1

In Part 1 of this two-part series, we introduce Blazor and demonstrate how to make a quick and simple client-side application.

Federico Tomassetti user avatar by
Federico Tomassetti
·
Sep. 10, 18 · Tutorial
Like (3)
Save
Tweet
Share
11.92K Views

Join the DZone community and get the full member experience.

Join For Free

In this article and tutorial we are going to use Blazor to bring C# in the browser. We are going to talk about what you can do and the things you have to think about when creating a Blazor app.

WebAssembly is a great platform that promises to revolutionize development on the browser. Thanks toWebAssembly, JavaScript is no longer the only language that you can use client-side when developing for the web. It is an exciting platform, which we already talked about in Understand WebAssembly. In this article, we go one step further see how to use a platform that runs on WebAssembly: Blazor.

What is exactly Blazor?

Full-stack web development with C# and WebAssembly

Everything you can do with C#, you can do on Blazor. In addition to that, you can obviously interact with JavaScript code, just as you would expect to do a WebAssembly project.

Technically, Blazor runs on Mono, which is an open-source and cross-platform version of the .NET Framework developed by Xamarin, a company that is now part of Microsoft. So, it does not run on .NET Core. This is technical information that, generally, has little practical consequences, but it may be useful to know in some circumstances. Also, in older browsers, where WebAssembly is not present, Blazor relies on the asm.js sub-set of JavaScript.

The last thing to say in the introduction is that Blazor is still an experimental project, but it is already quite successful: with an official website, a good community and many resources.

Why Blazor?

Why would you want to use C# in place of JavaScript? The usual reason is because you might prefer one language over the other:

  • Better support for what you care about.
  • An old code base to support.
  • A need for a unified code base.

In addition to that, JavaScript is a bit lacking when managing big and complex projects. More than one language was invented for this scope. Probably the most successful is TypeScript, which has the slogan: JavaScript that scales. C# can be an alternative solution, allowing you to use it for the complex parts of the application and leave JavaScript for the UI.

Setting Up Blazor

All you need to use Blazor is .NET Core 2.1.300 SDK or later. If you use Visual Studio, you can also install the Blazor Language Services extension to have Blazor templates available in the IDE. However, it is not required to use Visual Studio. In fact, in this article we are going to use Visual Studio Code.

You might wonder why we are using .NET Core, even though we just said that Blazor relies on Mono. Certainly, Blazor runs on Mono, as you can see inside the dist folder: mono.wasm contains the Mono compiled to WebAssembly, mono.js file contains glue code.

However, the app must also distributed to the user in some way. The default template uses ASP.NET Core and a web server to do it; just like your typical JavaScript app. In theory, you could pack it some other way, like an Electron app, but this is still not supported.

Once you have installed .NET Core you can install the Blazor templates from the command line, if you are not using Visual Studio.

# install the Blazor Templates
dotnet new -i Microsoft.AspNetCore.Blazor.Templates
# create a new Blazor App
dotnet new blazor -o BlazorApp
# run the app, as usual
cd BlazorApp
dotnet run

When creating the Blazor app you should go to the address indicated (usually localhost:5000 or localhost:5001 with TLS) to check that everything is working. If you see an image like the following one, everything is ok.

Common Errors

Instead, if you see a blank page, something is wrong. The most probable error is that you have installed an older version of .NET Core SDK. Remember that, even if you have the wrong version of .NET Core SDK, you can still successfully install the templates and create the app. The installation will succeed but the app will not work. So, check that you are using the correct version of the .NET Core SDK.

At the moment, if you go to the official .NET website, you get the right version by default for Windows and macOS, but you might still get an older version for some Linux distributios. For instance, for Ubuntu, .NET Core SDK 2.1.300 is still at the Release Candidate stage.

It's important to remember that the .NET Assemblies remain untouched, it is just the .NET Framework (i.e., Mono) that is compiled to WebAssembly. This means that any C# code should work the same way in Blazor as in any other .NET implementation.

In this article we are using Blazor version 0.5.1.

Anatomy of a Blazor App

Now that everything is properly setup we can create our first Blazor app. But, first, let's take a look at the default template and specifically at the Index.cshtml file under Pages. It is the same page that we have seen when we first launched the app to test whether it was working.

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

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

This is a short page but it contains a few interesting things. It is a traditional Razor page, that is well used in the C# world, but with a few Blazor additions. If you have never used Razor, you can still easily understand it since it is a typical templating language mixed with HTML.

Routing

The @page directive is used to configure routing. This mean that this page will answer when the home root (/) is requested. You can also use normal ASP.NET route parameters such as in the following example.

@page "/{name}"

This page will assign the value specified in the URL to the variable name. Notice that, at the moment, optional elements are not supported. So, to support a route with an optional parameter instead you have to add to page directives, one with the optional parameter and one without.

// in normal ASP.NET you would write "/{name?}" for an optional parameter
@page "/"
@page "/{name}"

Elements

The second interesting thing of this page is the last line, the SurveyPrompt element. It looks and behaves like a normal HTML element, but obviously is not. In fact it is what Blazor calls a component, which is defined in the SurveyPrompt.cshtml page under the Shared folder. In Blazor, any page defines a corresponding component with the same name.

<div class="alert alert-secondary mt-4" role="alert">
    <span class="oi oi-pencil mr-2" aria-hidden="true"></span> 
    <strong>@Title</strong>

    <span class="text-nowrap">
        Please take our
        <a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=874928">
            brief survey
        </a>
    </span>
    and tell us what you think.
</div>

@functions {
    [Parameter]
    string Title { get; set; } // Demonstrates how a parent component can supply parameters
}

On line 3, we see the syntax to display the variable Title inside the HTML UI. This is standard Razor syntax. The new Blazor-specific part is at the end, with the functions directive. Here we can use standard C# to add functionality to the page. Notice that the Title attribute that we used in the index page it is configured as a parameter in this functions section. This is done with the [Parameter] annotation.

Navigation

Lastly, let's look at the standard template of a Blazor app, the page NavMenu.cshtml.

<li class="nav-item px-3">
    <NavLink class="nav-link" href="calendar">
        <span class="oi oi-calendar" aria-hidden="true"></span> Dates
    </NavLink>
</li>

This is the example of a menu item that is using the NavLink component, which is basically a simple element that adds the CSS class active when the element is selected. Let's do some cleanup and remove some stuff from the standard template that we are not going to use. We add this element and delete the ones already present. Then we delete corresponding pages and add a new page called Calendar.cshtml. So, our pages should now look like this.

Creating Our App

In our app, we want a page that shows the same date in a few different calendars.

@page "/"
@page "/calendar"

We associate the page with both the default route and the route calendar. This is useful to see one thing: when launching the app you will see what happens when changing pages. When visiting one of the pages, the underlying data will remain the same. So, they are not two different pages, but the same instance of a page, but one that answers to two different addresses.

@page "/"
@page "/calendar"

<div class="container">
  <div class="row">
    <div class="col-sm input-row">
      <h1>Date in Different Calendars</h1>
        <p>Select a date</p>
        <input type="date" bind="@date" placeholder="@DateTime.Now"/>
        &nbsp;&nbsp;&nbsp;
        <button class="btn btn-primary" onclick="@ConvertDate">Convert Date</button>        
    </div>    
  </div>
  <!-- the calendars -->
  <div class="row calendar-row">
    <div class="col-sm">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">Julian Calendar</h5>            
                <p class="card-text"><p>@calendarDate.JulianDate</p></p>            
            </div>
        </div>
    </div>
    [..]
  </div>
  [..] 
</div>

The UI is divided in two parts: the first section contains the input, while the second displayS the same data provided by the user in different calendars. The input, on line 9, is bOUnd to the variable date, while, as a placeholder, we use the field DateTime.Now. On line 11, we bind a function to the click action, using standard HTML syntax. This works basically as if it were a JavaScript function.

The parts where we display calendars is only partially shown here, given that is quite repetitive. The final version present in the repository contains three rows of three calendars each, for a total of nine calendars. Each calendar looks like the one shown here: a card (a card is a Bootstrap element) displaying the name of the calendar, and the date itself. The date is a field of a custom class we created.

@functions {
    string date = DateTime.Today.ToString("yyyy-MM-dd");
    CalendarDate calendarDate = new CalendarDate();

    void ConvertDate()
    {
        if (!string.IsNullOrWhiteSpace(date))
        {
            calendarDate.StringDate = date;
        }
    }
}

The part containing the functions directive does not have any surprises: we setup the variables and the function that we need in the UI. What happens is simply that we select a date with the input element, then when we click the button we convert the input date in the dates shown in the calendars. This is dynamic behavior implemented in C#, just what we needed. But what about the CalendarDate class?

The C# CalendarDate Class

This is a class that we can create: first, we need to add a new root-level C# file, called CalendarDate.cs.

using System;
using System.Globalization;
using System.Text;

public class CalendarDate
{
    private String stringDate = DateTime.Now.ToString();
    public String StringDate {
        get {
            return stringDate;
        }
        set {
            stringDate = value;
            Date = DateTime.Parse(stringDate);
        }
    }
    public DateTime Date { get; set; } = DateTime.Now;

    private string GetDateForCalendar(Calendar cal)
    {
        if(Date > cal.MinSupportedDateTime && Date < cal.MaxSupportedDateTime)        
            return $"{cal.GetDayOfMonth(Date):d2}/{cal.GetMonth(Date):d2}/{cal.GetYear(Date):d4}";
        else
            return "Invalid Date";
    }
    public string JulianDate
    {
        get {
            Calendar cal = new JulianCalendar();

            return GetDateForCalendar(cal);                        
        }
    }

    [..]
}

This is simple C# code, with nothing special in it. When we assign a value to the StringDate field, we also automatically assign the corresponding value to the Date field. Basically, the input is a String, but we need to convert it to a DateTime variable. On line 17, we assign a default value to our Date field, so that initially the calendars show a valid date.

The GetDateForCalendar ensures that, if the date selected is valid for that calendar (line 21), we convert it to a String holding the representation of that date in the specified calendar (line 22). If the date is not valid, we return a string to denote that. This is necessary because not all calendars can deal with all dates, sometimes it is a problem of the calendar itself, sometimes the issue is with .NET implementation or the fact that we do not deal with the concept of eras.

Image title

After we added a bit of CSS in the file www-root/css/site.css (not shown), we can launch the program with dotnet run. The final result is quite neat.

Image title

Look at that, dynamic behavior without a hint of JavaScript.

So, can we ditch JavaScript altogether? Well, not quite. You probably going to want to keep using JavaScript to manipulate the DOM. Though before seeing how to interact with JavaScript, let's see a few gotchas in Blazor.


That's all for Part 1. Tune in tomorrow for Part 2 where we'll discuss topics just as JavaScript interoperability, writing to the console, and injecting variables. 

Blazor .NET app JavaScript Calendar (Apple) Element WebAssembly

Published at DZone with permission of Federico Tomassetti, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Spinnaker vs. Argo CD: Best Tools for Continuous Delivery
  • Journey to Event Driven, Part 1: Why Event-First Programming Changes Everything
  • Unlock the Power of Terragrunt’s Hierarchy
  • File Uploads for the Web (1): Uploading Files With HTML

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: