post

ASP.NET Core and Blazor updates in .NET Core 3.0 Preview 6

Daniel Roth

Daniel

.NET Core 3.0 Preview 6 is now available and it includes a bunch of new updates to ASP.NET Core and Blazor.

Here’s the list of what’s new in this preview:

  • New Razor features: @attribute, @code, @key, @namespace, markup in @functions
  • Blazor directive attributes
  • Authentication & authorization support for Blazor apps
  • Static assets in Razor class libraries
  • Json.NET no longer referenced in project templates
  • Certificate and Kerberos Authentication
  • SignalR Auto-reconnect
  • Managed gRPC Client
  • gRPC Client Factory
  • gRPC Interceptors

Please see the release notes for additional details and known issues.

Get started

To get started with ASP.NET Core in .NET Core 3.0 Preview 6 install the .NET Core 3.0 Preview 6 SDK

If you’re on Windows using Visual Studio, you also need to install the latest preview of Visual Studio 2019.

For the latest client-side Blazor templates also install the latest Blazor extension from the Visual Studio Marketplace.

Upgrade an existing project

To upgrade an existing an ASP.NET Core app to .NET Core 3.0 Preview 6, follow the migrations steps in the ASP.NET Core docs.

Please also see the full list of breaking changes in ASP.NET Core 3.0.

To upgrade an existing ASP.NET Core 3.0 Preview 5 project to Preview 6:

  • Update Microsoft.AspNetCore.* package references to 3.0.0-preview6.19307.2
  • In Blazor apps:
    • Rename @functions to @code
    • Update Blazor specific attributes and event handlers to use the new directive attribute syntax (see below)
    • Remove any call to app.UseBlazor<TStartup>() and instead add a call to app.UseClientSideBlazorFiles<TStartup>() before the call to app.UseRouting(). Also add a call to endpoints.MapFallbackToClientSideBlazor<TStartup>("index.html") in the call to app.UseEndpoints().

Before

app.UseRouting(); app.UseEndpoints(endpoints =>
{ endpoints.MapDefaultControllerRoute();
}); app.UseBlazor<Client.Startup>();

After

app.UseClientSideBlazorFiles<Client.Startup>(); app.UseRouting(); app.UseEndpoints(endpoints =>
{ endpoints.MapDefaultControllerRoute(); endpoints.MapFallbackToClientSideBlazor<Client.Startup>("index.html");
});

New Razor features

We’ve added support for the following new Razor language features in this release.

@attribute

The new @attribute directive adds the specified attribute to the generated class.

@attribute [Authorize]

@code

The new @code directive is used in .razor files (not supported in .cshtml files) to specify a code block to add to the generated class as additional members. It’s equivalent to @functions, but now with a better name.

@code { int currentCount = 0; void IncrementCount() { currentCount++; }
}

@key

The new @key directive attribute is used in .razor files to specify a value (any object or unique identifier) that the Blazor diffing algorithm can use to preserve elements or components in a list.

@foreach (var flight in Flights) { }

To understand why this feature is needed, consider rendering a list of cards with flight details without this feature:

@foreach (var flight in Flights) { }

If you add a new flight into the middle of the Flights list the existing DetailsCard instances should remain unaffected and one new DetailsCard should be inserted into the rendered output.

To visualize this, if Flights previously contained [F0, F1, F2], then this is the before state:

  • DetailsCard0, with Flight=F0
  • DetailsCard1, with Flight=F1
  • DetailsCard2, with Flight=F2

… and this is the desired after state, given we insert a new item FNew at index 1:

  • DetailsCard0, with Flight=F0
  • DetailsCardNew, with Flight=FNew
  • DetailsCard1, with Flight=F1
  • DetailsCard2, with Flight=F2

However, the actual after state this:

  • DetailsCard0, with Flight=F0
  • DetailsCard1, with Flight=FNew
  • DetailsCard2, with Flight=F1
  • DetailsCardNew, with Flight=F2

The system has no way to know that DetailsCard2 or DetailsCard3 should preserve their associations with their older Flight instances, so it just re-associates them with whatever Flight matches their position in the list. As a result, DetailsCard1 and DetailsCard2 rebuild themselves completely using new data, which is wasteful and sometimes even leads to user-visible problems (e.g., input focus is unexpectedly lost).

By adding keys using @key the diffing algorithm can associate the old and new elements or components.

@namespace

Specifies the namespace for the generated class or the namespace prefix when used in an _Imports.razor file. The @namespace directive works today in pages and views (.cshtml) apps, but is now it is also supported with components (.razor).

@namespace MyNamespace

Markup in @functions and local functions

In views and pages (.cshtml files) you can now add markup inside of methods in the @functions block and in local functions.

@{ GreetPerson(person); } @functions { void GreetPerson(Person person) { <p>Hello, <em>@person.Name!</em></p> }
}

Blazor directive attributes

Blazor uses a variety of attributes for influencing how components get compiled (e.g. ref, bind, event handlers, etc.). These attributes have been added organically to Blazor over time and use different syntaxes. In this Blazor release we’ve standardized on a common syntax for directive attributes. This makes the Razor syntax used by Blazor more consistent and predictable. It also paves the way for future extensibility.

Directive attributes all follow the following syntax where the values in parenthesis are optional:

@directive(-suffix(:name))(="value")

Some valid examples:

<!-- directive -->
...
<!-- directive with key/value arg-->
...
<!-- directive with suffix -->
<!-- directive with suffix and key/value arg-->

All of the Blazor built-in directive attributes have been updated to use this new syntax as described below.

Event handlers

Specifying event handlers in Blazor now uses the new directive attribute syntax instead of the normal HTML syntax. The syntax is similar to the HTML syntax, but now with a leading @ character. This makes C# event handlers distinct from JS event handlers.

<button @onclick="@Clicked">Click me!</button>

When specifying a delegate for C# event handler the @ prefix is currently still required on the attribute value, but we expect to remove this requirement in a future update.

In the future we also expect to use the directive attribute syntax to support additional features for event handlers. For example, stopping event propagation will likely look something like this (not implemented yet, but it gives you an idea of scenarios now enabled by directive attributes):

<button @onclick="Clicked" @onclick:stopPropagation>Click me!</button>

Bind

<input @bind="myValue">...</input>
<input @bind="myValue" @bind:format="mm/dd">...</input>
<MyButton @bind-Value="myValue">...</MyButton>

Key

...

Ref

<button @ref="myButton">...</button>

Authentication & authorization support for Blazor apps

Blazor now has built-in support for handling authentication and authorization. The server-side Blazor template now supports options for enabling all of the standard authentication configurations using ASP.NET Core Identity, Azure AD, and Azure AD B2C. We haven’t updated the Blazor WebAssembly templates to support these options yet, but we plan to do so after .NET Core 3.0 has shipped.

To create a new Blazor app with authentication enabled:

  1. Create a new Blazor (server-side) project and select the link to change the authentication configuration. For example, select “Individual User Accounts” and “Store user accounts in-app” to use Blazor with ASP.NET Core Identity:

    Blazor authentication

  2. Run the app. The app includes links in the top row for registering as a new user and logging in.

    Blazor authentication running

  3. Select the Register link to register a new user.

    Blazor authentication register

  4. Select “Apply Migrations” to apply the ASP.NET Core Identity migrations to the database.

    Blazor authentication apply migrations

  5. You should now be logged in.

    Blazor authentication logged in

  6. Select your user name to edit your user profile.

    Blazor authentication edit profile

In the Blazor app, authentication and authorization are configured in the Startup class using the standard ASP.NET Core middleware.

