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.

<div>
    @foreach (var flight in Flights)
    {
        <DetailsCard @key="flight" Flight="@flight" />
    }
</div>

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

<div>
    @foreach (var flight in Flights)
    {
        <DetailsCard Flight="@flight" />
    }
</div>

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 -->
<div @directive>...</div>
<div @directive="value"></div>

<!-- directive with key/value arg-->
<div @directive:key>...</div>
<div @directive:key="value"></div>

<!-- directive with suffix -->
<div @directive-suffix></div>
<div @directive-suffix="value"></div>

<!-- directive with suffix and key/value arg-->
<div @directive-suffix:key></div>
<div @directive-suffix:key="value"></div>

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

<div @key="id">...</div>

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.

    <script src="_content/RazorLib1/hello.js"></script>
    
  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   

83 comments

  • Hallam Etragu
    Hallam Etragu

    Hi Daniel, 
    First of all I have to say I’ve never been so excited in a while after getting to code Blazor, I just hope it gets more investment and more publicity. It really looks great. Some questions:
    While working with lists in UWP apps is important to virtualize the collection, is there any easy way to do this in Blazor like a virtualizing container that only draws items depending on the viewport width of that component?
    Blazor serverside has loads of sense to be deployed as an Electron app, are there any plans to facilitate this to the users?
    Regards.

    • Daniel Roth
      Daniel Roth

      Hi Hallam,

      > is there any easy way to do this in Blazor like a virtualizing container that only draws items depending on the viewport width of that component?

      We don’t provide out of the box components for virtualized lists/grids, but you can implement your own or take a look at the many community provided componets that do this. For example: Telerik, DevExpress, Syncfusion.

      > Blazor serverside has loads of sense to be deployed as an Electron app, are there any plans to facilitate this to the users?

      We implemented a proof of concept for Blazor + Electron a while back: https://github.com/aspnet/AspLabs/tree/master/src/ComponentsElectron. We don’t have a specific roadmap to ship it yet, but it is something we want to eventually do.

  • Øyvind Habberstad
    Øyvind Habberstad

    Hi Daniel,
    I assume that you are refering to a nuget package, when you write “add a package reference to Grpc.Net.Client and then you can create a new client“, but I cannot a package named “Grpc.Net.Client” on nuget.
    I tried to add the “Grpc.Core”, but I cannot find any “Grpc.Net.Client” namespace in that package. Is there something I have misunderstood? (I have ticked the “Include prerelease”)
    Thanks in advance.

      • Avatar
        Sourabh Shirhatti [MSFT]

        Hey Øyvind Habberstad! Apologies for the issue you ran into. I’m glad you were able to unblock yourself by discovering our dev feed.
        We’re waiting on the team over at CNCF to publish these packages to NuGet.org and hope to have it completed soon. 

        • Øyvind Habberstad
          Øyvind Habberstad

          Hi Sourabh Shirhatti!
          Thanks for your swift reply. I’m now faceing another issue. I see that the Grpc.Net.Client package has a dependency on netstandard2.1, I’m able to set this in my Blazor Client project, but when I add the Grpc.Net.Client I get an compilation error. I paste in all my nuget packages for your reference (it compiles fine without the Grpc.Net.Client package):
          <ItemGroup><PackageReference Include=”Google.Protobuf” Version=”3.8.0″ /><PackageReference Include=”Microsoft.AspNetCore.Blazor” Version=”3.0.0-preview6.19307.2″ /><PackageReference Include=”Microsoft.AspNetCore.Blazor.Build” Version=”3.0.0-preview6.19307.2″ PrivateAssets=”all” /><PackageReference Include=”Microsoft.AspNetCore.Blazor.DevServer” Version=”3.0.0-preview6.19307.2″ PrivateAssets=”all” /><PackageReference Include=”Grpc.Core” Version=”1.22.0-dev201906121010″ /><PackageReference Include=”Grpc.Tools” Version=”1.22.0-dev201906121010″><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference><PackageReference Include=”Grpc.Net.Client” Version=”0.1.22-dev201906130703″ /></ItemGroup> 1>Fatal error in IL Linker1>1>Unhandled Exception: Mono.Linker.MarkException: Error processing method: ‘Grpc.Core.Metadata Grpc.Net.Client.Internal.GrpcCall`2::GetTrailers()’ in assembly: ‘Grpc.Net.Client.dll’ —> Mono.Cecil.ResolutionException: Failed to resolve System.Net.Http.Headers.HttpResponseHeaders System.Net.Http.HttpResponseMessage::get_TrailingHeaders()1> at Mono.Linker.Steps.MarkStep.HandleUnresolvedMethod(MethodReference reference)1> at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference)1> at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction)1> at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body)1> at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method)1> at Mono.Linker.Steps.MarkStep.ProcessQueue()1> — End of inner exception stack trace —1> at Mono.Linker.Steps.MarkStep.ProcessQueue()1> at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue()1> at Mono.Linker.Steps.MarkStep.Process()1> at Mono.Linker.Steps.MarkStep.Process(LinkContext context)1> at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step)1> at Mono.Linker.Pipeline.Process(LinkContext context)1> at Mono.Linker.Driver.Run(ILogger customLogger)1> at Mono.Linker.Driver.Execute(String[] args, ILogger customLogger)1> at Mono.Linker.Driver.Main(String[] args)1>C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor.build\3.0.0-preview6.19307.2\targets\Blazor.MonoRuntime.targets(439,5): error MSB3073: The command “dotnet “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor.mono\0.10.0-preview6.19303.4\build\netstandard1.0\../../tools/illink/illink.dll” -l none –disable-opt unreachablebodies –verbose –strip-security true –exclude-feature com –exclude-feature sre -v false -c link -u link -b true -d “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor.mono\0.10.0-preview6.19303.4\build\netstandard1.0\../../tools/mono/bcl/” -d “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor.mono\0.10.0-preview6.19303.4\build\netstandard1.0\../../tools/mono/bcl/Facades/” -o “C:\Users\oyvin\source\repos\BlazorPreviewSix\BlazorPreviewSix\obj\Debug\netstandard2.1\blazor\linker/” -x “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor.build\3.0.0-preview6.19307.2\targets\BuiltInBclLinkerDescriptor.xml” -x “C:\Users\oyvin\source\repos\BlazorPreviewSix\BlazorPreviewSix\obj\Debug\netstandard2.1\blazor\linker.descriptor.xml” -a “C:\Users\oyvin\.nuget\packages\google.protobuf\3.8.0\lib\netstandard2.0\Google.Protobuf.dll” -a “C:\Users\oyvin\.nuget\packages\grpc.core\1.22.0-dev201906121010\lib\netstandard2.0\Grpc.Core.dll” -a “C:\Users\oyvin\.nuget\packages\grpc.core.api\1.22.0-dev201906121010\lib\netstandard2.0\Grpc.Core.Api.dll” -a “C:\Users\oyvin\.nuget\packages\grpc.net.client\0.1.22-dev201906120701\lib\netstandard2.1\Grpc.Net.Client.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.authorization\3.0.0-preview6.19307.2\lib\netstandard2.0\Microsoft.AspNetCore.Authorization.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.blazor\3.0.0-preview6.19307.2\lib\netstandard2.0\Microsoft.AspNetCore.Blazor.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.components\3.0.0-preview6.19307.2\lib\netstandard2.0\Microsoft.AspNetCore.Components.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.components.browser\3.0.0-preview6.19307.2\lib\netstandard2.0\Microsoft.AspNetCore.Components.Browser.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.aspnetcore.metadata\3.0.0-preview6.19307.2\lib\netstandard2.0\Microsoft.AspNetCore.Metadata.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.extensions.dependencyinjection\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.extensions.logging.abstractions\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.extensions.options\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.Extensions.Options.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.extensions.primitives\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll” -a “C:\Users\oyvin\.nuget\packages\microsoft.jsinterop\3.0.0-preview6.19304.6\lib\netstandard2.0\Microsoft.JSInterop.dll” -a “C:\Users\oyvin\.nuget\packages\mono.webassembly.interop\3.0.0-preview6.19304.6\lib\netstandard2.0\Mono.WebAssembly.Interop.dll” -a “C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.buffers\4.5.0\lib\netstandard2.0\System.Buffers.dll” -a “C:\Users\oyvin\.nuget\packages\system.componentmodel.annotations\4.6.0-preview6.19303.8\lib\netstandard2.0\System.ComponentModel.Annotations.dll” -a “C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.interactive.async\3.2.0\lib\netstandard2.0\System.Interactive.Async.dll” -a “C:\Users\oyvin\.nuget\packages\system.memory\4.5.3\lib\netstandard2.0\System.Memory.dll” -a “C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.numerics.vectors\4.5.0\lib\netstandard2.0\System.Numerics.Vectors.dll” -a “C:\Users\oyvin\.nuget\packages\system.runtime.compilerservices.unsafe\4.6.0-preview6.19303.8\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll” -a “C:\Users\oyvin\.nuget\packages\system.text.json\4.6.0-preview6.19303.8\lib\netstandard2.0\System.Text.Json.dll” -a “C:\Users\oyvin\.nuget\packages\system.threading.tasks.extensions\4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll” -a “C:\Users\oyvin\source\repos\BlazorPreviewSix\BlazorPreviewSix\obj\Debug\netstandard2.1\BlazorPreviewSix.dll”” exited with code -532462766.1>Done building project “BlazorPreviewSix.csproj” — FAILED.========== Build: 0 succeeded, 1 failed, 3 up-to-date, 0 skipped ==========

    • Daniel Roth
      Daniel Roth

      Thanks for sharing this feedback, Serge! Let me first try to clarify what we plan to fix. The attribute name for an event handler will still start with `@`. What we plan to fix is that the attribute value for event handlers shouldn’t require a leading `@`, because it’s redundant.

      So instead of this: `<button @onclick=”@Clicked”>Click me!</button>`

      You should be able to write this: `<button @onclick=”Clicked”>Click me!</button>`

      Do you still feel that the second `@` character is needed?

      • Serge S
        Serge S

        Hi Daniel, Thank you for your feedback. It is could be another option, which is looks even better – no ” 
        `<button @onclick=Clicked>Click me!</button>`
        What do you think?
        BTW, when using parameters in components syntax without   @Par=Value looks better.

        • Daniel Roth
          Daniel Roth

          Attribute values without quotes are supported. Whether you include the wrapping quotes are not is mostly a stylistic choice. Functionally, both syntaxes are equivalent except in cases where you need to have spaces in the attribute value.

  • Serge S
    Serge S

    Hi Daniel,  Re: “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.”I have a possibility to run preview 6 today and it was diificult to findout (5 minutes) that you have changed @Something. It is looks better code now and it is easy to distinguish in *razor code between HTML and C#. I like it! Please keep current syntax: It is will consistent @ – means Blazor! <button @onclick=”@Clicked”>Click me!</button>Thank you, Serge

    • Avatar
      Terry Young

      No.  Sourabh has indicated that “Browser APIs (XmlHttpRequest and fetch) today haven’t caught up and hence do not provide access to HTTP/2 framing and Response trailers which are required for gRPC.”

  • Avatar
    Issac Vale

    It should be app.UseClientSideBlazorFiles<TStartup> instead of app.UseClientSideBlazor<TStartup>()

    Hope this helps…

  • Avatar
    Stefan Over

    “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.”
    Does this mean that the client-side templates don’t include it? Or are the authentication features not supported by client-side projects?What about client-side projects with ASP.NET Core backend, which will probably the most successful ones?

    • Daniel Roth
      Daniel Roth

      The authentication features are supported by client-side Blazor on WebAssembly. We just haven’t updated the client-side Blazor templates yet to use these features like we did wtih the server-side Blazor template. Also, for client-side Blazor you’ll need to implement an AuthenticationStateProvider appropriate to your application that can establish the identity of the current user.

  • Avatar
    JJ Bussert

    Finally we have easier to use Auth integration and templates to spin up the projects faster.  Can’t wait to give this a try!

  • Steven Sullivan
    Steven Sullivan

    I have a Blazor Server-Side project that has now been updated to reference 3.0.0-preview6.19307.2 as well as the most recent version of VS2019. However, it’s still unable to recognize @code, or really implement any of the new features.Am I missing something?

      • Avatar
        Jan Wittland

        Same problem here, but only with IntelliSense in Code Editor. VS 2019 16.2 Preview 2 Enterprise, current .NET Core Preview 6, current Blazor Language Services installed.
        @code or @attribute is accepted by compiler (Build+Run and manual dotnet run).
        But: code editor/intellisense not working 🙁 e.g: FetchData.razor from sample does not recognize @code, so also the forecasts variable isn’t recognized in razor syntax loop.
        How to get this running? Are the latest syntax changes supported in VS 16.2? Everything was fine with Preview 5.

  • Avatar
    Luis Palacios

    Thanks a lot, Daniel, I’m highly excited for Blazor, and I’m no javascript hater, in fact, I’ve been doing a lot of typescript with react and angular but I’m still excited about the possibilities that are opening with Blazor 

  • Avatar
    Ra D

    Hi Daniel – excellent work and thanks for including the authentication in this release. I understand this is a preview release but I tried extending the user registration with custom attributes to a sample project by using the Scaffold Identity steps – the end result is a mess; I ended up discarding the project. Steps to reproduce: create a sample Blazor server-side with single user authentication. Project gets generated, run the project – works like a charm. Now extend the app with Scaffold Identity – select only Account\Registration page, select the dbcontext. VS adds additional code and pages – try running the project – either build fails or app wont run. Could you please streamline this to work with new Blazor libraries. Thank you.

  • Serge S
    Serge S

    Hi Daniel,
    I have a question regarding injecting: Server-Side or Client-Side Blazor:
    Client-Side Blazor: If I correctly understand, when we injecting a Class is it transferring an entire content of a Class (a lot’s of data in memory) to Client over SignalR?
    Server-Side Blazor: it is local by definition. No transferring.
    From this point of view the Server-Side should be much faster for an embedded server application, which is supposed to handle the device activities and, because number of clients are limited, also preferred.
    I am using the Server-Side Blazor and it is really fast.
    But I don’t know how fast it will be using Client-Side Blazor, probably it is required a granular data control.
    Thank you,
    Serge

    • Daniel Roth
      Daniel Roth

      Client-side Blazor runs your entire client UI in the browser using a WebAssembly based .NET runtime. Client-side Blazor doesn’t require a SignalR connection and doesn’t require .NET on the server at all. You can deploy a client-side Blazor app as a bunch of static files to a static site hosting solution like GitHub pages or Azure Static Site Hosting. For a full discussion of the different Blazor hosting models (client-side vs server-side) see https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models

      • Serge S
        Serge S

        Hi Daniel,
        Thank you. Sorry, just make sure I understand usage scenarios. Client-Side Blazor required to work with injected a communication protocol, for example HttpClient (another level of abstraction – a Device API service) to work with Device. Finally, using this Service we transferring required data over API Service – is it correct? Finally, the same API Service can be used by any third party clients. Am I correct?
        Thank you,
        Serge

        • Daniel Roth
          Daniel Roth

          That sounds right. From client-side Blazor you communicate with Web APIs on the server using HttpClient. You can abstract away this communication using a service that you inject into your components. The components call into the injected service, which then uses an HttpClient to call the Web API on the server. That Web API can be called by other third party clients as well.

          • Avatar
            Michael DeMond

            Might I suggest perhaps additional branding around these different modes?  I think something like “Blazor WebAssembly Mode” and “Blazor WebSocket Mode” is crystal clear, and makes it more apparent that you are supporting these two technologies.  A lot of developers think that Blazor is WebAssembly-only and I believe you’re losing out to adoption accordingly.

          • Daniel Roth
            Daniel Roth

            We have been thinking along similar lines. The plan is to rename the “Blazor (server-side)” template to “Blazor Server App” and the client-side Blazor templates to “Blazor WebAssembly App” with an option to host in an ASP.NET Core app or not. Feel free to chime in on the GitHub issue tracking this proposal with your thoughts.

  • Rod Macdonald
    Rod Macdonald

    Blazor just seems to be getting better and better. What’s the client side story for a local database? Have been saying for years SQL Server could do with a client side companion (non-Jet, non-SQLite, kinda SQL Server’ish, you know?)  🙂

  • D S
    D S

    Hi Daniel:
    Excellent work of your Blazor team.
    I am trying to learn about the authentication feature of Blazor Server Side.  Is it possible to create a custom login template instead of using the default page.
    Thanks
    David

    • Daniel Roth
      Daniel Roth

      It should be possible to override any of the Razor Pages that make up the default identity UI. The Identity scaffolder that we typically use to do this has some issues with Blazor projects right now that we need to address, but for now I believe you can scaffold the Identity pages you want in a vanilla ASP.NET Core Web App and then copy them over to get the desired result. Please report on GitHub any issues that you hit when trying to do this as we know this is an area where we need to do some work still.

  • Avatar
    Jesse Sander

    Hi Daniel,
    Thanks for the update! Really impressed with Blazor so far. Just wanted to say, keep up the good work and cheers to the team from Holland!

  • Shaun Sales
    Shaun Sales

    Hi Daniel, very happy to see great features continuing to be added to SignalR Core. Can we expect to see a SignalR C# client compatible with client-side Blazor any time soon?

      • Shaun Sales
        Shaun Sales

        Thanks for the reply, that’s a helpful data point for us to plan with. We are heavy Unity users and have a SignalR client running under Mono/IL2CPP, which talks to our backend and wanted to share that with our upcoming Blazor client. It may be a good time for us to investigate building a lightweight Mono-based SignalR C# client that works for both Blazor and Unity. 

  • Avatar
    Wilson, Joel

    Hosting Blazor apps in IIS doesn’t seem to work under Preview 6. I always get the message “This localhost page can’t be found” (Chrome). The app runs fine in Visual Studio 2019 Preview (16.2.0 Preview 2.0). It also works if I run the server executable from the command line (i.e., WebApplication1.Server.exe) and then navigate the browser to http://localhost:5000. But when I publish the code to an IIS website I get the error. I’m thinking it has something to do with the new MapFallbackToClientSideBlazor call in Startup.Configure (but that’s just a guess). Wondering if anyone else is having the same problem OR if anyone else has successfully hosted a Preview 6 Blazor app in IIS (and, yes, I installed the Preview 6 Runtime & Hosting Bundle).

      • Avatar
        Wilson, Joel

        I figured out the issue and I think it’s the Visual Studio Publisher. When you publish it creates a wwwroot folder but it’s not putting index.html (or the css folder, in this case) under wwwroot. Instead it creates folders under wwwroot called _content\webapplication1client which contain index.html (and my css folder). I copied these to the wwwroot folder and the app runs now — no 404. So it looks like the hosting bundle works fine but VS2019 publisher is not creating the correct folder structure. So there is a workaround but it’s a pain-in-the-*** to have to fix up the folders after a publish.

  • Mark Lynn
    Mark Lynn

    Looks like this.StateHasChanged isn’t behaving in a threadsafe manner?This version now throws in the following,- countdown example from button click
    var timer = new Timer(new TimerCallback(_ =>{if (Count <= 0) return;Count–;
    // recognize the state change and refresh the UIthis.StateHasChanged();}), null, 1000, 1000);

    or a ticking clock example?

  • Avatar
    Dimitri Joosten

    Hi Daniel, my question is about Deployment to Azure Web App. For .Net Core Preview 5 there is an extention provided in Azure whereas for preview 6 is none provided (yet). So I tried to deploy self-contained. I used the project template “Blazor (ASPNet Core hosted)”. The startup target is “xxxx.Server” When I try to publish I get the following error:
    Severity Code Description Project File Line Suppression StateError  Assets file ‘….Client\obj\project.assets.json’ doesn’t have a target for ‘.NETStandard,Version=v2.0’. Ensure that restore has run and that you have included ‘netstandard2.0’ in the TargetFrameworks for your project. xxx.Server  0 
    I tried to remove / reinstall the preview (.net core and visual studio preview). Created the project from scretch but that didn’t help… 
    Thank you for helping me solving this issue.
    Br. Dimitri

    • Daniel Roth
      Daniel Roth

      Unfortunately there is an issue that has blocked us from deploying the preview6 site extension to Azure. We are working to resolve this issue as soon as possible. To work around the issue you can instead publish your app as a “self-contained” app.

      • Avatar
        Dimitri Joosten

        Thank you for your answer! Unfortunately “self-contained” doesn’t work either for the .server project. My run-target is the .server project. The compiler complaints about “….Client\obj\project.assets.json” doesn’t have target for ‘.NETStandard,Version=v2.0’. This used to work in preview5 but not in preview6. If you try to deploy the out-of-the-box ASP.Net hosted app (self -contained) you can easily simulate this issue.
        PS: I can deploy the client target, but then the server-side won’t work (as expected).
        Thank you. Br. Dimitri 

  • Avatar
    Alexandre Reyes

    Hey Daniel, does “Static assets in Razor class libraries” works when you disable server pre-rendering?

    endpoints.MapBlazorHub().AddComponent(typeof(App), selector: “app”);endpoints.MapFallbackToFile(“index.html”);

  • Avatar
    Dwayne Barsotta

    I like the changes so far, however the new binding method broke my intellisense. With the new changes, when I bind to an internal method of an object, Intellisense will show the object name => but after hitting “enter” or selecting the object name, the intenal components do not become avaiable.

  • Avatar
    Mohammad Mirza

    Very nice news. I’m glad to see all the good progress with Blazor. I’m trying to convince my working place to move from KnockOut.js/Angular to Blazor. I really hope this Blazor technology goes mainstream.  

    • Daniel Roth
      Daniel Roth

      > I’m trying to convince my working place to move from KnockOut.js/Angular to Blazor.

      Awesome! Let us know if you think there is anything we can do to make the pitch for Blazor more compelling.

  • Avatar
    Тарасенков Дмитрий

    Installed VS 2019 (SDK:Latest version).Create a test project with Blazor.Run. That is all right.Open the MainLayout.razor file and make a simple change.Replace the English word “Above” with the Russian word “О нас”.Run. That is all right.Open the NavMenu.razor file and make a simple change. Replace the English word “Counter” on the Russian word “Счетчик”.Run. Instead of the desired result on the screen we see question marks.The situation is similar in the translation of words into Russian in the authorization.In other words Blazor does not properly handle the Cyrillic alphabet, starting from the second level of nesting.How is this problem solved?

  • Avatar
    Тарасенков Дмитрий

    Installed VS 2019 (SDK: latest version).Create a test project with Blazor.Run. Everything’s in order.Open the MainLayout (razor file) and make a simple change.Replace the English word “Above” with the Cyrillic word (translate).Run. Everything’s in order.Open the NavMenu (razor file) and make a simple change. Replace the English word ” Counter “with the Cyrillic word (translate).Run. Instead of the desired result, we see question marks on the screen.A similar situation is with the translation of words into Cyrillic in the authorization.In other words, Blazor incorrectly handles Cyrillic characters starting from the second level of nesting.How do I fix this?

  • Avatar
    John Barrett

    Hey Daniel,
    Any plans for getting somethig like Identity Scaffolding to generate *.razor components or similar?
    Cheers, John

  • Avatar
    Cosmin Sontu

    Hi Daniel,
    I think the code snippet in section “Markup in @functions and local functions”
    for preview 6 should be:
    @{ GreetPerson(builder, person); }

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

    Otherwise I’m getting “Error CS0103 The name ‘builder’ does not exist in the current context …razor.g.cs” since builder is not accessible from GreetPerson method.

    • Daniel Roth
      Daniel Roth

      The syntax shown in this blog post is specific to MVC views and Razor Pages (.cshtml files). You are correct that additional code is needed to use the same feature in Razor components (.razor) files.

  • Michael Calvin
    Michael Calvin

    The link to the grpc Server examples does not work. I would really love to find some better examples of implementing Interceptors.

Leave a comment