Posted on Leave a comment

Blazor 0.6.0 experimental release now available

Blazor 0.6.0 is now available! This release includes new features for authoring templated components and enables using server-side Blazor with the Azure SignalR Service. We’re also excited to announce our plans to ship the server-side Blazor model as Razor Components in .NET Core 3.0!

Here’s what’s new in the Blazor 0.6.0 release:

  • Templated components
    • Define components with one or more template parameters
    • Specify template arguments using child elements
    • Generic typed components with type inference
    • Razor templates
  • Refactored server-side Blazor startup code to support the Azure SignalR Service

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

Get Blazor 0.6.0

Install the following:

  1. .NET Core 2.1 SDK (2.1.402 or later).
  2. Visual Studio 2017 (15.8 or later) with the ASP.NET and web development workload selected.
  3. The latest Blazor Language Services extension from the Visual Studio Marketplace.
  4. 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.6.0

To upgrade a Blazor 0.5.x project to 0.6.0:

  • Install the prerequisites listed above.
  • Update the Blazor package and .NET CLI tool references to 0.6.0. The 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.6.0" />
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.6.0" />
 <DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.6.0" />
    </ItemGroup>
    
    </Project>
    

That’s it! You’re now ready to try out the latest Blazor features.

Templated components

Blazor 0.6.0 adds support for templated components. Templated components are components that accept one or more UI templates as parameters, which can then be used as part of the component’s rendering logic. Templated components allow you to author higher-level components that are more reusable than what was possible before. For example, a list view component could allow the user to specify a template for rending items in the list, or a grid component could allow the user to specify templates for the grid header and for each row.

Template parameters

A templated component is defined by specifying one or more component parameters of type RenderFragment or RenderFragment<T>. A render fragment represents a segment of UI that is rendered by the component. A render fragment optionally take a parameter that can be specified when the render fragment is invoked.

TemplatedTable.cshtml

@typeparam TItem

<table>
 <thead>
 <tr>@TableHeader</tr>
 </thead>
 <tbody>
 @foreach (var item in Items)
 {
 @RowTemplate(item)
 }
 </tbody>
 <tfoot>
 <tr>@TableFooter</tr>
 </tfoot>
</table>

@functions {
 [Parameter] RenderFragment TableHeader { get; set; }
 [Parameter] RenderFragment<TItem> RowTemplate { get; set; }
 [Parameter] RenderFragment TableFooter { get; set; }
 [Parameter] IReadOnlyList<TItem> Items { get; set; }
}

When using a templated component, the template parameters can be specified using child elements that match the names of the parameters.

<TemplatedTable Items="@pets">
 <TableHeader>
 <th>ID</th>
 <th>Name</th>
 <th>Species</th>
 </TableHeader>
 <RowTemplate>
 <td>@context.PetId</td>
 <td>@context.Name</td>
 <td>@context.Species</td>
 </RowTemplate>
</TemplatedTable>

Template context parameters

Component arguments of type RenderFragment<T> passed as elements have an implicit parameter named context, but you can change the parameter name using the Context attribute on the child element.

<TemplatedTable Items="@pets">
 <TableHeader>
 <th>ID</th>
 <th>Name</th>
 <th>Species</th>
 </TableHeader>
 <RowTemplate Context="pet">
 <td>@pet.PetId</td>
 <td>@pet.Name</td>
 <td>@pet.Species</td>
 </RowTemplate>
</TemplatedTable>

Alternatively, you can specify the Context attribute on the component element (e.g., <TemplatedTable Context="pet">). The specified Context attribute applies to all specified template parameters. This can be useful when you want to specify the content parameter name for implicit child content (without any wrapping child element).

Generic-typed components

Templated components are often generically typed. For example, a generic ListView component could be used to render IEnumerable<T> values. To define a generic component use the new @typeparam directive to specify type parameters.

GenericComponent.cshtml

@typeparam TItem

@foreach (var item in Items)
{
 @ItemTemplate(item)
}

@functions {
 [Parameter] RenderFragment<TItem> ItemTemplate { get; set; }
 [Parameter] IReadOnlyList<TItem> Items { get; set; }
}

