Book Image

Building Blazor WebAssembly Applications with gRPC

By : Václav Pekárek
5 (1)
Book Image

Building Blazor WebAssembly Applications with gRPC

5 (1)
By: Václav Pekárek

Overview of this book

Building Blazor WebAssembly Applications with gRPC will take you to the next level in your web development career. After working through all the essentials of gRPC, Blazor, and source generators, you will be far from a beginner C# developer and would qualify as a developer with intermediate knowledge of the Blazor ecosystem. After a quick primer on the basics of Blazor technology, REST, gRPC, and source generators, you’ll dive straight into building Blazor WASM applications. You’ll learn about everything from two-way bindings and Razor syntax to project setup. The practical emphasis continues throughout the book as you steam through creating data repositories, working with REST, and building and registering gRPC services. The chapters also cover how to manage source generators, C# and debugging best practices, and more. There is no shorter path than this book to solidify your gRPC-enabled web development knowledge. By the end of this book, your knowledge of building Blazor applications with one of the most modern and powerful frameworks around will equip you with a highly sought-after skill set that you can leverage in the best way possible.
Table of Contents (10 chapters)

Learning how to write Razor syntax

Razor syntax is a combination of HTML, Razor markup, and C#. The syntax is similar to other JavaScript SPA frameworks, such as Vue.js, React, and Angular. The HTML in the Razor component is rendered the same way as it is in the HTML file. In the Razor component, you can fluently move between HTML markup and C# code.

Razor uses the @ symbol to determine the Razor syntax. If the @ symbol is followed by a reserved keyword, then the code is transitioned to Razor syntax. This Razor syntax can add dynamic logic to our components. The expressions can be implicit, explicit, inline, or in the form of code blocks.

Writing implicit Razor expressions

Implicit Razor expressions start with the @ symbol, followed by C# code:

<span>It is @DateTime.Now</span>

In the preceding code, @ is followed by the C# code directly. Implicit Razor expressions can’t contain spaces or generic calls, because < and > symbols in the generic call are translated as HTML in the Razor syntax. The only exception is the await keyword, which can be followed by a space. If the method is used in the implicit Razor syntax call, the spaces can be used in the arguments.

Writing explicit Razor expressions

Explicit Razor expressions start with @, followed by parentheses:

<span>It was @(DateTime.Now – TimeSpan.FromDays(7))</span>

The preceding code renders the date in the last week. Explicit Razor expressions are used when we can’t access the result value directly in the property or field or when we need to calculate some result, use generic calls, or prevent the value in the HTML string from being concatenated. Here is an example:

@{
var addr = new Address(Street: "Fairmont St NW", City: "Washington", "PostalCode": "20009");
}
<span>The address [email protected] @addr.City @addr.PostalCode</span>

The preceding code will render the following output HTML:

<span>The address [email protected] Washington 20009</span>

In the preceding output, addr.Street is not replaced by the property value because the term may comprise the syntax of an email address – that is, [email protected]. When we need to use a directive just after a letter, we need to use the explicit Razor syntax:

<span>The address is@(addr.Street) @addr.City @addr.PostalCode</span>

As expected, the preceding code will generate the output HTML:

<span>The address isFairmont St NW Washington 20009</span>

Important information

If the @ symbol follows the letter, it is not translated to the Razor directive. If you need to render @ in the HTML, you can escape the symbol with another @.

For example, @@MyUserName will render in the HTML as @MyUserName.

Writing inline expressions

Inline expressions are all of the expressions on a single line. Both implicit and explicit expressions are inline expressions.

Writing code block expressions

When creating our Razor components, we need to use some functionality other than just the properties or fields from C#. The code block expressions start with the @ symbol and are enclosed within curly brackets:

@{
var title = "About Blazor WebAssembly";
}
<h2>@title</h2>
@{
title = "Razor syntax";
}
<h2>@title</h2>

The preceding code will generate the following output HTML:

<h2>About Blazor WebAssembly</h2>
<h2>Razor syntax</h2>

As you can see in the preceding output, the generated HTML consists of two headlines.

Block expressions can also be used to create local functions to render repeated HTML code:

@{
void RenderTitle(string title)
{
<h2>@title</h2>
}
RenderTitle("About Blazor WebAssembly");
RenderTitle("Razor syntax");
}

The output HTML generated from the preceding code will be the same as in the first example in this section. We do not need to modify the variable each time we want to render the title because we can use the RenderTitle function defined in the code block. This example shows simple code, but in the real world, the local function will contain more complex code.

Writing control structures

Control structures are specific types of code blocks. They are used when the code block has some specific meaning to the code, such as conditions, loops, and so on.

Conditions

We can use the if directive to start a code block with conditions:

@if (chapterNumber == 1)
{
  <p>This is the first chapter.</p>
}
else if (chapterNumber == 6)
{
  <p>This is the last chapter.</p>
}
else
{
  <p>Chapter @chapterNumber</p>
}

The preceding code shows a full if - else if – else statement for rendering paragraph information for each chapter in this book. The same condition can be applied by the switch statement:

@switch (chapterNumber)
{
  case 1:
    <p>This is the first chapter.</p>
    break;
  case 6:
    <p>This is the last chapter.</p>
    break;
  default:
    <p>Chapter @chapterNumber</p>
    break;
}

