Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Blazor: .NET in the Browser, Part 2

DZone's Guide to

Blazor: .NET in the Browser, Part 2

Last time, we looked at the general structure of a Blazor app is. Now, we'll look at interoperability with JavaScript, binding details, and more.

· Web Dev Zone ·
Free Resource

Start coding something amazing with our library of open source Cloud code patterns. Content provided by IBM.

Welcome back! If you missed Part 1, check it out here!

Things to Know When Using Blazor

We have seen how simple the general structure of a Blazor app is. Now, we are going to see a few things to know when using Blazor: interoperability with JavaScript, binding details, etc.

Special Attribute to Format Strings

In our example, we bind the input to a string field and then convert the string field to the proper DateTime value. This is the typical pattern that you are going to use because the input is generally a string, while our fields are not always so. However, just for the DateTime type, there is a special attribute that you can use to bypass the need for an intermediate variable.

<input type="date" bind="@calendarDate.Date" format-value="yyyy-MM-dd" />

We could have used the special attribute format-value to help Blazor automatically convert to and from the DateTime value. At the moment, this attribute only works for DateTime variables. It works both for display and when the value is parsed after the onchange event.

Writing to Console Works

Writing to Console works as if you were using console.log. If we added the following line to our ConvertDate function.

Console.WriteLine("ConvertDate called");

You would see this text on the usual Console in the browser.

The only difference is that the string is prepended with a WASM: .

You Can Inject Variables

Using the directive inject you can inject variables/properties into a component.

@inject HttpClient Http

Blazor comes with a ready-to-inject service for HttpClient. Since Blazor 0.5.0, you've been able to add your custom services as you would in a traditional ASP.NET app, by going to the ConfigureServices function of the Startup class.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Add any custom services here
    }

    public void Configure(IBlazorApplicationBuilder app)
    {
        app.AddComponent<App>("app");
    }
}

You can also use these services to perform traditional constructor injections, like in any other ASP.NET software. You can look up the documentation for more information.

JavaScript Interoperability

To see how JavaScript interoperability works, let's create the new page Text.csthml and add the link to navigation column in NavMenu.cshtml. Then we create a folder js inside www-root, and inside this folder we add a file called site.js.

The image shows our additions.

We obviously also need to add in a script the JavaScript source in the main index.html file.

Calling JavaScript From C#

Since Blazor 0.5.0, there is no need to register with Blazor the JavaScript function that we are going to call from C#. You can call any JavaScript function.

To call a registered JavaScript function we use the method InvokeAsync of JSRuntime.Current, included in the namespace Microsoft.JSInterop. The first parameter of the method is the name of the JavaScript function while the others are its arguments.The function identifier of the JavaScript function is relative to the global scope (window). For example, if you wish to call window.someFunction, the identifier is someFunction.

The generic parameter type is the return type of the function. You cannot use void or not return anything. However, there is a workaround: if you do not return anything, you can say that the function returns a string and everything works fine. Except, of course that you should not use the value returned by the invocation of the function.

We can go to the Text.cshtml file and perform the call.

@page "/text"
@using Microsoft.AspNetCore.Blazor;
@using Microsoft.JSInterop;

<textarea id="main_text" class="form-control" rows="10" onchange='@repeat' ></textarea>

@functions {        
    void repeat(UIChangeEventArgs e)
    {
        JSRuntime.Current.InvokeAsync<string>(
            "console.log",
            e.Value);
    }
}

We bind the onchange attribute to our repeat function. Notice that the signature of the repeat function contains a parameter of type UIChangeEventArgs. We cannot define custom parameters but we can use some that are predefined for specific events. These parameters can be omitted if we do not need them. For the change events there is an argument of type UIChangeEventArgs that contains the new value.

Passing References of Elements

Since Blazor 0.5.0 you can also pass references of HTML elements from C# to JavaScript functions. All you have to do is adding the attribute ref to the HTML elements and then add an ElementRef field with the value of the attribute in the functions section.

<textarea ref="text"></textarea>

@functions {  
    ElementRef text;
}

In this example we create a reference text for a textarea element. The ElementRef handle is completely opaque for Blazor, so you cannot do anything with itm except passing as-it-is to a JavaScript function.

@function {
    JSRuntime.Current.InvokeAsync<string>(
            "console.log",
            text);
}