When using generic-typed components the type parameter will be inferred if possible. Otherwise, it must be explicitly specified using an attribute that matches the name of the type parameter:

<GenericComponent Items="@pets" TItem="Pet">
 ...
</GenericComponent>

Razor templates

Render fragments can be defined using Razor template syntax. Razor templates are a way to define a UI snippet. They look like the following:

@<tag>...<tag>

You can now use Razor templates to define RenderFragment and RenderFragment<T> values like this:

@{ 
 RenderFragment template = @<p>The time is @DateTime.Now.</p>;
 RenderFragment<Pet> petTemplate = (pet) => @<p>Your pet's name is @pet.Name.</p>
}

Render fragments defined using Razor templates can be passed as arguments to templated components or rendered directly. For example, you can render the previous templates directly like this:

@template

@petTemplate(new Pet { Name = "Fido" })

Use server-side Blazor with the Azure SignalR Service

In the previous Blazor release we added support for running Blazor on the server where UI interactions and DOM updates are handled over a SignalR connection. In this release we refactored the server-side Blazor support to enable using server-side Blazor with the Azure SignalR Service. The Azure SignalR Service handles connection scale out for SignalR based apps, scaling up to handle thousands of persistent connections so that you don’t have to.

To use the Azure SignalR Service with a server-side Blazor application:

  1. Create a new server-side Blazor app.

    dotnet new blazorserverside -o BlazorServerSideApp1
    
  2. Add the Azure SignalR Server SDK to the server project.

    dotnet add BlazorServerSideApp1/BlazorServerSideApp1.Server package Microsoft.Azure.SignalR
    
  3. Create an Azure SignalR Service resource for your app and copy the primary connection string.

  4. Add a UserSecretsId property to the BlazorServerSideApp1.Server.csproj project file.

    <PropertyGroup>
 <UserSecretsId>BlazorServerSideApp1.Server.UserSecretsId</UserSecretsId>
    <PropertyGroup>
    
  5. Configure the connection string as a user secret for your app.

    dotnet user-secret -p BlazorServerSideApp1/BlazorServerSideApp1.Server set Azure:SignalR:ConnectionString <Your-Connection-String>
    

    NOTE: When deploying the app you’ll need to configure the Azure SignalR Service connection string in the target environment. For example, in Azure App Service configure the connection string using an app setting.

  6. In the Startup class for the server project, replace the call to app.UseServerSideBlazor<App.Startup>() with the following code:

    app.UseAzureSignalR(route => route.MapHub<BlazorHub>(BlazorHub.DefaultPath));
    app.UseBlazor<App.Startup>();
    
  7. Run the app.

    If you look at the network trace for the app in the browser dev tools you see that the SignalR traffic is now being routed through the Azure SignalR Service. Congratulations!

Razor Components to ship with ASP.NET Core in .NET Core 3.0

We announced last month at .NET Conf that we’ve decided to move forward with shipping the Blazor server-side model as part of ASP.NET Core in .NET Core 3.0. About half of Blazor users have indicated they would use the Blazor server-side model, and shipping it in .NET Core 3.0 will make it available for production use. As part of integrating the Blazor component model into the ASP.NET Core we’ve decided to give it a new name to differentiate it from the ability to run .NET in the browser: Razor Components. We are now working towards shipping Razor Components and the editing in .NET Core 3.0. This includes integrating Razor Components into ASP.NET Core so that it can be used from MVC. We expect to have a preview of this support early next year after the ASP.NET Core 2.2 release has wrapped up.

Our primary goal remains to ship support for running Blazor client-side in the browser. Work on running Blazor client-side on WebAssembly will continue in parallel with the Razor Components work, although it will remain experimental for a while longer while we work through the issues of running .NET on WebAssembly. We will however keep the component model the same regardless of whether you are running on the server or the client. You can switch your Blazor app to run on the client or the server by changing a single line of code. See the Blazor .NET Conf talk to see this in action and to learn more about our plans for Razor Components:

Give feedback

We hope you enjoy this latest preview release of Blazor. As with previous releases, your feedback is important to us. If you run into issues or have questions while trying out Blazor, 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 let us know what you think by taking our in-product survey. 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.5.0 experimental release now available