app.UseRouting(); app.UseAuthentication();
app.UseAuthorization(); app.UseEndpoints(endpoints =>
{ endpoints.MapControllers(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host");
});

When using ASP.NET Core Identity all of the identity related UI concerns are handled by the framework provided default identity UI.

services.AddDefaultIdentity<IdentityUser>() .AddEntityFrameworkStores<ApplicationDbContext>();

The authentication related links in top row of the app are rendered using the new built-in AuthorizeView component, which displays different content depending on the authentication state.

LoginDisplay.razor

<AuthorizeView> <Authorized> <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a> <a href="Identity/Account/LogOut">Log out</a> </Authorized> <NotAuthorized> <a href="Identity/Account/Register">Register</a> <a href="Identity/Account/Login">Log in</a> </NotAuthorized>
</AuthorizeView>

The AuthorizeView component will only display its child content when the user is authorized. Alternatively, the AuthorizeView takes parameters for specifying different templates when the user is Authorized, NotAuthorized, or Authorizing. The current authentication state is passed to these templates through the implicit context parameter. You can also specify specific roles or an authorization policy on the AuthorizeView that the user must satisfy to see the authorized view.

To authorize access to specific pages in a Blazor app, use the normal [Authorize] attribute. You can apply the [Authorize] attribute to a component using the new @attribute directive.

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@page "/fetchdata"

To specify what content to display on a page that requires authorization when the user isn’t authorized or is still in the processing of authorizing, use the NotAuthorizedContent and AuthorizingContent parameters on the Router component. These Router parameters are only support in client-side Blazor for this release, but they will be enabled for server-side Blazor in a future update.

The new AuthenticationStateProvider service make the authentication state available to Blazor apps in a uniform way whether they run on the server or client-side in the browser. In server-side Blazor apps the AuthenticationStateProvider surfaces the user from the HttpContext that established the connection to the server. Client-side Blazor apps can configure a custom AuthenticationStateProvider as appropriate for that application. For example, it might retrieve the current user information by querying an endpoint on the server.

The authentication state is made available to the app as a cascading value (Task<AuthenticationState>) using the CascadingAuthenticationState component. This cascading value is then used by the AuthorizeView and Router components to authorize access to specific parts of the UI.

App.razor

<CascadingAuthenticationState> <Router AppAssembly="typeof(Startup).Assembly"> <NotFoundContent> <p>Sorry, there's nothing at this address.</p> </NotFoundContent> </Router>
</CascadingAuthenticationState>

Static assets in Razor class libraries

Razor class libraries can now include static assets like JavaScript, CSS, and images. These static assets can then be included in ASP.NET Core apps by referencing the Razor class library project or via a package reference.

To include static assets in a Razor class library add a wwwroot folder to the Razor class library and include any required files in that folder.

When a Razor class library with static assets is referenced either as a project reference or as a package, the static assets from the library are made available to the app under the path prefix _content/{LIBRARY NAME}/. The static assets stay in their original folders and any changes to the content of static assets in the Razor class libraries are reflected in the app without rebuilding.

When the app is published, the companion assets from all referenced Razor class libraries are copied into the wwwroot folder of the published app under the same prefix.

To try out using static assets from a Razor class library:

  1. Create a default ASP.NET Core Web App.

    dotnet new webapp -o WebApp1
    
  2. Create a Razor class library and reference it from the web app.

    dotnet new razorclasslib -o RazorLib1
    dotnet add WebApp1 reference RazorLib1
    
  3. Add a wwwroot folder to the Razor class library and include a JavaScript file that logs a simple message to the console.

    cd RazorLib1
    mkdir wwwroot
    

    hello.js

    console.log("Hello from RazorLib1!");
    
  4. Reference the script file from Index.cshtml in the web app.

    http://_content/RazorLib1/hello.js
    
  5. Run the app and look for the output in the browser console.

    Hello from RazorLib1!
    

Projects now use System.Text.Json by default

New ASP.NET Core projects will now use System.Text.Json for JSON handling by default. In this release we removed Json.NET (Newtonsoft.Json) from the project templates. To enable support for using Json.NET, add the Microsoft.AspNetCore.Mvc.NewtonsoftJson package to your project and add a call to AddNewtonsoftJson() following code in your Startup.ConfigureServices method. For example:

services.AddMvc() .AddNewtonsoftJson();

Certificate and Kerberos authentication

Preview 6 brings Certificate and Kerberos authentication to ASP.NET Core.

Certificate authentication requires you to configure your server to accept certificates, and then add the authentication middleware in Startup.Configure and the certificate authentication service in Startup.ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{ services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(); // All the other service configuration.
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ app.UseAuthentication(); // All the other app configuration.
}

Options for certificate authentication include the ability to accept self-signed certificates, check for certificate revocation, and check that the proffered certificate has the right usage flags in it. A default user principal is constructed from the certificate properties, with an event that enables you to supplement or replace the principal. All the options, and instructions on how to configure common hosts for certificate authentication can be found in the documentation.

We’ve also extended “Windows Authentication” onto Linux and macOS. Previously this authentication type was limited to IIS and HttpSys, but now Kestrel has the ability to use Negotiate, Kerberos, and NTLM on Windows, Linux, and macOS for Windows domain joined hosts by using the Microsoft.AspNetCore.Authentication.Negotiate nuget package. As with the other authentication services you configure authentication app wide, then configure the service:

public void ConfigureServices(IServiceCollection services)
{ services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) .AddNegotiate();
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ app.UseAuthentication(); // All the other app configuration.
}

Your host must be configured correctly. Windows hosts must have SPNs added to the user account hosting the application. Linux and macOS machines must be joined to the domain, then SPNs must be created for the web process, as well as keytab files generated and configured on the host machine. Full instructions are given in the documentation.

SignalR Auto-reconnect

This preview release, available now via npm install @aspnet/signalr@next and in the .NET Core SignalR Client, includes a new automatic reconnection feature. With this release we’ve added the withAutomaticReconnect() method to the HubConnectionBuilder. By default, the client will try to reconnect immediately and after 2, 10, and 30 seconds. Enlisting in automatic reconnect is opt-in, but simple via this new method.

const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect() .build();

By passing an array of millisecond-based durations to the method, you can be very granular about how your reconnection attempts occur over time.

.withAutomaticReconnect([0, 3000, 5000, 10000, 15000, 30000])
//.withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior

Or you can pass in an implementation of a custom reconnect policy that gives you full control.

If the reconnection fails after the 30-second point (or whatever you’ve set as your maximum), the client presumes the connection is offline and stops trying to reconnect. During these reconnection attempts you’ll want to update your application UI to provide cues to the user that the reconnection is being attempted.

Reconnection Event Handlers

To make this easier, we’ve expanded the SignalR client API to include onreconnecting and onreconnected event handlers. The first of these handlers, onreconnecting, gives developers a good opportunity to disable UI or to let users know the app is offline.

connection.onreconnecting((error) => { const status = `Connection lost due to error "${error}". Reconnecting.`; document.getElementById("messageInput").disabled = true; document.getElementById("sendButton").disabled = true; document.getElementById("connectionStatus").innerText = status;
});

Likewise, the onreconnected handler gives developers an opportunity to update the UI once the connection is reestablished.

connection.onreconnected((connectionId) => { const status = `Connection reestablished. Connected.`; document.getElementById("messageInput").disabled = false; document.getElementById("sendButton").disabled = false; document.getElementById("connectionStatus").innerText = status;
});

Learn more about customizing and handling reconnection

Automatic reconnect has been partially documented already in the preview release. Check out the deeper docs on the topic, with more examples and details on usage, at https://aka.ms/signalr/auto-reconnect.

Managed gRPC Client

In prior previews, we relied on the Grpc.Core library for client support. The addition of HTTP/2 support in HttpClient in this preview has allowed us to introduce a fully managed gRPC client.

To begin using the new client, add a package reference to Grpc.Net.Client and then you can create a new client.

var httpClient = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };
var client = GrpcClient.Create<GreeterClient>(httpClient);

gRPC Client Factory

Building on the opinionated pattern we introduced in HttpClientFactory, we’ve added a gRPC client factory for creating gRPC client instances in your project. There are two flavors of the factory that we’ve added: Grpc.Net.ClientFactory and Grpc.AspNetCore.Server.ClientFactory.

The Grpc.Net.ClientFactory is designed for use in non-ASP.NET app models (such as Worker Services) that still use the Microsoft.Extensions.* primitives without a dependency on ASP.NET Core.

In applications that perform service-to-service communication, we often observe that most servers are also clients that consume other services. In these scenarios, we recommend the use of Grpc.AspNetCore.Server.ClientFactory which features automatic propagation of gRPC deadlines and cancellation tokens.

To use the client factory, add the appropriate package reference to your project (Grpc.AspNetCore.Server.Factory or Grpc.Net.ClientFactory) before adding the following code to ConfigureServices().

services .AddGrpcClient<GreeterClient>(options => { options.BaseAddress = new Uri("https://localhost:5001"); });

gRPC Interceptors

