Posted on Leave a comment

Blazor 0.4.0 experimental release now available

Blazor 0.4.0 is now available! This release includes important bug fixes and several new feature enhancements.

New features in Blazor 0.4.0 (details below):

  • Add event payloads for common event types
  • Use camelCase for JSON handling
  • Automatic import of core Blazor namespaces in Razor
  • Send and receive binary HTTP content using HttpClient
  • Templates run on IIS Express by default with autobuild enabled
  • Bind to numeric types
  • JavaScript interop improvements

A full list of the changes in this release can be found in the Blazor 0.4.0 release notes.

Get Blazor 0.4.0

To get setup with Blazor 0.4.0:

  1. Install the .NET Core 2.1 SDK (2.1.300 or later).
  2. Install Visual Studio 2017 (15.7) with the ASP.NET and web development workload selected.
    • Note: The Blazor tooling isn’t currently compatible with the VS2017 preview channel (15.8). This will be addressed in a future Blazor release.
  3. Install the latest Blazor Language Services extension from the Visual Studio Marketplace.

To install the Blazor templates on the command-line:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates

You can find getting started instructions, docs, and tutorials for Blazor at https://blazor.net.

Upgrade an existing project to Blazor 0.4.0

To upgrade an existing Blazor project from 0.3.0 to 0.4.0:

  • Install all of the required bits listed above.
  • Update your Blazor package and .NET CLI tool references to 0.4.0.

Your upgraded Blazor project file should look like this:

<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <RunCommand>dotnet</RunCommand> <RunArguments>blazor serve</RunArguments> <LangVersion>7.3</LangVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Blazor.Browser" Version="0.4.0" /> <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.4.0" /> <DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.4.0" /> </ItemGroup> </Project>

Event payloads for common event types

This release adds payloads for the following event types:

Event arguments Events
UIMouseEventArgs onmouseover, onmouseout, onmousemove, onmousedown, onmouseup, oncontextmenu
UIDragEventArgs ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop
UIPointerEventArgs gotpointercapture, lostpointercapture, pointercancel, pointerdown, pointerenter, pointerleave, pointermove, pointerout, pointerover, pointerup
UITouchEventArgs ontouchcancel, ontouchend, ontouchmove, ontouchstart, ontouchenter, ontouchleave
UIWheelEventArgs onwheel, onmousewheel
UIKeyboardEventArgs onkeydown, onkeyup
UIKeyboardEventArgs onkeydown, onkeyup, onkeypress
UIProgressEventArgs onloadstart, ontimeout, onabort, onload, onloadend, onprogress, onerror

Thank you to Gutemberg Ribeiro (galvesribeiro) for this contribution! If you haven’t checked out Gutemberg’s handy collection of Blazor extensions they are definitely worth a look.

Use camelCase for JSON handling

The Blazor JSON helpers and utilities now use camelCase by default. .NET objects serialized to JSON are serialized using camelCase for the member names. On deserialization a case-insensitive match is used. The casing of dictionary keys is preserved.

Automatic import of core for Blazor namespaces in Razor

Blazor now automatically imports the Microsoft.AspNetCore.Blazor and Microsoft.AspNetCore.Blazor.Components namespaces in Razor files, so you don’t need to add @using statements for them. One less thing for you to do!

Send and receive binary HTTP content using HttpClient

You can now use HttpClient to send and receive binary data from a Blazor app (previously you could only handle text content). Thank you Robin Sue (Suchiman) for this contribution!

Bind to numeric types

Binding now works with numeric types: long, float, double, decimal. Thanks again to Robin Sue (Suchiman) for this contribution!

Templates run on IIS Express by default with autobuild enabled

The Blazor project templates are now setup to run on IIS Express by default, while still preserving autobuild support.

JavaScript interop improvements

Call async JavaScript functions from .NET

With Blazor 0.4.0 you can now call and await registered JavaScript async functions like you would an async .NET method using the new RegisteredFunction.InvokeAsync method. For example, you can register an async JavaScript function so it can be invoked from your Blazor app like this:

Blazor.registerFunction('BlazorLib1.DelayedText', function (text) { // Wait 1 sec and then return the specified text return new Promise((resolve, reject) => { setTimeout(() => { resolve(text); }, 1000); });
});

You then invoke this async JavaScript function using InvokeAsync like this:

public static class ExampleJSInterop
{ public static Task<string> DelayedText(string text) { return RegisteredFunction.InvokeAsync<string>("BlazorLib1.DelayedText", text); }
}

Now you can await the async JavaScript function like you would any normal C# async method:

var text = await ExampleJSInterop.DelayedText("See ya in 1 sec!");

Call .NET methods from JavaScript

Blazor 0.4.0 makes it easy to call sync and async .NET methods from JavaScript. For example, you might call back into .NET when a JavaScript callback is triggered. While calling into .NET from JavaScript was possible with earlier Blazor releases the pattern was low-level and difficult to use. Blazor 0.4.0 provides simpler pattern with the new Blazor.invokeDotNetMethod and Blazor.invokeDotNetMethodAsync functions.

To invoke a .NET method from JavaScript the target .NET method must meet the following criteria:

  • Static
  • Non-generic
  • No overloads
  • Concrete JSON serializable parameter types

For example, let’s say you wanted to invoke the following .NET method when a timeout is triggered:

namespace Alerts
{ public class Timeout { public static void TimeoutCallback() { Console.WriteLine('Timeout triggered!'); } }
}

You can call this .NET method from JavaScript using Blazor.invokeDotNetMethod like this:

Blazor.invokeDotNetMethod({ type: { assembly: 'MyTimeoutAssembly', name: 'Alerts.Timeout' }, method: { name: 'TimeoutCallback' }
})

When invoking an async .NET method from JavaScript if the .NET method returns a task, then the JavaScript invokeDotNetMethodAsync function will return a Promise that completes with the task result (so JavaScript/TypeScript can also use await on it).

Summary

We hope you enjoy this latest preview of Blazor. Your feedback is especially important to us during this experimental phase for Blazor. If you run into issues or have questions while trying out Blazor please file issues on GitHub. You can also chat with us and the Blazor community on Gitter if you get stuck or to share how Blazor is working for you. After you’ve tried out Blazor for a while please also let us know what you think by taking our in-product survey. Just click the survey link shown on the app home page when running one of the Blazor project templates:

Blazor survey

Thanks for trying out Blazor!

Posted on Leave a comment

Blazor 0.3.0 experimental release now available

Blazor 0.3.0 is now available! This release includes important bug fixes and many new feature enhancements.

New features in this release (details below):

  • Project templates updated to use Bootstrap 4
  • Async event handlers
  • New component lifecycle events: OnAfterRender / OnAfterRenderAsync
  • Component and element refs
  • Better encapsulation of component parameters
  • Simplified layouts

A full list of the changes in this release can be found in the Blazor 0.3.0 release notes.

Get Blazor 0.3.0

To get setup with Blazor 0.3.0:

  1. Install the .NET Core 2.1 SDK (2.1.300-preview2-008533 or later).
  2. Install Visual Studio 2017 (15.7 Preview 5 or later) with the ASP.NET and web development workload selected.
  3. Install the latest Blazor Language Services extension from the Visual Studio Marketplace.

To install the Blazor templates on the command-line:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates

You can find getting started instructions, docs, and tutorials for Blazor at https://blazor.net.

Upgrade an existing project to Blazor 0.3.0

To upgrade an existing Blazor project from 0.2.0 to 0.3.0:

  • Install all of the required bits listed above.
  • Update your Blazor package and .NET CLI tool references to 0.3.0.
  • Remove any package reference to Microsoft.AspNetCore.Razor.Design as it is now a transitive dependency.
  • Update the C# language version to be 7.3. You may need to restart Visual Studio for this change to take effect.
  • Update component parameters to not be public and to add the [Parameter] attribute.
  • Update layouts to inherit from BlazorLayoutComponent and remove the implementation of ILayoutComponent including the Body property.