In JavaScript, the reference represents the whole element. So, from JavaScript you can access its individual attributes, like id or name.

However, from Blazor you cannot pass anything other than the plain reference. So, the following code is invalid.

Calling C# From JavaScript

You can also call C# methods from JavaScript using the functions Blazor.invokeDotNetMethod or Blazor.invokeDotNetMethodAsync. However, you cannot call all methods, only the ones that respect these conditions:

  • Non-generic.
  • Not overloaded.
  • Concrete type method parameters (i.e., Example<string> is valid, Example<T> is not).
  • Parameters deserializable using JSON.

Let's see an example of how it works with a static method.

We create a new root C# file called Util.cs.

namespace BlazorApp
{
    public class Util
    {
        [JSInvokable]
        public static string RememberTheTruth(string text)
        {
            int start = 0;

            while(text.IndexOf("JavaScript", start) != -1)
            {                
                start = text.IndexOf("JavaScript", start) + 10;
                if((text.Length > start + 4 && text.Substring(start+2, 2) != "C#") ||
                   text.Length < start + 4)
                    text = text.Insert(start, " (C# is better)");
            }

            return text;
        }
    }
}

The class contain a static C# method decorate with [JSInvokable]. The method checks a string and ensures that one basic truth of life is always remembered.

Then we edit the JavaScript file.

function check() {          
      document.getElementById("main_text").value =
      DotNet.invokeMethod('BlazorApp','RememberTheTruth',
        document.getElementById("main_text").value);
}

We can use the function DotNet.invokeMethod to call a C# method (add Async if you are calling an async method):

  • The first argument is the name of the assembly.
  • The second one is the name of the function.
  • The last argument is the argument for the C# method.

We assign the result of our C# function call to the textarea value.

Now, we just have to change onchange attribute of the textarea in the Text.cshtml file to call our JavaScript function.

<textarea id="main_text" class="form-control" rows="10" onchange='check();'></textarea>

The end result works nicely.

Calling a .NET Instance Method

Since Blazor 0.5.0 you can also call .NET instance method, although the procedure is a bit more convoluted.

As usual, you have to decorate the method with [JSInvokable].

public class Simple 
{            
    public string Text { get; set; }
    public Simple(string text)
    {
        Text = text;
    }
    [JSInvokable]
    public string ToUpper()
    {
        return Text.ToUpper();
    }
}

You then have to invoke the JavaScript function that is going to use that method (ToUpper in our example) from C#, passing an object of the class to it.

@function {
    void shout() {
        JSRuntime.Current.InvokeAsync<object>(
            "capitalize", // name of the JavaScript function
            // object passed to the JavaScript function
            new DotNetObjectRef(new Simple("strong opinion")));
    }
}

The instance of the desired class is wrapped in another object of the type DotNetObjectRef. In this example, we pass an object of type Simple.

Finally, in JavaScript we are going to use invokeMethod to call the method we wanted to call.

function capitalize(dotnetHelper) {  
    console.log(dotnetHelper.invokeMethod('ToUpper'));
}

As you can see it is not hard, but is still a bit complex.

Summary

We have created a small example program and shown the major issues that arise when merging the C# and JavaScript world. We have seen how Blazor allows to easily bring the mature ASP.NET and C# ecosystem to the client in the browser. The interoperability with JavaScript is also there, although it is still a bit cumbersome.

Blazor is a very promising platform to deliver C# software on the client. It is still at an experimental stage, so there are a few rough edges, but it already works well enough for simple projects. Even at this stage, it is still better than using WebAssembly with C++. If you like C#, or the .NET Platform, you should start studying the platform now, since it promises to be an awesome new addition to the .NET world.

Blazor is a great way to fullfill the promise of WebAssembly: you can now create and bring to the client every kind of powerful and complex software that is still on the desktop. And you can do that using your favorite language and the existing codebase. What is not to like?

One thing to remember: you can call any .NET library, but you will have always to use some C# because Razor uses C#. So, you can already use F# libraries, but you need C# in the Razor pages (i.e., everything the code that is in *.cshtml files) to make it work with Blazor.

Code something amazing with the IBM library of open source blockchain patterns. Content provided by IBM.

Topics:
web dev ,blazor ,.net ,web application development

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}