Blazor 0.5.0 is now available! This release explores scenarios where Blazor is run in a separate process from the rendering process. Specifically, Blazor 0.5.0 enables the option to run Blazor on the server and then handle all UI interactions over a SignalR connection. This release also adds some very early support for debugging your Blazor .NET code in the browser!

New features in this release:

  • Server-side Blazor
  • Startup model aligned with ASP.NET Core
  • JavaScript interop improvements
    • Removed requirement to preregister JavaScript methods
    • Invoke .NET instance method from JavaScript
    • Pass .NET objects to JavaScript by reference
  • Add Blazor to any HTML file using a normal script tag
  • Render raw HTML
  • New component parameter snippet
  • Early support for in-browser debugging

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

Get Blazor 0.5.0

To get setup with Blazor 0.5.0:

  1. Install the .NET Core 2.1 SDK (2.1.300 or later).
  2. Install Visual Studio 2017 (15.7 or later) with the ASP.NET and web development workload selected.
  3. Install the latest Blazor Language Services extension from the Visual Studio Marketplace.
  4. 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.5.0

To upgrade an existing Blazor project from 0.4.0 to 0.5.0:

  • Install all of the required bits listed above.
  • Update your Blazor package and .NET CLI tool references to 0.5.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.5.0" />
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.5.0" />
 <DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.5.0" />
    </ItemGroup>
    
    </Project>
    
  • Update index.html to replace the blazor-boot script tag with a normal script tag that references _framework/blazor.webassembly.js..

    index.html

    <!DOCTYPE html>
    <html>
    <head>
 <meta charset="utf-8" />
 <meta name="viewport" content="width=device-width">
 <title>BlazorApp1</title>
 <base href="/" />
 <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
 <link href="css/site.css" rel="stylesheet" />
    </head>
    <body>
 <app>Loading...</app> 
 <script src="_framework/blazor.webassembly.js"></script>
    </body>
    </html>
    
  • Add a Startup class to your project and update Program.cs to setup the Blazor host.

    Program.cs

    @using using Microsoft.AspNetCore.Blazor.Hosting;
    
    public class Program
    {
 public static void Main(string[] args)
 {
 CreateHostBuilder(args).Build().Run();
 }
    
 public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
 BlazorWebAssemblyHost.CreateDefaultBuilder()
 .UseBlazorStartup<Startup>();
    }
    

    Startup.cs

    using Microsoft.AspNetCore.Blazor.Builder;
    using Microsoft.Extensions.DependencyInjection;
    
    public class Startup
    {
 public void ConfigureServices(IServiceCollection services)
 {
 }
    
 public void Configure(IBlazorApplicationBuilder app)
 {
 app.AddComponent<App>("app");
 }
    }
    
  • Update to the new JavaScript interop model. The changes to the JavaScript interop model are covered in the “JavaScript interop changes” section below.

What is server-side Blazor?

Blazor is principally a client-side web framework intended to run in a browser where the component logic and DOM interactions all happen in the same process.

Blazor client-side

However, Blazor was built to be flexible enough to handle scenarios where the Blazor app runs apart from the rendering process. For example, you might run Blazor in a Web Worker thread so that it runs separately from the UI thread. Events would get pushed from the UI thread to the Blazor worker thread, and Blazor would push UI updates to the UI thread as needed. This scenario isn’t supported yet, but it’s something Blazor was designed to handle.

Blazor web worker

Another potential use case for running Blazor in a separate process is writing desktop applications with Electron. The Blazor component logic could run in a normal .NET Core process, while the UI updates are handled in the Electron rendering process.

Blazor Electron

We have a working prototype that you can try out of using Blazor with Electron in this way.

Blazor 0.5.0 takes the out-of-process model for Blazor and streeeetches it over a network connection so that you can run Blazor on the server. With Blazor 0.5.0 you can run your Blazor components server-side on .NET Core while UI updates, event handling, and JavaScript interop calls are handled over a SignalR connection.

Blazor server-side