Your upgraded Blazor project file should look like this:

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

 <PropertyGroup>
 <TargetFramework>netstandard2.0</TargetFramework>
 <RunCommand>dotnet</RunCommand>
 <RunArguments>blazor serve</RunArguments>
 <LangVersion>7.3</LangVersion>
 </PropertyGroup>

 <ItemGroup>
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Browser" Version="0.3.0" />
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.3.0" />
 <DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.3.0" />
 </ItemGroup>

</Project>

Project templates updated to use Bootstrap 4

The Blazor project templates have been updated to use Bootstrap 4. Bootstrap 4 includes lots of new features including an improved grid system based on flexbox, an improved reset file, new components, better tooltip support, better forms styling, built-in spacing utilities, and much more.

The new Bootstrap 4 styles also give the Blazor templates a fresh look:

Blazor Boostrap 4 template

Async event handlers

Event handlers can now be asynchronous and return a Task that gets managed by the runtime. Once the task is completed the component is rendered without the need to manually invoke StateHasChanged. Any exceptions that occur during the asynchronous execution of the event handler will be correctly handled and reported.

For example, we can update the FetchData.cshtml page to have an Update button that when selected asynchronously updates the weather forecast data by making HttpClient calls to the backend web API:

<button class="btn btn-primary" onclick="@UpdateForecasts">Update</button>

...

@functions {
 WeatherForecast[] forecasts;

 protected override Task OnInitAsync()
 {
 return UpdateForecasts();
 }

 async Task UpdateForecasts()
 {
 forecasts = await Http.GetJsonAsync<WeatherForecast[]>("/api/SampleData/WeatherForecasts");
 }
}

More strongly-typed events

This release adds strongly typed events for the most of the commonly used browser events, including mouse and focus events. You can now handle most events from your components.

You can see a full list of the events now supported in here.

<h1 class="display-1" onmouseover="@OnMouseOver" onmouseout="@OnMouseOut">@inOrOut</h1>

@functions {
 string inOrOut = "OUT";

 void OnMouseOver()
 {
 inOrOut = "IN!";
 }

 void OnMouseOut()
 {
 inOrOut = "OUT";
 }
}

Mouse events tooling screen shot

Most of the event arguments don’t yet capture and surface the data from the events. That’s something that we expect to handle in a future release. We welcome community contributions to help out with this effort.

Capturing references to DOM elements

Blazor components typically interact with the DOM through their rendering logic in markup. There are cases, however, when a parent component needs to modify or interact with DOM elements directly. Example scenarios including setting element focus or integrating with existing UI libraries that require references to elements for initialization. This release adds support for capturing DOM elements from components and using them when interacting with JavaScript.

To capture an element reference from a component attribute the element markup with a ref attribute that points to a component field of type ElementRef.

<input ref="username" />

@functions {
 ElementRef username;
}

ElementRef is an opaque handle. The only thing you can do with it is pass it through to JavaScript code, which receives the element as an HTMLElement that can be used with normal DOM APIs.

Note that the ElementRef field (username in the previous example) will uninitialized until after the component has been rendered. If you pass an uninitialized ElementRef to JavaScript code, the JavaScript code will receive null.

Let’s create a API that lets us set the focus on an element. We could define this API in our app, but to make it reusable let’s put it in a library.

  1. Create a new Blazor class library

     dotnet new blazorlib -o BlazorFocus
    
  2. Update content/exampleJsInterop.js to register a JavaScript method that sets the focus on a specified element.

     Blazor.registerFunction('BlazorFocus.FocusElement', function (element) {
 element.focus();
 });
    
  3. Add a ElementRefExtensions class to the library that defines a Focus extension method for ElementRef.

     using System;
 using Microsoft.AspNetCore.Blazor;
 using Microsoft.AspNetCore.Blazor.Browser.Interop;
    
 namespace BlazorFocus
 {
 public static class ElementRefExtensions
 {
 public static void Focus(this ElementRef elementRef)
 {
 RegisteredFunction.Invoke<object>("BlazorFocus.FocusElement", elementRef);
 }
 }
 }
    
  4. Create a new Blazor app and reference the BlazorFocus library

     dotnet new blazor -o BlazorApp1
     dotnet add BlazorApp1 reference BlazorFocus
    
  5. Update Pages/Index.cshtml to add a button and a text input. Capture a reference to the text input by adding a ref attribute that points to a field of type ElementRef with the same name. Add an onclick handler to the first button that sets the focus on the second button using the captured reference and the Focus extension method we defined previously.

     @using BlazorFocus
    
 ...
    
 <button onclick="@SetFocus">Set focus</button>
 <input ref="input1" />
    
 @functions {
 ElementRef input1;
    
 void SetFocus()
 {
 input1.Focus();
 }
 }
    
  6. Run the app and try out behavior

     dotnet run BlazorApp1
    

    Set focus