gRPC exposes a mechanism to intercept RPC invocations on both the client and the server. Interceptors can be used in conjunction with existing HTTP middleware. Unlike HTTP middleware, interceptors give you access to actual request/response objects before serialization (on the client) and after deserialization (on the server) and vice versa for the response. All middlewares run before interceptors on the request side and vice versa on the response side.

Client interceptors

When used in conjunction with the client factory, you can add a client interceptor as shown below.

services .AddGrpcClient<GreeterClient>(options => { options.BaseAddress = new Uri("https://localhost:5001"); }) .AddInterceptor<CallbackInterceptor>();

Server interceptors

Server interceptors can be registered in ConfigureServices() as shown below.

services .AddGrpc(options => { // This registers a global interceptor options.Interceptors.Add<MaxStreamingRequestTimeoutInterceptor>(TimeSpan.FromSeconds(30)); }) .AddServiceOptions<GreeterService>(options => { // This registers an interceptor for the Greeter service options.Interceptors.Add<UnaryCachingInterceptor>(); });

For examples on how to author an interceptors, take a look at these examples in the grpc-dotnet repo.

Give feedback

We hope you enjoy the new features in this preview release of ASP.NET Core and Blazor! Please let us know what you think by filing issues on GitHub.

Thanks for trying out ASP.NET Core and Blazor!

Daniel Roth
Daniel Roth

Principal Program Manager, ASP.NET

Follow Daniel   

post

What’s new in Azure SignalR 1.1.0 Preview 1

Avatar

Ken

We just shipped 1.1.0 Preview 1 of Azure SignalR Service SDK to support some new features in ASP.NET Core 3.0, including endpoint routing and server-side Blazor. Let’s take a look how you can use them in your Azure SignalR application.

Here is the list of what’s new in this release:

  • Endpoint routing support for ASP.NET Core 3
  • Use SignalR service in server-side Blazor apps
  • Server stickiness

Endpoint routing support for ASP.NET Core 3

For those who are using Azure SignalR, you should be familiar with AddAzureSignalR() and UseAzureSignalR(). These two methods are required if you want to switch your app server from self-hosted SignalR to use Azure SignalR.

A typical Azure SignalR application usually looks like this in Startup.cs (note where AddAzureSignalR() and UseAzureSignalR() are used):

public void ConfigureServices(IServiceCollection services)
{ ... services.AddSignalR() .AddAzureSignalR(); ...
} public void Configure(IApplicationBuilder app)
{ ... app.UseAzureSignalR(routes => { routes.MapHub<Chat>("/chat"); }); ...
}

ASP.NET Core 3.0 introduced a new endpoint routing support which allows routable things like MVC and SignalR to be mixed together in a unified UseEndpoints() interface.

For example, you can call MapGet() and MapHub() in a single UseEndpoints() call, like this:

app.UseEndpoints(routes =>
{ routes.MapGet("/foo", async context => { await context.Response.WriteAsync("bar"); }); routes.MapHub<Chat>("/chat");
});

This new syntax is also supported in the latest Azure SignalR SDK so you don’t need to use a separate UseAzureSignalR() to map hubs.

Now your Azure SignalR application looks like this:

public void ConfigureServices(IServiceCollection services)
{ ... services.AddSignalR() .AddAzureSignalR(); ...
} public void Configure(IApplicationBuilder app)
{ ... app.UseRouting(); app.UseEndpoints(routes => { routes.MapHub<Chat>("/chat"); }); ...
}

The only change you need to make is to call AddAzureSignalR() after AddSignalR().

This will be very useful in the case that SignalR is deeply integrated in your code base or the library you’re using. For example, when you’re using server-side Blazor.

Use SignalR service in server-side Blazor apps

Server-side Blazor is a new way to build interactive client-side web UI in ASP.NET Core 3. In server-side Blazor, UI updates are rendered at server side, then sent to browser through a SignalR connection. Since it uses SignalR, there is a natural need to use Azure SignalR service to handle the SignalR traffic so your application can easily scale.

blazor

If you look at some server-side Blazor code samples, you’ll see they have a call to MapBlazorHub() to setup the communication channel between client and server.

app.UseEndpoints(endpoints =>
{ ... endpoints.MapBlazorHub(); ...
});

The implementation of this method calls MapHub() to create a SignalR hub at server side. Before this release there is no way to change the implementation of MapBlazorHub() to use SignalR service. Now if you call AddAzureSignalR(), MapBlazorHub() will also use SignalR service to host the hub instead of hosting it on the server.

Please follow these steps to change your server-side Blazor app to use SignalR service:

  1. Open your Startup.cs, add services.AddSignalR().AddAzureSignalR() in ConfigureServices().
  2. Create a new SignalR service instance.
  3. Get connection string and set it to environment variable Azure:SignalR:ConnectionString.

Then run your app you’ll see the WebSocket connection is going through SignalR service.

Check out this repo for a complete code sample.

Server stickiness

The typical connection flow when using SignalR service is that client first negotiates with app server to get the url of SignalR service, then service routes client to app server.

When you have multiple app servers, there is no guarantee that two servers (the one who does negotiation and the one who gets the hub invocation) will be the same one.

We hear a lot of customers asking about whether it’s possible to make the two servers the same one so they can share some states between negotiation and hub invocation. In this release we have added a new “server sticky mode” to support this scenario.

To enable this, you just need to set ServerStickyMode to Required in AddAzureSignalR():

services.AddSignalR().AddAzureSignalR(options => { options.ServerStickyMode = ServerStickyMode.Required;
});

Now for any connection, SignalR service will guarantee negotiation and hub invocation go to the same app server (called “server sticky”).

This feature is very useful when you have client state information maintained locally on the app server. For example, when using server-side Blazor, UI state is maintained at server side so you want all client requests go to the same server including the SignalR connection. So you need to set server sticky mode to Required when using server-side Blazor together with SignalR service.

Please note in this mode, there may be additional cost for the service to route connection to the right app server. So there may be some negative impact in message latency. If you don’t want the performance penalty, there is another Preferred mode you can use. In this mode stickiness is not always guaranteed (only when there is no additional cost to do the routing). But you can still gain some performance benefits as message delivery is more efficient if sender and receiver are on the same app server. Also when sticky mode is enabled, service won’t balance connections between app servers (by default SignalR service balances the traffic by routing to a server with least connections). So we recommend to set sticky mode to Disabled (this is also the default value) and only enable it when there is a need.

You can refer to this doc for more details about server sticky mode.

Avatar
Ken Chen

Principal Software Engineering Manager

Follow Ken   

post

ASP.NET Core updates in .NET Core 3.0 Preview 5

Avatar

.NET Core 3.0 Preview 5 is now available. This iteration was brief for the team and primarily includes bug fixes and improvements to the more significant updates in Preview 4. This post summarizes the important points in this release.

Please see the release notes for additional details and known issues.

Get started

To get started with ASP.NET Core in .NET Core 3.0 Preview 5 install the .NET Core 3.0 Preview 5 SDK. If you’re on Windows using Visual Studio, you also need to install the latest preview of Visual Studio.

Upgrade an existing project

To upgrade an existing an ASP.NET Core app (including Blazor apps) to .NET Core 3.0 Preview 5, follow the migrations steps in the ASP.NET Core docs. Please also see the full list of breaking changes in ASP.NET Core 3.0.

To upgrade an existing ASP.NET Core 3.0 Preview 4 project to Preview 5:

  • Update Microsoft.AspNetCore.* package references to 3.0.0-preview5-19227-01
  • Update Microsoft.Extensions.* package references to 3.0.0-preview5.19227.01

That’s it! You should be good to go with this latest preview release.

New JSON Serialization

In 3.0-preview5, ASP.NET Core MVC adds supports for reading and writing JSON using System.Text.Json. The System.Text.Json serializer can read and write JSON asynchronously, and is optimized for UTF-8 text making it ideal for REST APIs and backend applications.

This is available for you to try out in Preview 5, but is not yet the default in the templates. You can use the new serializer by removing the call to add Newtonsoft.Json formatters:

public void ConfigureServices(IServiceCollection services)
{ ... services.AddControllers() .AddNewtonsoftJson() ...
}

In the future this will be default for all new ASP.NET Core applications. We hope that you will try it in these earlier previews and log any issues you find here.

We used this WeatherForecast model when we profiled JSON read/writer performance using Newtonsoft.Json, our previous serializer.

public class WeatherForecast
{ public DateTime Date { get; set; } public int TemperatureC { get; set; } public string Summary { get; set; }
}

JSON deserialization (input)

Description RPS CPU (%) Memory (MB)
Newtonsoft.Json – 500 bytes 136,435 95 172
System.Text.Json – 500 bytes 167,861 94 169
Newtonsoft.Json – 2.4 kbytes 97,137 97 174
System.Text.Json – 2.4 kbytes 132,026 96 169
Newtonsoft.Json – 40 kbytes 7,712 88 212
System.Text.Json – 40 kbytes 16,625 96 193

JSON serialization (output)

Description RPS CPU (%) Memory (MB)
Newtonsoft.Json – 500 bytes 120,273 94 174
System.Text.Json – 500 bytes 145,631 94 173
Newtonsoft.Json – 8 Kbytes 35,408 98 187
System.Text.Json – 8 Kbytes 56,424 97 184
Newtonsoft.Json – 40 Kbytes 8,416 99 202
System.Text.Json – 40 Kbytes 14,848 98 197

For the most common payload sizes, System.Text.Json offers about 20% throughput increase during input and output formatting with a smaller memory footprint.

Options for the serializer can be configured using MvcOptions:

services.AddControllers(options => options.SerializerOptions.WriteIndented = true) 

Integration with SignalR

System.Text.Json is now the default Hub Protocol used by SignalR clients and servers starting in ASP.NET Core 3.0-preview5. Please try it out and file issues if you find anything not working as expected.

Switching back to Newtonsoft.Json

If you would like to switch back to the previous default of using Newtonsoft.Json then you can do so on both the client and server.

  1. Install the Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson NuGet package.
  2. On the client add .AddNewtonsoftJsonProtocol() to the HubConnectionBuilder:

    new HubConnectionBuilder()
    .WithUrl("/chatHub")
    .AddNewtonsoftJsonProtocol()
    .Build();
  3. On the server add .AddNewtonsoftJsonProtocol() to the AddSignalR() call:

    services.AddSignalR()
    .AddNewtonsoftJsonProtocol();

Give feedback

We hope you enjoy the new features in this preview release of ASP.NET Core! Please let us know what you think by filing issues on Github.

Avatar
Brady Gaster

Senior Program Manager, ASP.NET Core

Follow    

post

ASP.NET Core updates in .NET Core 3.0 Preview 4

Daniel Roth

Daniel

.NET Core 3.0 Preview 4 is now available and it includes a bunch of new updates to ASP.NET Core.

Here’s the list of what’s new in this preview:

  • Razor Components renamed back to server-side Blazor
  • Client-side Blazor on WebAssembly now in official preview
  • Resolve components based on @using
  • _Imports.razor
  • New component item template
  • Reconnection to the same server
  • Stateful reconnection after prerendering
  • Render stateful interactive components from Razor pages and views
  • Detect when the app is prerendering
  • Configure the SignalR client for server-side Blazor apps
  • Improved SignalR reconnect features
  • Configure SignalR client for server-side Blazor apps
  • Additional options for MVC service registration
  • Endpoint routing updates
  • New template for gRPC
  • Design-time build for gRPC
  • New Worker SDK

Please see the release notes for additional details and known issues.

Get started

To get started with ASP.NET Core in .NET Core 3.0 Preview 4 install the .NET Core 3.0 Preview 4 SDK

If you’re on Windows using Visual Studio, you also need to install the latest preview of Visual Studio 2019.

If you’re using Visual Studio Code, check out the improved Razor tooling and Blazor support in the C# extension.

Upgrade an existing project

To upgrade an existing an ASP.NET Core app to .NET Core 3.0 Preview 4, follow the migrations steps in the ASP.NET Core docs.

Please also see the full list of breaking changes in ASP.NET Core 3.0.

To upgrade an existing ASP.NET Core 3.0 Preview 3 project to Preview 4:

  • Update Microsoft.AspNetCore.* package references to 3.0.0-preview4-19216-03
  • In Razor Components apps (i.e. server-side Blazor apps) rename _ViewImports.cshtml to _Imports.razor for Razor imports that should apply to Razor components.
  • In Razor Component apps, in your Index.cshtml file, change the tag that references components.server.js so that it references blazor.server.js instead.
  • Remove any use of the _RazorComponentInclude property in your project file and rename and component files using the .cshtml file extension to use the .razor file extension instead.
  • Remove package references to Microsoft.AspNetCore.Components.Server.
  • Replace calls to AddRazorComponents in Startup.ConfigureServices with AddServerSideBlazor.
  • Replace calls to MapComponentHub with MapBlazorHub.
  • Remove any use of the Microsoft.AspNetCore.Components.Services namespace and replace with Microsoft.AspNetCore.Components as required.
  • In Razor Component apps, replace the {*clientPath} route in the host Razor Page with “/” and add a call to MapFallbackToPage in UseEndpoints.
  • Update any call to UseRouting in your Startup.Configure method to move the route mapping logic into a call to UseEndpoints at the point where you want the endpoints to be executed.

Before:

app.UseRouting(routes =>
{ routes.MapRazorPages();
}); app.UseCookiePolicy(); app.UseAuthorization();

After:

app.UseRouting(); app.UseCookiePolicy(); app.UseAuthorization(); app.UseEndpoints(routes =>
{ routes.MapRazorPages(); routes.MapFallbackToPage();
});

Razor Components renamed back to server-side Blazor

For a while, we’ve used the terminology Razor Components in some cases, and Blazor in other cases. This has proven to be confusing, so following a lot of community feedback, we’ve decided to drop the name ASP.NET Core Razor Components, and return to the name Server-side Blazor instead.

This emphasizes that Blazor is a single client app model with multiple hosting models:

  • Server-side Blazor runs on the server via SignalR
  • Client-side Blazor runs client-side on WebAssembly

… but either way, it’s the same programming model. The same Blazor components can be hosted in both environments.

In this preview of the .NET Core SDK we renamed the “Razor Components” template back to “Blazor (server-side)” and updated the related APIs accordingly. In Visual Studio the template will still show up as “Razor Components” when using Visual Studio 2019 16.1.0 Preview 1, but it will start showing up as “Blazor (server-side)” in a subsequent preview. We’ve also updated the template to use the new super cool flaming purple Blazor icon.

Blazor (server-side) template

Client-side Blazor on WebAssembly now in official preview

We’re also thrilled to announce that client-side Blazor on WebAssembly is now in official preview! Blazor is no longer experimental and we are committing to ship it as a supported web UI framework including support for running client-side in the browser on WebAssembly.

  • Server-side Blazor will ship as part of .NET Core 3.0. This was already announced last October.
  • Client-side Blazor won’t ship as part of the initial .NET Core 3.0 release, but we are now announcing it is committed to ship as part of a future .NET Core release (and hence is no longer an “experiment”).

With each preview release of .NET Core 3.0, we will continue to ship preview releases of both server and client-side Blazor.

Resolve components based on @using

Components in referenced assemblies are now always in scope and can be specified using their full type name including the namespace. You no longer need to import components from component libraries using the @addTagHelper directive.

For example, you can add a Counter component to the Index page like this:


Use the @using directive to bring component namespaces into scope just like you would in C# code:

@using BlazorWebApp1.Pages 

_Imports.razor

Use _Imports.razor files to import Razor directives across multiple Razor component files (.razor) in a hierarchical fashion.

For example, the following _Imports.razor file applies a layout and adds using statements for all Razor components in a the same folder and in any sub folders:

@layout MainLayout
@using Microsoft.AspNetCore.Components.
@using BlazorApp1.Data

This is similar to how you can use _ViewImports.cshtml with Razor views and pages, but applied specifically to Razor component files.

New component item template

You can now add components to Blazor apps using the new Razor Component item template:

dotnet new razorcomponent -n MyComponent1

Reconnection to the same server

Server-side Blazor apps require an active SignalR connection to the server to function. In this preview, the app will now attempt to reconnect to the server. As long as the state for that client is still in memory, the client session will resume without losing any state.

When the client detects that the connection has been lost a default UI is displayed to the user while the client attempts to reconnect:

Attempting reconnect

If reconnection failed the user is given the option to retry:

Reconnect failed

To customize this UI define an element with components-reconnect-modal as its ID. The client will update this element with one of the following CSS classes based on the state of the connection:

  • components-reconnect-show: Show the UI to indicate the connection was lost and the client is attempting to reconnect.
  • components-reconnect-hide: The client has an active connection – hide the UI.
  • components-reconnect-failed: Reconnection failed. To attempt reconnection again call window.Blazor.reconnect().

Stateful reconnection after prerendering

Server-side Blazor apps are setup by default to prerender the UI on the server before client connection back to the server is established. This is setup in the _Host.cshtml Razor page:

 @(await Html.RenderComponentAsync()) 
</body>

In this preview the client will now reconnect back to the server to the same state that was used to prerender the app. If the app state is still in memory it doesn’t need to be rerendered once the SignalR connection is established.

Render stateful interactive components from Razor pages and views

You can now add stateful interactive components to a Razor page or View. When the page or view renders the component will be prerendered with it. The app will then reconnect to the component state once the client connection has been established as long as it is still in memory.

For example, the following Razor page renders a Counter component with an initial count that is specified using a form:

<h1>My Razor Page</h1>
<form> <input type="number" asp-for="InitialCount" /> <button type="submit">Set initial count</button>
</form> @(await Html.RenderComponentAsync<Counter>(new { InitialCount = InitialCount })) @functions { [BindProperty(SupportsGet=true)] public int InitialCount { get; set; }
}

Interactive component on Razor page

Detect when the app is prerendering

While a Blazor app is prerendering, certain actions (like calling into JavaScript) are not possible because a connection with the browser has not yet been established. Components may need to render differently when being prerendered.

To delay JavaScript interop calls until after the connection with the browser has been established you can now use the OnAfterRenderAsync component lifecycle event. This event will only be called after the app has been fully rendered and the client connection established.

To conditionally render different content based on whether the app is currently being prerendered or not use IsConnected property on the IComponentContext service. This property will only return true if there is an active connection with the client.

Configure the SignalR client for server-side Blazor apps

Sometimes you need to configure the SignalR client used by server-side Blazor apps. For example, you might want to configure logging on the SignalR client to diagnose a connection issue.

To configure the SignalR client for server-side Blazor apps, add an autostart="false" attribute on the script tag for the blazor.server.js script, and then call Blazor.start passing in a config object that specifies the SignalR builder:

http://_framework/blazor.server.js
 Blazor.start({ configureSignalR: function (builder) { builder.configureLogging(2); // LogLevel.Information } });

Improved SignalR connection lifetime handling

Preview 4 will improve the developer experience for handling SignalR disconnection and reconnection. Automatic reconnects can be enabled by calling the withAutomaticReconnect method on HubConnectionBuilder:

const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect() .build();

Without any parameters, withAutomaticReconnect() will cause the configure the client to try to reconnect, waiting 0, 2, 10 and 30 seconds respectively before between each attempt.

In order to configure a non-default number of reconnect attempts before failure, or to change the reconnect timing, withAutomaticReconnect accepts an array of numbers representing the delay in milliseconds to wait before starting each reconnect attempt.

const connection = new signalR.HubConnectionBuilder() .withUrl("/chatHub") .withAutomaticReconnect([0, 0, 2000, 5000]) // defaults to [0, 2000, 10000, 30000] .build();

Improved disconnect & reconnect handling opportunities

Before starting any reconnect attempts, the HubConnection will transition to the Reconnecting state and fire its onreconnecting callback. This provides an opportunity to warn users that the connection has been lost, disable UI elements, and mitigate confusing user scenarios that might occur due to the disconnected state.

connection.onreconnecting((error) => { console.assert(connection.state === signalR.HubConnectionState.Reconnecting); document.getElementById("messageInput").disabled = true; const li = document.createElement("li"); li.textContent = `Connection lost due to error "${error}". Reconnecting.`; document.getElementById("messagesList").appendChild(li);
});

If the client successfully reconnects within its first four attempts, the HubConnection will transition back to the Connected state and fire onreconnected callbacks. This gives developers a good opportunity to inform users the connection has been reestablished.

connection.onreconnected((connectionId) => { console.assert(connection.state === signalR.HubConnectionState.Connected); document.getElementById("messageInput").disabled = false; const li = document.createElement("li"); li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`; document.getElementById("messagesList").appendChild(li);
});

If the client doesn’t successfully reconnect within its first four attempts, the HubConnection will transition to the Disconnected state and fire its onclosed callbacks. This is a good opportunity to inform users the connection has been permanently lost and recommend refreshing the page.

connection.onclose((error) => { console.assert(connection.state === signalR.HubConnectionState.Disconnected); document.getElementById("messageInput").disabled = true; const li = document.createElement("li"); li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`; document.getElementById("messagesList").appendChild(li);
})

Additional options for MVC service registration

We’re adding some new options for registering MVC’s various features inside ConfigureServices.

What’s changing

We’re adding three new top level extension methods related to MVC features on IServiceCollection. Along with this change we are updating our templates to use these new methods instead of AddMvc().

AddMvc() is not being removed and will continue to behave as it does today.

public void ConfigureServices(IServiceCollection services)
{ // Adds support for controllers and API-related features - but not views or pages. // // Used by the API template. services.AddControllers();
}
public void ConfigureServices(IServiceCollection services)
{ // Adds support for controllers, API-related features, and views - but not pages. // // Used by the Web Application (MVC) template. services.AddControllersWithViews();
}
public void ConfigureServices(IServiceCollection services)
{ // Adds support for Razor Pages and minimal controller support. // // Used by the Web Application template. services.AddRazorPages();
}

These new methods can also be combined. This example is equivalent to the current AddMvc().

public void ConfigureServices(IServiceCollection services)
{ services.AddControllers(); services.AddRazorPages();
}

These methods return an IMvcBuilder that can be chained to access any of the methods that are available today from the builder returned by AddMvc().

We recommend using whichever option feels best based on your needs.

Motivations

We wanted to provide some more options that represent how users use the product. In particular we’ve received strong feedback from users that want an API-focused flavor of MVC without the overhead for having the ability to serve views and pages. We tried to provide an experience for this in the past through the AddMvcCore() method, but that approach hasn’t been very successful. Users who tried using AddMvcCore() have been surprised by how much they need to know to use it successfully, and as a result we haven’t promoted its usage. We hope that AddControllers() will better satisfy this scenario.

In addition to the AddControllers() experience, we’re also attempting to create options that feel right for other scenarios. We’ve heard requests for this in the past, but not as strongly as the requests for an API-focused profile. Your feedback about whether AddMvc() could be improved upon, and how will be valuable.

What’s in AddControllers()

AddControllers() includes support for:

  • Controllers
  • Model Binding
  • API Explorer (OpenAPI integration)
  • Authorization [Authorize]
  • CORS [EnableCors]
  • Data Annotations validation [Required]
  • Formatter Mappings (translate a file-extension to a content-type)

All of these features are included because they fit under the API-focused banner, and they are very much pay-for-play. None of these features proactively interact with the request pipeline, these are activated by attributes on your controller or model class. API Explorer is an slight exception, it is a piece of infrastructure used by OpenAPI libraries and will do nothing without Swashbuckle or NSwag.

Some notable features AddMvc() includes but AddControllers() does not:

  • Antiforgery
  • Temp Data
  • Views
  • Pages
  • Tag Helpers
  • Memory Cache

These features are view-related and aren’t necessary in an API-focused profile of MVC.

What’s in AddControllersWithViews()

AddControllersWithViews() includes support for:

  • Controllers
  • Model Binding
  • API Explorer (OpenAPI integration)
  • Authorization [Authorize]
  • CORS [EnableCors]
  • Data Annotations validation [Required]
  • Formatter Mappings (translate a file-extension to a content-type)
  • Antiforgery
  • Temp Data
  • Views
  • Tag Helpers
  • Memory Cache

We wanted to position AddControllersWithViews() as a superset of AddControllers() for simplicity in explaining it. This features set also happens to align with the ASP.NET Core 1.X release (before Razor Pages).

Some notable features AddMvc() includes but AddControllersWithViews() does not:
– Pages

What’s in AddRazorPages()

AddRazorPages() includes support for:

  • Pages
  • Controllers
  • Model Binding
  • Authorization [Authorize]
  • Data Annotations validation [Required]
  • Antiforgery
  • Temp Data
  • Views
  • Tag Helpers
  • Memory Cache

For now this profile includes basic support for controllers, but excludes many of the API-focused features listed below. We’re interested in your feedback about what should be included by default in AddRazorPages().

Some notable features AddMvc() includes but AddRazorPages() does not:

  • API Explorer (OpenAPI integration)
  • CORS [EnableCors]
  • Formatter Mappings (translate a file-extension to a content-type)

Endpoint Routing updates

In ASP.NET Core 2.2 we introduced a new routing implementation called Endpoint Routing which replaces IRouter-based routing for ASP.NET Core MVC. In the upcoming 3.0 release Endpoint Routing will become central to the ASP.NET Core middleware programming model. Endpoint Routing is designed to support greater interoperability between frameworks that need routing (MVC, gRPC, SignalR, and more …) and middleware that want to understand the decisions made by routing (localization, authorization, CORS, and more …).

While it’s still possible to use the old UseMvc() or UseRouter() middleware in a 3.0 application, we recommend that every application migrate to Endpoint Routing if possible. We are taking steps to address compatibility bugs and fill in previously unsupported scenarios. We welcome your feedback about what features are missing or anything else that’s not great about routing in this preview release.

We’ll be uploading another post soon with a conceptual overview and cookbook for Endpoint Routing in 3.0.

Endpoint Routing overview

Endpoint Routing is made up of the pair of middleware created by app.UseRouting() and app.UseEndpoints(). app.UseRouting() marks the position in the middleware pipeline where a routing decision is made – where an endpoint is selected. app.UseEndpoints() marks the position in the middleware pipeline where the selected endpoint is executed. Middleware that run in between these can see the selected endpoint (if any) or can select a different endpoint.

If you’re familiar with routing from using MVC then most of what you have experienced so far will behave the same way. Endpoint Routing understands the same route template syntax and processes URLs in a very similar way to the in-the-box implementations of IRouter. Endpoint routing supports the [Route] and similar attributes inside MVC.

We expect most applications will only require changes to the Startup.cs file.

A typical Configure() method using Endpoint Routing has the following high-level structure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ // Middleware that run before routing. Usually the following appear here: if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Error"); } app.UseStaticFiles() // Runs matching. An endpoint is selected and set on the HttpContext if a match is found. app.UseRouting(); // Middleware that run after routing occurs. Usually the following appear here: app.UseAuthentication() app.UseAuthorization() app.UseCors() // These middleware can take different actions based on the endpoint. // Executes the endpoint that was selected by routing. app.UseEndpoints(endpoints => { // Mapping of endpoints goes here: endpoints.MapControllers() endpoints.MapRazorPages() endpoints.MapHub<MyChatHub>() endpoints.MapGrpcService<MyCalculatorService>() }); // Middleware here will only run if nothing was matched.
}

MVC Controllers, Razor Pages, SignalR, gRPC, and more are added inside UseEndpoints() – they are now part of the same routing system.

New template for gRPC

The gRPC template has been simplified to a single project template. We no longer include a gRPC client as part of the template.
For instructions on how to create a gRPC client, refer to the docs.

.
├── appsettings.Development.json
├── appsettings.json
├── grpc.csproj
├── Program.cs
├── Properties
│   └── launchSettings.json
├── Protos
│   └── greet.proto
├── Services
│   └── GreeterService.cs
└── Startup.cs 3 directories, 8 files

Design-time build for gRPC

Design-time build support for gRPC code-generation makes it easier to rapidly iterate on your gRPC services. Changes to your *.proto files no longer require you to build your project to re-run code generation.

Design time build

Worker SDK

In Preview 3 we introduced the new Worker Service template. In Preview 4 we’ve further decoupled that template from Web by introducing its own SDK. If you create a new Worker Service your csproj will now look like the following:

<Project Sdk="Microsoft.NET.Sdk.Worker"> <PropertyGroup> <TargetFramework>netcoreapp3.0</TargetFramework> <UserSecretsId>dotnet-WebApplication59-A2B1DB8D-0408-4583-80BA-1B32DAE36B97</UserSecretsId> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0-preview4.19216.2" /> </ItemGroup>
</Project>

We’ll have more to share on the new Worker SDK in a future post.

Give feedback

We hope you enjoy the new features in this preview release of ASP.NET Core! Please let us know what you think by filing issues on GitHub.

Daniel Roth
Daniel Roth

Principal Program Manager, ASP.NET

Follow Daniel   

post

Blazor now in official preview!

Daniel Roth

Daniel

With this newest Blazor release we’re pleased to announce that Blazor is now in official preview! Blazor is no longer experimental and we are committing to ship it as a supported web UI framework including support for running client-side in the browser on WebAssembly.

A little over a year ago we started the Blazor experimental project with the goal of building a client web UI framework based on .NET and WebAssembly. At the time Blazor was little more than a prototype and there were lots of open questions about the viability of running .NET in the browser. Since then we’ve shipped nine experimental Blazor releases addressing a variety of concerns including component model, data binding, event handling, routing, layouts, app size, hosting models, debugging, and tooling. We’re now at the point where we think Blazor is ready to take its next step.

Blazor icon

Simplifying the naming and versioning

For a while, we’ve used the terminology Razor Components in some cases, and Blazor in other cases. This has proven to be confusing, so following a lot of community feedback, we’ve decided to drop the name ASP.NET Core Razor Components, and return to the name Server-side Blazor instead.

This emphasizes that Blazor is a single client app model with multiple hosting models:

  • Server-side Blazor runs on the server via SignalR
  • Client-side Blazor runs client-side on WebAssembly

… but either way, it’s the same programming model. The same Blazor components can be hosted in both environments.

Also, since Blazor is now part of .NET Core, the client-side Blazor package versions now align with the .NET Core 3.0 versions. For example, the version number of all the preview packages we are shipping today is 3.0.0-preview4-19216-03. We no longer use separate 0.x version numbers for client-side Blazor packages.

What will ship when

  • Server-side Blazor will ship as part of .NET Core 3.0. This was already announced last October.
  • Client-side Blazor won’t ship as part of the initial .NET Core 3.0 release, but we are now announcing it is committed to ship as part of a future .NET Core release (and hence is no longer an “experiment”).

With each preview release of .NET Core 3.0, we will continue to ship preview releases of both server and client-side Blazor.

Today’s preview release

New features in this preview release:

  • Templates updated to use the .razor file extension
  • _Imports.razor
  • Scope components with @using
  • New component item template
  • New Blazor icons
  • Blazor support in Visual Studio Code

Check out the ASP.NET Core 3.0 Preview 4 announcement for details on these improvements. See also the Blazor release notes for additional details on this preview release.

Get the Blazor preview

To get started with the Blazor preview install the following:

  1. .NET Core 3.0 Preview 4 SDK (3.0.100-preview4-011223)
  2. The Blazor templates on the command-line:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview4-19216-03
    
  3. Visual Studio 2019 Preview with the ASP.NET and web development workload selected as well as the latest Blazor extension from the Visual Studio Marketplace, or Visual Studio Code with the latest C# extension (now with Blazor support!).

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

Blazor home page

Upgrade to the Blazor preview:

To upgrade your existing Blazor apps to the new Blazor preview first make sure you’ve installed the prerequisites listed above then follow these steps:

  • Update all Microsoft.AspNetCore.Blazor.* package references to 3.0.0-preview4-19216-03.
  • Remove any package reference to Microsoft.AspNetCore.Components.Server.
  • Remove any DotNetCliToolReference to Microsoft.AspNetCore.Blazor.Cli and replace with a package reference to Microsoft.AspNetCore.Blazor.DevServer.
  • In client Blazor projects remove the <RunCommand>dotnet</RunCommand> and <RunArguments>blazor serve</RunArguments> properties.
  • In client Blazor projects add the <RazorLangVersion>3.0</RazorLangVersion> property.
  • Rename all _ViewImports.cshtml files to _Imports.razor.
  • Rename all remaining .cshtml files to .razor.
  • Rename components.webassembly.js to blazor.webassembly.js
  • Remove any use of the Microsoft.AspNetCore.Components.Services namespace and replace with Microsoft.AspNetCore.Components as required.
  • Update server projects to use endpoint routing:
// Replace this:
app.UseMvc(routes =>
{ routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");
}); // With this:
app.UseRouting(); app.UseEndpoints(routes =>
{ routes.MapDefaultControllerRoute();
});
  • Run dotnet clean on the solution to clear out old Razor declarations.

Blazor community page is now Awesome Blazor

As part of updating the Blazor site, we’ve decided to retire the Blazor community page and instead direct folks to the community driven Awesome Blazor site. Thank you Adrien Torris for maintaining this truly “awesome” list of Blazor resources!

Try out preview Blazor UI offerings from Telerik, DevExpress, and Syncfusion

Blazor benefits from an active and supportive community that has contributed all sorts of sample apps, components, and libraries to the Blazor ecosystem. Recently popular component vendors like Telerik, DevExpress, and Syncfusion have joined in the fun and shipped previews of Blazor UI components. We encourage you to give these Blazor UI offerings a try and let them know what you think.

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!

Daniel Roth
Daniel Roth

Principal Program Manager, ASP.NET

Follow Daniel   

post

Updated Razor support in Visual Studio Code, now with Blazor support

Daniel Roth

Daniel

Today we are pleased to announce improved Razor tooling support in Visual Studio Code with the latest C# extension. This latest release includes improved Razor diagnostics and support for tag helpers and Blazor apps.

Get Started

To use this preview of Razor support in Visual Studio Code install the following:

To try out Visual Studio Code with Blazor apps, also install:

  • .NET Core 3.0 (Preview 4 or later)
  • The latest Blazor CLI templates:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview4-19216-03
    

What’s new in this release?

Improved diagnostics

We’ve improved the Razor diagnostics in Visual Studio Code for a variety of scenarios, including floating @ characters:

Floating @ character

Missing end braces:

Missing end brace

And missing end tags in code blocks:

Missing end tag

Tag helpers

Tag helper completions are now supported in ASP.NET Core projects:

Tag helper completion

As well as completions for tag helper attribute names and values:

Tag helper attribute completion

Blazor

Visual Studio Code now works with Blazor apps too!

You get completions for components and component parameters:

Component completions

Also data-binding, event handlers and lots of other Blazor goodies!

Blazor todos

Limitations and known issues

This is an alpha release of the Razor tooling for Visual Studio Code, so there are a number of limitations and known issues:

  • Razor editing is currently only supported in ASP.NET Core and Blazor projects (no support for ASP.NET projects)
  • Limited support for colorization

Note that if you need to disable the Razor tooling:

  • Open the Visual Studio Code User Settings: File -> Preferences -> Settings
  • Search for “razor”
  • Check the “Razor: Disabled” checkbox

Feedback

Please let us know what you think about this latest update to the Razor tooling support in Visual Studio Code by reporting issues in the Razor.VSCode repo. When reporting Razor tooling related issues please use the “Report a Razor Issue” command in Visual Studio Code to capture all of the relevant longs and diagnostic information. Just run the command and then follow the instructions.

Thanks for trying out Razor in Visual Studio Code!

Daniel Roth
Daniel Roth

Principal Program Manager, ASP.NET

Follow Daniel   

post

Blazor 0.9.0 experimental release now available

Daniel Roth

Daniel

Blazor 0.9.0 is now available! This release updates Blazor with the Razor Components improvements in .NET Core 3.0 Preview 3.

New Razor Component improvements now available to Blazor apps:

  • Improved event handling
  • Forms & validation

Checkout the ASP.NET Core 3.0 Preview 3 announcement for details on these improvements. See also the Blazor 0.9.0 release notes for additional details.

Note: The Blazor templates have not been updated to use the new .razor file extension for Razor Components in this release. This update will be done in a future release.

Get Blazor 0.9.0

To get started with Blazor 0.9.0 install the following:

  1. .NET Core 3.0 Preview 3 SDK (3.0.100-preview3-010431)
  2. Visual Studio 2019 (Preview 4 or later) with the ASP.NET and web development workload selected.
  3. The latest Blazor extension from the Visual Studio Marketplace.
  4. The Blazor templates on the command-line:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates::0.9.0-preview3-19154-02
    

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

Upgrade to Blazor 0.9.0

To upgrade your existing Blazor apps to Blazor 0.9.0 first make sure you’ve installed the prerequisites listed above.

To upgrade a Blazor 0.8.0 project to 0.9.0:

  • Update the Blazor packages and .NET CLI tool references to 0.9.0-preview3-19154-02.
  • Update the remaining Microsoft.AspNetCore.* packages to 3.0.0-preview3-19153-02.
  • Remove any usage of JSRuntime.Current and instead use dependency injection to get the current IJSRuntime instance and pass it through to where it is needed.

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!

Daniel Roth
Daniel Roth

Principal Program Manager, ASP.NET

Follow Daniel   

<!–


–>

post

Blazor 0.8.0 experimental release now available

Blazor 0.8.0 is now available! This release updates Blazor to use Razor Components in .NET Core 3.0 and adds some critical bug fixes.

Get Blazor 0.8.0

To get started with Blazor 0.8.0 install the following:

  1. .NET Core 3.0 Preview 2 SDK (3.0.100-preview-010184)
  2. Visual Studio 2019 (Preview 2 or later) with the ASP.NET and web development workload selected.
  3. The latest Blazor extension from the Visual Studio Marketplace.
  4. The Blazor templates on the command-line:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates::0.8.0-preview-19104-04
    

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

Upgrade to Blazor 0.8.0

To upgrade your existing Blazor apps to Blazor 0.8.0 first make sure you’ve installed the prerequisites listed above.

To upgrade a standalone Blazor 0.7.0 project to 0.8.0:

  • Update the Blazor packages and .NET CLI tool references to 0.8.0-preview-19104-04.
  • Replace any package reference to Microsoft.AspNetCore.Blazor.Browser with a reference to Microsoft.AspNetCore.Blazor.
  • Replace BlazorComponent with ComponentBase.
  • Update overrides of SetParameters on components to override SetParametersAsync instead.
  • Replace BlazorLayoutComponent with LayoutComponentBase
  • Replace IBlazorApplicationBuilder with IComponentsApplicationBuilder.
  • Replace any using statements for Microsoft.AspNetCore.Blazor.* with Microsoft.AspNetCore.Components.*, except leave Microsoft.AspNetCore.Blazor.Hosting in Program.cs
  • In index.html update the script reference to reference components.webassembly.js instead of blazor.webassembly.js

To upgrade an ASP.NET Core hosted Blazor app to 0.8.0:

  • Update the client-side Blazor project as described previously.
  • Update the ASP.NET Core app hosting the Blazor app to .NET Core 3.0 by following the migrations steps in the ASP.NET Core docs.
    • Update the target framework to be netcoreapp3.0
    • Remove any package reference to Microsoft.AspNetCore.App or Microsoft.AspNetCore.All
    • Upgrade any non-Blazor Microsoft.AspNetCore.* package references to version 3.0.0-preview-19075-0444
    • Remove any package reference to Microsoft.AspNetCore.Razor.Design
    • To enable JSON support, add a package reference to Microsoft.AspNetCore.Mvc.NewtonsoftJson and updateStartup.ConfigureServices to call services.AddMvc().AddNewtonsoftJson()
  • Upgrade the Microsoft.AspNetCore.Blazor.Server package reference to 0.8.0-preview-19104-04
  • Add a package reference to Microsoft.AspNetCore.Components.Server
  • In Startup.ConfigureServices simplify any call to app.AddResponseCompression to call the default overload without specifying WebAssembly or binary data as additional MIME types to compress.
  • In Startup.Configure add a call to app.UseBlazorDebugging() after the existing call to app.UseBlazor<App.Startup>()
  • Remove any unnecessary use of the Microsoft.AspNetCore.Blazor.Server namespace.

To upgrade a Blazor class library to 0.8.0:

  • Replace the package references to Microsoft.AspNetCore.Blazor.Browser and Microsoft.AspNetCore.Blazor.Build with references to Microsoft.AspNetCore.Components.Browser and Microsoft.AspNetCore.Components.Build and update the versions to 3.0.0-preview-19075-0444.
  • In the project file for the library change the project SDK from “Microsoft.NET.Sdk.Web” to “Microsoft.NET.Sdk.Razor”.

Server-side Blazor is now ASP.NET Core Razor Components in .NET Core 3.0

As was recently announced, server-side Blazor is now shipping as ASP.NET Core Razor Components in .NET Core 3.0. We’ve integrated the Blazor component model into ASP.NET Core 3.0 and renamed it to Razor Components. Blazor 0.8.0 is now built on Razor Components and enables you to host Razor Components in the browser on WebAssembly.

Upgrade a server-side Blazor project to ASP.NET Core Razor Components in .NET Core 3.0

If you’ve been working with server-side Blazor, we recommend upgrading to use ASP.NET Core Razor Components in .NET Core 3.0.

To upgrade a server-side Blazor app to ASP.NET Core Razor Components:

  • Update the client-side Blazor project as described previously, except replace the script reference to blazor.server.js with components.server.js
  • Update the ASP.NET Core app hosting the Razor Components to .NET Core 3.0 as described previously.
  • In the server project:
    • Upgrade the Microsoft.AspNetCore.Blazor.Server package reference to 0.8.0-preview-19104-04
    • Add a package reference to Microsoft.AspNetCore.Components.Server version 3.0.0-preview-19075-0444
    • Replace the using statement for Microsoft.AspNetCore.Blazor.Server with Microsoft.AspNetCore.Components.Server
    • Replace services.AddServerSideBlazor with services.AddRazorComponents and app.UseServerSideBlazor with app.UseRazorComponents.
    • In the Startup.Configure method add app.UseStaticFiles() just prior to calling app.UseRazorComponents.
    • Move the wwwroot folder from the Blazor app project to the ASP.NET Core server project

Switching between ASP.NET Core Razor Components and client-side Blazor

Sometimes it’s convenient to be able to switch between running your Razor Components on the server (ASP.NET Core Razor Components) and on the client (Blazor). For example, you might run on the server during development so that you can easily debug, but then publish your app to run on the client.

To update an ASP.NET Core hosted Blazor app so that it can be run as an ASP.NET Core Razor Components app:

  • Move the wwwroot folder from the client-side Blazor project to the ASP.NET Core server project.
  • In the server project:
    • Update the script tag in index.html to point to components.server.js instead of components.webassembly.js.
    • Add a call to services.AddRazorComponents<Client.Startup>() in the Startup.ConfigureServices method.
    • Add a call to app.UseStaticFiles() in the Startup.Configure method prior to the call to UseMvc.
    • Replace the call to UseBlazor with app.UseRazorComponents<Client.Startup>()
  • If you’re using dependency injection to inject an HttpClient into your components, then you’ll need to add an HttpClient as a service in your server’s Startup.ConfigureServices method.

Previously to get tooling support for Blazor projects you needed to install the Blazor extension for Visual Studio. Starting with Visual Studio 2019 Preview 2, tooling support for Razor Components (and hence Blazor apps) is already included without having to install anything else. The Blazor extension is now only needed to install the Blazor project templates in Visual Studio.

Runtime improvements

Blazor 0.8.0 includes some .NET runtime improvements like improved runtime performance on Chrome and an improved IL linker. In our performance benchmarks, Blazor 0.8.0 performance on Chrome is now about 25% faster. You can now also reference existing libraries like Json.NET from a Blazor app without any additional linker configuration:

@functions {
 WeatherForecast[] forecasts;

 protected override async Task OnInitAsync()
 {
 var json = await Http.GetStringAsync("api/SampleData/WeatherForecasts");
 forecasts = Newtonsoft.Json.JsonConvert.DeserializeObject<WeatherForecast[]>(json);
 }
}

Known issues

There are a couple of known issues with this release that you may run into:

  • “It was not possible to find any compatible framework version. The specified framework ‘Microsoft.NETCore.App’, version ‘2.0.0’ was not found.”: You may see this error when building a Blazor app because the IL linker currently requires .NET Core 2.x to run. To work around this issue, either install .NET Core 2.2 or disable IL linking by setting the <BlazorLinkOnBuild>false</BlazorLinkOnBuild> property in your project file.
  • “Unable to generate deps.json, it may have been already generated.”: You may see this error when running a standalone Blazor app and you haven’t yet restored packages for any .NET Core apps. To workaround this issue create any .NET Core app (ex dotnet new console) and then rerun the Blazor app.

These issues will be addressed in a future Blazor update.

Future updates

This release of Blazor was primarily focused on first integrating Razor Components into ASP.NET Core 3.0 and then rebuilding Blazor on top of that. Going forward, we plan to ship Blazor updates with each .NET Core 3.0 update.

Blazor, and support for running Razor Components on WebAssembly in the browser, won’t ship with .NET Core 3.0, but we continue to work towards shipping Blazor some later date.

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!

post

Blazor 0.7.0 experimental release now available

Blazor 0.7.0 is now available! This release focuses on enabling component coordination across ancestor-descendent relationships. We’ve also added some improvements to the debugging experience.

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

  • Cascading values and parameters
  • Debugging improvements

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

Get Blazor 0.7.0

Install the following:

  1. .NET Core 2.1 SDK (2.1.500 or later).
  2. Visual Studio 2017 (15.9 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.7.0

To upgrade a Blazor 0.6.0 project to 0.7.0:

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

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

Cascading values and parameters

Blazor components can accept parameters that can be used to flow data into a component and impact the component’s rendering. Parameter values are provided from parent component to child component. Sometimes, however, it’s inconvenient to flow data from an ancestor component to a descendent component, especially when there are many layers in between. Cascading values and parameters solve this problem by providing a convenient way for an ancestor component to provide a value that is then available to all descendent components. They also provide a great way for components to coordinate.

For example, if you wanted to provide some theme information for a specific part of your app you could flow the relevant styles and classes from component to component, but this would be tedious and cumbersome. Instead, a common ancestor component can provide the theme information as a cascading value that descendents can accept as a cascading parameter and then consume as needed.

Let’s say the following ThemeInfo class specifies all of the theme information that you want to flow down the component hierarchy so that all of the buttons within that part of your app share the same look and feel:

public class ThemeInfo 
{
 public string ButtonClass { get; set; }
}

An ancestor component can provide a cascading value using the CascadingValue component. The CascadingValue component wraps a subtree of the component hierarchy and specifies a single value that will be available to all components within that subtree. For example, we could specify the theme info in our application layout as a cascading parameter for all components that make up the layout body like this:

@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>

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

@functions {
 ThemeInfo theme = new ThemeInfo { ButtonClass = "btn-success" };
}

To make use of cascading values, components can declare cascading parameters using the [CascadingParameter] attribute. Cascading values are bound to cascading parameters by type. In the following example the Counter component is modified to have a cascading parameter that binds to the ThemeInfo cascading value, which is then used to set the class for the button.

@page "/counter"

<h1>Counter</h1>

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

<button class="btn @ThemeInfo.ButtonClass" onclick="@IncrementCount">Click me</button>

@functions {
 int currentCount = 0;

 [CascadingParameter] protected ThemeInfo ThemeInfo { get; set; }

 void IncrementCount()
 {
 currentCount++;
 }
}

When we run the app we can see that the new style is applied:

Counter with cascading parameter

Cascading parameters also enable components to collaborate across the component hierarchy. For example, let’s say you have a TabSet component that contains a number of Tab components, like this:

<TabSet>
 <Tab Title="First tab">
 <h4>First tab</h4>
 This is the first tab.
 </Tab>

 @if (showSecondTab)
 {
 <Tab Title="Second">
 <h4>Second tab</h4>
 You can toggle me.
 </Tab>
 }

 <Tab Title="Third">
 <h4>Third tab</h4>

 <label>
 <input type="checkbox" bind=@showSecondTab />
 Toggle second tab
 </label>
 </Tab>
</TabSet>

In this example the child Tab components are not explicitly passed as parameters to the TabSet. Instead they are simply part of the child content of the TabSet. But the TabSet still needs to know about each Tab so that it can render the headers and the active tab. To enable this coordination without requiring any specific wire up from the user, the TabSet component can provide itself as a cascading value that can then be picked up by the descendent Tab components:

In TabSet.cshtml

<!-- Display the tab headers -->
<CascadingValue Value=this>
 <ul class="nav nav-tabs">
 @ChildContent
 </ul>
</CascadingValue>

This allows the descendent Tab components to capture the containing TabSet as a cascading parameter, so they can add themselves to the TabSet and coordinate on which Tab is active:

In Tab.cshtml

[CascadingParameter] TabSet ContainerTabSet { get; set; }

Check out the full TabSet sample here.

Debugging improvements

In Blazor 0.5.0 we added some very preliminary support for debugging client-side Blazor apps in the browser. While this initial debugging support demonstrated that debugging .NET apps in the browser was possible, it was still a pretty rough experience. Blazor 0.7.0 picks up the latest runtime updates, which includes some fixes that makes the debugging experience more reliable. You can now more reliably set and remove breakpoints, and the reliability of step debugging has been improved.

Improved Blazor debugging

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!

post

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!