There are a number of benefits to running Blazor on the server in this way:

  • You can still write your entire app with .NET and C# using the Blazor component model.
  • Your app still has a rich interactive feel and avoids unnecessary page refreshes.
  • Your app download size is significantly smaller and the initial app load time is much faster.
  • Your Blazor component logic can take full advantage of server capabilities including using any .NET Core compatible APIs.
  • Because you’re running on .NET Core on the server existing .NET tooling, like debugging, just works.
  • Works with thin clients (ex browsers that don’t support WebAssembly, resource constrained devices, etc.).

Of course there are some downsides too:

  • Latency: every user interaction now involves a network hop.
  • No offline support: if the client connection goes down the app stops working.
  • Scalability: the server must manage multiple client connections and handle client state.

While our primary goal for Blazor remains to provide a rich client-side web development experience, enough developers expressed interest in the server-side model that we decided to experiment with it. And because server-side Blazor uses the exact same component model as running Blazor on the client, it is well aligned with our client-side efforts.

Get started with server-side Blazor

To create your first server-side Blazor app use the new server-side Blazor project template.

dotnet new blazorserverside -o BlazorApp1

Build and run the app from the BlazorApp1.Server directory to see it in action:

cd BlazorApp1.Server
dotnet run

You can also create a server-side Blazor app from Visual Studio.

Blazor server-side template

When you run the Blazor server-side app it looks like a normal Blazor app, but the download size is significantly smaller (under 100KB), because there is no need to download a .NET runtime, the app assembly, or any of its dependencies.

Blazor server-side running app

Blazor server-side download size

You’re also free to run the app under the debugger (F5) as all the .NET logic is running on .NET Core on the server.

The template creates a solution with two projects: an ASP.NET Core host project, and a project for your server-side Blazor app. In a future release we hope to merge these two projects into one, but for now the separation is necessary due to the differences in the Blazor compilation model.

The server-side Blazor app contains all of your component logic, but instead of running client-side in the browser the logic is run server-side in the ASP.NET Core host application. The Blazor app uses a different bootstrapping script (blazor.server.js instead of blazor.webassembly.js), which establishes a SignalR connection with the server and handles applying UI updates and forwarding events. Otherwise the Blazor programming model is the same.

The ASP.NET Core app hosts the Blazor app and sets up the SignalR endpoint. Because the Blazor app runs on the server, the event handling logic can directly access server resources and services. For example, the FetchData page no longer needs to issue an HTTP request to retrieve the weather forecast data, but can instead use a service configured on the server:

protected override async Task OnParametersSetAsync()
{
 forecasts = await ForecastService.GetForecastAsync(StartDate);
}

The WeatherForecastService in the template generates the forecast data in memory, but it could just as easily pull the data from a database using EF Core, or use other server resources.

Startup model

All Blazor projects in 0.5.0 now use a new startup model that is similar to the startup model in ASP.NET Core. Each Blazor project has a Startup class with a ConfigureServices method for configuring the services for your Blazor app, and a Configure method for configuring the root components of the application.

public class Startup
{
 public void ConfigureServices(IServiceCollection services)
 {
 }

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

The app entry point in Program.cs creates a Blazor host that is configured to use the Startup class.

public class Program
{
 public static void Main(string[] args)
 {
 CreateHostBuilder(args).Build().Run();
 }

 public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
 BlazorWebAssemblyHost.CreateDefaultBuilder()
 .UseBlazorStartup<Startup>();
}

In server-side Blazor apps the entry point comes from the host ASP.NET Core app, which references the Blazor Startup class to both add the server-side Blazor services and to add the Blazor app to the request handling pipeline:

public class Startup
{
 public void ConfigureServices(IServiceCollection services)
 {
 ...
 services.AddServerSideBlazor<App.Startup>();
 }

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
 ...
 app.UseServerSideBlazor<App.Startup>();
 }
}

While the server-side Blazor project may also have a Program class, it is not used when running on the server. However it would be used if you switched to client-side (WebAssembly) execution just by changing the <script> tag in index.html to load blazor.webassembly.js instead of blazor.server.js.

The Blazor app and the ASP.NET Core app share the same service provider. Services added in either ConfigureServices methods are visible to both apps. Scoped services are scoped to the client connection.

State management