The preceding switch statement will generate the same HTML result as the if statement.

Loops

The following loop types are supported in Razor syntax:

  • for
  • foreach
  • while
  • do while

Each loop starts with the @ symbol. Looping through a collection of items helps you in situations where you want to apply some repetitive code to each item in the collection. The following example shows the looping of chapters:

@{
  var chapters = new Chapter[]
  {
    new Chapter(1, "Learning Razor syntax"),
    new Chapter(2, "Creating Razor components"),
    new Chapter(3, "Understanding page routing in Blazor"),
    …
  };
}

The preceding code defines a new chapters variable that will be used in the following loop examples:

  • The following is an example of a for loop:
    @for (var i = 0; i < chapters.Length; i++)
    {
      var chapter = chapters[i];
      <h2>Chapter no. @chapter.Number: @chapter.Title</h2>
    }
  • The following is an example of a foreach loop:
    @foreach (var chapter in chapters)
    {
      <h2>Chapter no. @chapter.Number: @chapter.Title</h2>
    }
  • The following is an example of a while loop:
    @{ var i = 0; }
    @while (i < chapters.Length)
    {
      var chapter = chapters[i];
      <h2>Chapter no. @chapter.Number: @chapter.Title</h2>
      i++;
    }
  • The following is an example of a do while loop:
    @{ var i = 0; }
    @do
    {
      var chapter = chapters[i];
      <h2>Chapter no. @chapter.Number: @chapter.Title</h2>
      i++;
    }
    while (i < chapters.Length)

As you can see, the Razor syntax is similar to the C# syntax. The only difference is in the transition between C# code and HTML code.

Razor syntax allows some other keywords to be used in the code blocks, such as @using (for disposable objects), @try, catch, finally, and @lock. The HTML and C# comments are also allowed.

Writing top-level directives

Razor directives, which are at the top of the file, control many aspects of the component. They can change the way the component is compiled, how the component is used on the website, or who can view the component’s output. The directives should be at the top of the file, but the order of the directives is not defined. Here is the list of these top-level directives:

  • @page: This directive specifies the page where the component is rendered. We will learn more about this in the following sections. Here is an example of the directive for the home page:
    @page "/home"
  • @namespace: The @namespace directive can override the namespace for the component. The default component namespace is based on the folder structure. Here is an example of namespace overriding:
    @namespace DemoProject.MyLibrary.Components
  • @inherits: When we want to change the base class of the component, we need to use the @inherits directive, as shown in the following example:
    @inherits CustomComponentBase
  • @implements: Our component can implement any interface. This directive can be used multiple times. Here is an example of implementing two interfaces:
    @implements IDisposable
    @implements ISortable
  • @layout: The @layout directive is only used on the component that contains the @page directive. The default layout is used if nothing has been set. If the page directive is missing, the @layout directive is ignored. Here is an example of the layout directive setting the layout to LoginLayout:
    @layout LoginLayout
  • @attribute: The @attribute directive adds a class-level attribute to the component class. This directive can be used multiple times. Here is an example of marking a component for only authorized viewing:
    @attribute [Authorize]
  • @using: This directive can be used multiple times to import namespaces to the component scope:
    @using DemoProject.Model
  • @typeparam: The @typeparam directive is mostly used in combination with the generic base class in the @inherits directive. If the base class contains multiple generic types, the order of the @typeparam directive must reflect the order of the generic types:
    @implements MyBaseClass<TItemModel, TFilterModel>
    @typeparam MyItemModel
    @typeparam MyFilterModel
  • @inject: The @inject directive injects service from the dependency injection container into the component:
    @inject HttpClient Client
    @inject IJSRuntime JS

The preceding code shows how to inject an HttpClient into the Client property and IJSRuntime into the JS property.

Writing inline directives

Inline directives are used in the HTML or Razor components. These directives include the following:

  • @attributes: These directives represent a collection (Dictionary<string, object>) of HTML attributes that we want to render in the child component that has not specified these HTML attributes as component parameter properties:
    @{
      Dictionary<string, object> AdditionalAttributes =
        new Dictionary<string, object()
    {
      { "tooltip", "Set your full name." },
      { "required", "true" },
      { "data-id", 150 }
    };
    }
    <input @attributes="AdditionalAttributes" />
  • @bind: This directive creates two-way data binding for a component with user input:
    @{ public string UserName { get; set; } }
    <input type="text" @bind-Value="UserName" /> 
  • @on{event}: This directive adds an event handler for the event specified (click, change, and so on):
    <button @onclick="OnClickHandler">Click here!</button> 
  • @key: This directive specifies the unique key used to render the collection of data in loops (for, foreach, while, and do while):
    @for (var i = 1; i <= 10; i++)
    {
      <p @key="i">This is row @i</p>
    }

Such keys are used when updating the rendered data to update a correct item of the loop, instead of updating the whole loop.

  • @ref: This directive captures a reference to the component or HTML element:
    <ConfirmBox @ref="myConfirmBox" />
    @code {
    …
      myConfirmBox.OnConfirm(…);
      …
    }

@ref can be used to trigger JavaScript events.

Now that we know how to write Razor syntax, let’s learn how to use Razor syntax and create fully functional Razor components.