Capturing reference to components

You can also capture references to other components. This is useful when you want a parent component to be able to issue commands to child components such as Show or Reset.

To capture a component reference attribute the component with a ref attributes that points to a field of the matching component type.

<MyLoginDialog ref="loginDialog"/>

@functions {
 MyLoginDialog loginDialog;

 void OnSomething()
 {
 loginDialog.Show();
 }
}

Note that component references should not be used as a way of mutating the state of child components. Instead, always use normal declarative parameters to pass data to child components. This will allow child components to re-render at the correct times automatically.

OnAfterRender / OnAfterRenderAsync

To capture element and component references the component must already be rendered. Components now have a new life-cycle event that fires after the component has finished rendering: OnAfterRender / OnAfterRenderAsync. When this event fires element and component references have already been populated. This makes it possible to perform additional initialization steps using the rendered content, such as activating third-party JavaScript libraries that operate on the rendered DOM elements.

For example, we can use OnAfterRender to set the focus on a specific element when a component first renders.

The example below shows how you can receive the OnAfterRender event in your component.

<input ref="input1" placeholder="Focus on me first!" />
<button>Click me</button>

@functions {
 ElementRef input1;
 bool isFirstRender = true;

 protected override void OnAfterRender()
 {
 if (isFirstRender)
 {
 isFirstRender = false;
 input1.Focus();
 }
 }
}

Note that OnAfterRender / OnAfterRenderAsync is called after each render, not just the initial one, so the component has to keep try of whether this is the first render or not.

Better encapsulation of component parameters

In this release we’ve made some changes to the programming model for component parameters. These changes are intended to improve the encapsulation of the parameter values and discourage improper mutation of component state (e.g. using component references).

Component parameters are now defined by properties on the component type that have been attributed with [Parameter]. Parameters that are set by the Blazor runtime (e.g. ChildContent properties, route parameters) must be similarly attributed. Properties that define parameters should not be public.

A Counter component with an IncrementAmount parameter now looks like this:

@page "/counter"

<h1>Counter</h1>

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

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

@functions {
 int currentCount = 0;

 [Parameter]
 private int IncrementAmount { get; set; } = 1;

 void IncrementCount()
 {
 currentCount += IncrementAmount;
 }
}

Simplified layouts

Layouts now inherit from BlazorLayoutComponent instead of implementing ILayoutComponent. The BlazorLayoutComponent defines a Body parameter that can be used for specifying where content should be rendered. Layouts no longer need to define their own Body property.

An example layout with these changes is shown below:

@inherits BlazorLayoutComponent

<div class="sidebar">
 <NavMenu />
</div>

<div class="main">
 <div class="top-row px-4">
 <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
 </div>

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

Summary

We hope you enjoy this latest preview of Blazor. Your feedback is especially important to us during this experimental phase for Blazor. If you run into issues or have questions while trying out Blazor please file issues on GitHub. You can also chat with us and the Blazor community on Gitter if you get stuck or to share how Blazor is working for you. After you’ve tried out Blazor for a while please also let us know what you think by taking our in-product survey. Just click the survey link shown on the app home page when running one of the Blazor project templates:

Blazor survey

Thanks for trying out Blazor!