When running Blazor on the server the UI state is all managed server-side. The initial state is established with the client connects to the server and is maintained in memory as the user interacts with the app. If the client connection is lost then the server-side app state will be lost, unless it is otherwise persisted and restored by the app. For example, you could maintain your app state in an AppState class that you serialize into session state periodically and then initialize the app state from session state when it is available. While this process is currently completely manual in the future we hope to make server-side state management easier and more integrated.

JavaScript interop changes

You can use JavaScript interop libraries when using server-side Blazor. The Blazor runtime handles sending the JavaScript calls to the browser and then sending the results back to the server. To accommodate out-of-process usage of JavaScript interop the JavaScript interop model was significantly revised and expanded upon in this release.

Calling JavaScript from .NET

To call into JavaScript from .NET use the new IJSRuntime abstraction, which is accessible from JSRuntime.Current. The InvokeAsync<T> method on IJSRuntime takes an identifier for the JavaScript function you wish to invoke along with any number of JSON serializable arguments. The function identifier is relative to the global scope (window). For example, if you wish to call window.someScope.someFunction then the identifier would be someScope.someFunction. There is no longer any need to register the function before it can be called. The return type T must also be JSON serializable.

exampleJsInterop.js

window.exampleJsFunctions = {
 showPrompt: function (message) {
 return prompt(message, 'Type anything here');
 }
};

ExampleJsInterop.cs

using Microsoft.JSInterop;

public class ExampleJsInterop
{
 public static Task<string> Prompt(string message)
 {
 // Implemented in exampleJsInterop.js
 return JSRuntime.Current.InvokeAsync<string>(
 "exampleJsFunctions.showPrompt",
 message);
 }
}

The IJSRuntime abstraction is async to allow for out-of-process scenarios. However, if you are running in-process and want to invoke a JavaScript function synchronously you can downcast to IJSInProcessRuntime and call Invoke<T> instead. We recommend that most JavaScript interop libraries should use the async APIs to ensure the libraries can be used in all Blazor scenarios, client-side or server-side.

Calling .NET from JavaScript

To invoke a static .NET method from JavaScript use the DotNet.invokeMethod or DotNet.invokeMethodAsync functions passing in the identifier of the static method you wish to call, the name of the assembly containing the function, and any arguments. Again, the async version is required to support out-of-process scenarios. To be invokable from JavaScript, the .NET method must be public, static, and attributed with [JSInvokable]. By default, the method identifier is the method name, but you can specify a different identifier using the JSInvokableAttribute constructor. Calling open generic methods is not currently supported.

JavaScriptInteroperable.cs

public class JavaScriptInvokable
{
 [JSInvokable]
 public static Task<int[]> ReturnArrayAsync()
 {
 return Task.FromResult(new int[] { 1, 2, 3 });
 }
}

dotnetInterop.js

DotNet.invokeMethodAsync(assemblyName, 'ReturnArrayAsync').then(data => ...)

New in Blazor 0.5.0, you can also call .NET instance methods from JavaScript. To invoke a .NET instance method from JavaScript you first pass the .NET instance to JavaScript by wrapping it in a DotNetObjectRef instance. The .NET instance will then be passed by reference to JavaScript and you can invoke .NET instance methods on the instance using the invokeMethod or invokeMethodAsync functions. The .NET instance can also be passed as an argument when invoking other .NET methods from JavaScript.

ExampleJsInterop.cs

public class ExampleJsInterop
{
 public static Task SayHello(string name)
 {
 return JSRuntime.Current.InvokeAsync<object>(
 "exampleJsFunctions.sayHello", 
 new DotNetObjectRef(new HelloHelper(name)));
 }
}

exampleJsInterop.js

window.exampleJsFunctions = {
 sayHello: function (dotnetHelper) {
 return dotnetHelper.invokeMethodAsync('SayHello')
 .then(r => console.log(r));
 }
};

HelloHelper.cs

public class HelloHelper
{
 public HelloHelper(string name)
 {
 Name = name;
 }

 public string Name { get; set; }

 [JSInvokable]
 public string SayHello() => $"Hello, {Name}!";
}

Output

Hello, Blazor!

Add Blazor to any HTML file

In previous Blazor releases the project build modified index.html to replace the blazor-boot script tag with a real script tag that handled downloading the starting up the runtime. This setup made it difficult to use Blazor in arbitrary HTML files.

In Blazor 0.5.0 this mechanism has been replaced. For client-side projects add a script tag that references the _framework/blazor.webassembly.js script (which is generated as part of the build). For server-side projects you reference _framework/blazor.server.js. You can add this script to any HTML file, including server generated content.

For example, instead of using the static index.html file from the Blazor client project you could add a Razor Page to your ASP.NET Core host project and then add the Blazor script tag there along with any server-side rendering logic.

Render raw HTML

Blazor normally renders strings using DOM text nodes, which means that any markup they may contain will be ignored and treated as literal text. This new feature lets you render special MarkupString values that will be parsed as HTML or SVG and then inserted into the DOM.

WARNING: Rendering raw HTML constructed from any untrusted source is a major security risk!

Use the MarkupString type to add blocks of static HTML content.

@((MarkupString)myMarkup)

@functions {
 string myMarkup = "<p class='markup'>This is a <em>markup string</em>.</p>";
}

Component parameter snippet

Thanks to a community contribution from Benjamin Vertonghen (vertonghenb) we now have a Visual Studio snippet for adding component parameters. Just type para and then hit Tab twice to add a parameter to your component.

Debugging

Blazor 0.5.0 introduces some very basic debugging support in Chrome for client-side Blazor apps running on WebAssembly. While this initial debugging support is very limited and unpolished it does show the basic debugging infrastructure coming together.

To debug your client-side Blazor app in Chrome:

  • Build a Blazor app in Debug configuration (the default for non-published apps)
  • Run the Blazor app in Chrome
  • With the keyboard focus on the app (not in the dev tools, which you should probably close as it’s less confusing that way), press the following Blazor specific hotkey:
    • Shift+Alt+D on Windows/Linux
    • Shift+Cmd+D on macOS

You need to run Chrome with remote debugging enabled to debug your Blazor app. If you don’t, you will get an error page with instructions for running Chrome with the debugging port open so that the Blazor debugging proxy can connect to it. You will need to close all Chrome instances and then restart Chrome as instructed.

Blazor debugging error page

Once you have Chrome running with remote debugging enabled, hitting the debugging hotkey will open a new debugger tab. After a brief moment the Sources tab will show a list of the .NET assemblies in the app. You can expand each assembly and find the .cs/.cshtml source files you want to debug. You can then set breakpoints, switch back to your app’s tab, and cause the breakpoints to be hit. You can then single-step (F10) or resume (F8).

Blazor debugging

How does this work? Blazor provides a debugging proxy that implements the Chrome DevTools Protocol and augments the protocol with .NET specific information. When you hit the debugging hotkey, Blazor points the Chrome DevTools at the proxy, which in turn connects to the browser window you are trying to debug (hence the need for enabling remote debugging).

You might be wondering why we don’t just use browser source maps. Source maps allow the browser to map compiled files back to their original source files. However, Blazor does not map C# directly to JS/WASM (at least not yet). Instead, Blazor does IL interpretation within the browser, so source maps are not relevant.

NOTE: The debugger capabilities are very limited. You can currently only:

  • Single-step through the current method (F10) or resume (F8)
  • In the Locals display, observe the values of any local variables of type int/string/bool
  • See the call stack, including call chains that go from JavaScript into .NET and vice-versa

That’s it! You cannot step into child methods (i.e., F11), observe the values of any locals that aren’t an int/string/bool, observe the values of any class properties or fields, hover over variables to see their values, evaluate expressions in the console, step across async calls, or do basically anything else.

Our friends on the Mono team have done some great work tackling some of the hardest technical problems to enable source viewing, breakpoints, and stepping, but please be patient as completing the long tail of debugger features remains a significant ongoing task.

Community

The Blazor community has produced a number of great Blazor extensions, libraries, sample apps, articles, and videos.
You can find out about these community projects on the Blazor Community page. Recent additions include a Blazor SignalR client, Redux integration, and various community authored samples (Toss, Clock, Chat). If you have a Blazor related project that you’d like to share on the community page let us know by sending us a pull request to the Blazor.Docs repo.

Give feedback

We hope you enjoy this latest preview release of Blazor. As with previous releases, your feedback is important to us. 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. 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.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!