Posted on Leave a comment

ASP.NET Core 2.2.0-preview3 now available

Today we’re very happy to announce that the third preview of the next minor release of ASP.NET Core and .NET Core is now available for you to try out. We’ve been working hard on this release, along with many folks from the community, and it’s now ready for a wider audience to try it out and provide the feedback that will continue to shape the release.

How do I get it?

You can download the new .NET Core SDK for 2.2.0-preview3 (which includes ASP.NET 2.2.0-preview3) from https://www.microsoft.com/net/download/dotnet-core/2.2

Visual Studio requirements

Customers using Visual Studio should also install and use the Preview channel of Visual Studio 2017 (15.9 Preview 3 or later) in addition to the SDK when working with .NET Core 2.2 and ASP.NET Core 2.2 projects. Please note that the Visual Studio preview channel can be installed side-by-side with existing an Visual Studio installation without disrupting your current development environment.

Azure App Service Requirements

If you are hosting your application on Azure App Service, you can follow these instructions to install the required site extension for hosting your 2.2.0-preview3 applications.

Impact to machines

Please note that is a preview release and there are likely to be known issues and as-yet-to-be discovered bugs. While the .NET Core SDK and runtime installs are side-by-side, your default SDK will become the latest one. If you run into issues working on existing projects using earlier versions of .NET Core after installing the preview SDK, you can force specific projects to use an earlier installed version of the SDK using a global.json file as documented here. Please log an issue if you run into such cases as SDK releases are intended to be backwards compatible.

What’s new in Preview 3

For a full list of changes, bug fixes, and known issues you can read the release announcement.

Routing

We’ve introduced the concept of Parameter Transformers to routing in ASP.NET Core 2.2. A parameter transformer customizes the route generated by transforming parameter’s route values, and gives developers new options when generating routes. For example, a custom slugify parameter transformer in route pattern blog\{article:slugify} with Url.Action(new { article = "MyTestArticle" }) generates blog\my-test-article. Parameter transformers implement Microsoft.AspNetCore.Routing.IOutboundParameterTransformer and are configured using ConstraintMap.

These features are specific to the new endpoint routing system used in MVC by default in 2.2.

Parameter transformers are also used by frameworks to transform the URI to which an endpoint resolves. For example, ASP.NET Core MVC uses parameter transformers to transform the route value used to match an area, controller, action, and page.

routes.MapRoute(
 name: "default",
 template: "{controller=Home:slugify}/{action=Index:slugify}/{id?}");

With the preceding route, the action SubscriptionManagementController.GetAll() is matched with the URI /subscription-management/get-all. A parameter transformer doesn’t change the route values used to generate a link. Url.Action("GetAll", "SubscriptionManagement") outputs /subscription-management/get-all.

ASP.NET Core provides API conventions for using a parameter transformers with generated routes:

  • MVC has the Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention API convention. This convention applies a specified parameter transformer to all attribute routes in the app. The parameter transformer will transform attribute route tokens as they are replaced. For more information, see Use a parameter transformer to customize token replacement.
  • Razor pages has the Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API convention. This convention applies a specified parameter transformer to all automatically discovered Razor pages. The parameter transformer will transform the folder and file name segments of Razor page routes. For more information, see Use a parameter transformer to customize page routes.

Link Generation

Added a new service called LinkGenerator, it is a singleton service that supports generating paths and absolute URIs both with and without an HttpContext. If you need to generate links in Middleware or somewhere outside of Razor then this new service will be useful to you. You can use it in Razor, but the existing APIs like Url.Action are already backed by the new service so you can continue to use those.

return _linkGenerator.GetPathByAction(
 httpContext,
 controller: "Home",
 action: "Index",
 values: new { id=42 });

For now this is useful to link to MVC actions and pages from outside of MVC. We will add additional features in the next release targeting non-MVC scenarios.

Health Checks

DbContextHealthCheck

We added a new DbContext based check for when you are using Entity Framework Core:

// Registers required services for health checks
services.AddHealthChecks()
 // Registers a health check for the MyContext type. By default the name of the health check will be the
 // name of the DbContext type. There are other options available through AddDbContextCheck to configure
 // failure status, tags, and custom test query.
 .AddDbContextCheck<MyContext>();

This check will make sure that the application can communicate with the database you configured for MyContext. By default the DbContextHealthCheck will call the CanConnectAsync method that is being added to Entity Framework Core 2.2. You can customize what operation is run when checking health using overloads of the AddDbContextCheck method.

Health Check Publisher

We added the IHealthCheckPublisher interface that has a single method you can implement:

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

If you add an IHealthCheckPublisher to DI then the health checks system will periodically execute your health checks and call PublishAsync with the result. We expect this to be useful when you are interacting with a push based health system that expects each process to call it periodically in order to determine health.

Tags

In preview3 we added the ability to tag health checks with a list of strings when you register them:

services.AddHealthChecks()
 .AddDbContextCheck<MyContext>(tags: new[] { "db" });

Once you’ve done this then you can filter execution of your checks via tag:

app.UseHealthChecks("/liveness", new HealthCheckOptions
{
 Predicate = (_) => false
});

app.UseHealthChecks("/readiness", new HealthCheckOptions
{
 Predicate = (check) => check.Tags.Contains("db")
});

We see tags as a way for consumers of health checks, application authors, to use as a convenient grouping and filtering mechanism for their health checks. Not something that health check authors will pre-populate.

You can also customize what status a failure of this check means for your application, for example if your application is written such that it can handle the database not being available then a database being down might mean Degraded rather than UnHealthy.

Validation Performance Improvements

MVC’s validation system is designed to be extensible and flexible allowing developer to determine on a per request basis what validators apply to a given model. This is great for authoring complex validation providers. However, in the most common case your application only uses the built-in validation pieces such as DataAnnotations ([Required], [StringLength] etc, or IValidatableObject) and don’t require this extra flexability.

In 2.2.0-preview3, we’re adding a feature that allows MVC to short-circuit validation if it can determine that a given model graph would not require any validation. This results in significant improvements when validating models that cannot or do not have any associated validators. This includes objects such as collections of primitives (byte[], string[], Dictionary<string, string> etc), or complex object graphs without many validators.

For this model – https://github.com/aspnet/Mvc/blob/release/2.2/benchmarkapps/BasicApi/Models/Pet.cs – the table below compares the difference in Requests Per Second (RPS) with and without the enhancement:

Description RPS Memory (MB) Avg. Latency (ms) Startup (ms) First Request (ms) Ratio
Baseline 78,738 398 3.5 547 111.3 1.00
Validation changes 90,167 401 2.9 541 115.9 1.15

HTTP Client Performance Improvements

Some significant performance improvements have been made to SocketsHttpHandler by improving the connection pool locking contention. For applications making many outgoing HTTP requests, such as some Microservices architectures, throughput should be significantly improved. Our internal benchmarks show that under load HttpClient throughput has improved by 60% on Linux and 20% on Windows. At the same time the 90th percentile latency was cut down by two on Linux. See Github #32568 for the actual code change that made this improvement.

Requests Per Second Linux (higher is better)

image

Requests Per Second Windows (higher is better)

image

Request Latency Linux (lower is better)

image

Request Latency Windows (lower is better)

image

ASP.NET Core Module

We added support for the ability to detect client disconnects when you’re using the new IIS in-process hosting model. The HttpContext.RequestAborted cancellation token now gets tripped when your client disconnnects.

The ASP.NET Core Module also features enhanced diagnostics logs that configurable via the new handler settings or environment variables that expose a higher fidelity of diagnostic information.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <location path="." inheritInChildApplications="false">
 <system.webServer>
 <handlers>
 <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
 </handlers>
 <aspNetCore processPath="dotnet" arguments=".\clientdisconnect.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
 <handlerSettings>
 <handlerSetting name="debugFile" value="debug.txt" />
 <handlerSetting name="debugLevel" value="TRACE" />
 </handlerSettings> 
 </aspNetCore>
 </system.webServer>
 </location>
</configuration>

SignalR Java Client

Preview 3 includes a few notable changes to the SignalR Java Client as we progress towards a 1.0 release:

The “groupId” for the Maven package has changed to com.microsoft.signalr. To reference the new package from a Maven POM file, add the following dependency:

<dependency>
 <groupId>com.microsoft.signalr</groupId>
 <artifactId>signalr</artifactId>
 <version>1.0.0-preview3-35501</version>
</dependency>

Or in Gradle:

implementation 'com.microsoft.signalr:signalr:1.0.0-preview3-35501'

In Preview 3 we’ve changed all the APIs to be asynchronous, using RxJava. Our Java Client documentation will be updated to show the new usage patterns. We also have support for the invoke method, allowing the client code to wait for the server method to complete. This version also includes support for serializing custom types in method arguments and return values.

The Java Client currently requires Android API Level 26 (or higher). We are investigating moving down to a lower API level before RTM. If you are planning to use SignalR in an Java-based Android application, please comment on the GitHub issue tracking our Android API level support so we know what API level would work well for our users.

Migrating an ASP.NET Core 2.1 project to 2.2

To migrate an ASP.NET Core project from 2.1.x to 2.2.0-preview3, open the project’s .csproj file and change the value of the the element to netcoreapp2.2. You do not need to do this if you’re targeting .NET Framework 4.x.

Giving Feedback

The main purpose of providing previews is to solicit feedback so we can refine and improve the product in time for the final release. Please help provide us feedback by logging issues in the appropriate repository at https://github.com/aspnet or https://github.com/dotnet. We look forward to receiving your feedback!

Posted on Leave a comment

Use Hybrid Connections to Incrementally Migrate Applications to the Cloud

As the software industry shifts to running software in the cloud, organizations are looking to migrate existing applications from on-premises to the cloud. Last week at Microsoft’s Ignite conference, Paul Yuknewicz and I delivered a talk focused on how to get started migrating applications to Azure (watch the talk free) where we walked through the business case for migrating to the cloud, and choosing the right hosting and data services.

If your application is a candidate for running in App Service, one of the most useful pieces of technology that we showed was Hybrid Connections. Hybrid Connections let you host a part of your application in Azure App Service, while calling back into resources and services not running in Azure (e.g. still on-premises). This enables you to try running a small part of your application in the cloud without the need to move your entire application and all of its dependencies at once; which is usually time consuming, and extremely difficult to debug when things don’t work. So, in this post I’ll show you how to host an ASP.NET front application in the cloud, and configure a hybrid connection to connect back to a service on your local machine.

Publishing Our Sample App to the Cloud

For the purposes of this post, I’m going to use the Smart Hotel 360 App sample that uses an ASP.NET front end that calls a WCF service which then accesses a SQL Express LocalDB instance on my machine.

The first thing I need to do is publish the ASP.NET application to App Service. To do this, right click on the “SmartHotel.Registration.Web” project and choose “Publish”

clip_image001

The publish target dialog is already on App Service, and I want to create a new one, so I will just click the “Publish” button.

This will bring up the “Create App Service” dialog.  Next, I will click “Create” and wait for a minute while the resources in the cloud are created and the application is published.

clip_image003

When it’s finished publishing, my web browser will open to my published site. At this point, there will be an error loading the page since it cannot connect to the WCF service. To fix this we’ll add a hybrid connection.

image

Create the Hybrid Connection

To create the Hybrid Connection, I navigate to the App Service I just created in the Azure Portal. One quick way to do this is to click the “Managed in Cloud Explorer” link on the publish summary page

clip_image005

Right click the site, and choose “Open in Portal” (You can manually navigate to the page by logging into the Azure portal, click App Services, and choose your site).

clip_image006

To create the hybrid connection:

Click the “Networking” tab in the Settings section on the left side of the App Service page

Click “Configure your hybrid connection endpoints” in the “Hybrid connections” section

image

Next, click “Add a hybrid connection”

Then click “Create a new hybrid connection”

clip_image010

Fill out the “Create new hybrid connection” form as follows:

  • Hybrid connection Name: any unique name that you want
  • Endpoint Host: This is the machine URL your application is currently using to connect to the on-premises resource. In this case, this is “localhost” (Note: per the documentation, use the hostname rather than a specific IP address if possible as it’s more robust)
  • Endpoint Port: The port the on-premises resource is listening on. In this case, the WCF service on my local machine is listening on 2901
  • Servicebus namespace: If you’ve previously configured hybrid connections you can re-use an existing one, in this case we’ll create a new one, and give it a name

clip_image011

Click “OK”. It will take about 30 seconds to create the hybrid connection, when it’s done you’ll see it appear on the Hybrid connections page.

Configure the Hybrid Connection Locally

Now we need to install the Hybrid Connection Manager on the local machine. To do this, click the “Download connection manager” on the Hybrid connections page and install the MSI.

clip_image013

After the connection manager finishes installing, launch the “Hybrid Connections Manager UI”, it should appear in your Windows Start menu if you type “Hybrid Connections”. (If for some reason it doesn’t appear on the Start Menu, launch it manually from “C:\Program Files\Microsoft\HybridConnectionManager <version#>”)

Click the “Add a new Hybrid Connection” button in the Hybrid Connections Manager UI and login with the same credentials you used to publish your application.

clip_image015

Choose the subscription you used published your application from the “Subscription” dropdown, choose the hybrid connection you just created in the portal, and click “Save”.

clip_image017

In the overview, you should see the status say “Connected”. Note: If the state won’t change from “Not Connected”, I’ve found that rebooting my machine fixes this (it can take a few minutes to connect after the reboot).

clip_image019

Make sure everything is running correctly on your local machine, and then when we open the site running in App Service we can see that it loads with no error. In fact, we can even put a breakpoint in the GetTodayRegistrations() method of Service.svc.cs, hit F5 in Visual Studio, and when the page loads in App Service the breakpoint on the local machine is hit!

clip_image021

Conclusion

If you are looking to move applications to the cloud, I hope that this quick introduction to Hybrid Connections will enable you to try moving things incrementally. Additionally, you may find these resources helpful:

As always, if you have any questions, or problems let me know via Twitter, or in the comments section below.

Posted on Leave a comment

Blazor 0.6.0 experimental release now available

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

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

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

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

Get Blazor 0.6.0

Install the following:

  1. .NET Core 2.1 SDK (2.1.402 or later).
  2. Visual Studio 2017 (15.8 or later) with the ASP.NET and web development workload selected.
  3. The latest Blazor Language Services extension from the Visual Studio Marketplace.
  4. The Blazor templates on the command-line:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates
    

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

Upgrade an existing project to Blazor 0.6.0

To upgrade a Blazor 0.5.x project to 0.6.0:

  • Install the prerequisites listed above.
  • Update the Blazor package and .NET CLI tool references to 0.6.0. The upgraded Blazor project file should look like this:

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

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

Templated components

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

Template parameters

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

TemplatedTable.cshtml

@typeparam TItem

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

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

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

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

Template context parameters

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

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

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

Generic-typed components

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

GenericComponent.cshtml

@typeparam TItem

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

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

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

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

Razor templates

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

@<tag>...<tag>

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

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

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

@template

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

Use server-side Blazor with the Azure SignalR Service

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

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

  1. Create a new server-side Blazor app.

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

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

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

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

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

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

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

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

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

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

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

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

Give feedback

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

Blazor survey

Thanks for trying out Blazor!

Posted on Leave a comment

ASP.NET Core 2.2.0-preview2 now available

Today we’re very happy to announce that the second preview of the next minor release of ASP.NET Core and .NET Core is now available for you to try out. We’ve been working hard on this release over the past months, along with many folks from the community, and it’s now ready for a wider audience to try it out and provide the feedback that will continue to shape the release.

How do I get it?

You can download the new .NET Core SDK for 2.2.0-preview2 (which includes ASP.NET 2.2.0-preview2) from https://www.microsoft.com/net/download/dotnet-core/2.2

Visual Studio requirements

Customers using Visual Studio should also install and use the Preview channel of Visual Studio 2017 (15.9 Preview 2) in addition to the SDK when working with .NET Core 2.2 and ASP.NET Core 2.2 projects. Please note that the Visual Studio preview channel can be installed side-by-side with existing an Visual Studio installation without disrupting your current development environment.

Azure App Service Requirements

If you are hosting your application on Azure App Service, you can follow these instructions to install the required site extension for hosting your 2.2.0-preview2 applications.

Impact to machines

Please note that is a preview release and there are likely to be known issues and as-yet-to-be discovered bugs. While the .NET Core SDK and runtime installs are side-by-side, your default SDK will become the latest one. If you run into issues working on existing projects using earlier versions of .NET Core after installing the preview SDK, you can force specific projects to use an earlier installed version of the SDK using a global.json file as documented here. Please log an issue if you run into such cases as SDK releases are intended to be backwards compatible.

What’s new in Preview 2

For a full list of changes, bug fixes, and known issues you can read the release notes.

SignalR Java Client updated to support Azure SignalR Service

The SignalR Java Client, first introduced in preview 1, now has support for the Azure SignalR Service. You can now develop Java and Android applications that connect to a SignalR server using the Azure SignalR Service. To get this new functionality, just update your Maven or Gradle file to reference version 0.1.0-preview2-35174 of the SignalR Client package.

Problem Details support

In 2.1.0, MVC introduced ProblemDetails, based on the RFC 7807 specification for carrying detils of an error with a HTTP Response. In preview2, we’re standardizing around using ProblemDetails for client error codes in controllers attributed with ApiControllerAttribute. An IActionResult returning a client error status code (4xx) will now return a ProblemDetails body. The result additionally includes a correlation ID that can be used to correlate the error using request logs. Lastly, ProducesResponseType for client errors, default to using ProblemDetails as the response type. This will be documented in Open API / Swagger output generated using NSwag or Swashbuckle.AspNetCore. Documentation for configuring the ProblemDetails response can be found here – https://aka.ms/AA2k4zg.

ASP.NET Core Module Improvements

We’ve introduced a new module (aspNetCoreModuleV2) for hosting ASP.NET Core application in IIS in 2.2.0-preview1. This new module adds the ability to host your .NET Core application within the IIS worker process and avoids the additional cost of reverse-proxying your requests over to a separate dotnet process.

ASP.NET Core 2.2.0-preview2 or newer projects default to the new in-process hosting model. If you are upgrading from preview1, you will need to add a new project property to your .csproj file.

<PropertyGroup>
 <TargetFramework>netcoreapp2.2</TargetFramework>
 <AspNetCoreHostingModel>inprocess</AspNetCoreHostingModel>
</PropertyGroup>

Visual Studio 15.9-preview2 adds the ability to switch your hosting model as part of your development-time experience.

Hosting in IIS

To deploy applications targeting ASP.NET Core 2.2.0-preview2 on servers with IIS, you require a new version of the 2.2 Runtime & Hosting Bundle on the target server. The bundle is available at https://www.microsoft.com/net/download/dotnet-core/2.2.

Caveats

There are a couple of caveats with the new in-process hosting model: – You are limited to one application per IIS Application Pool. – No support for .NET Framework. The new module is only capable of hosting .NET Core in the IIS process.

If you have a ASP.NET Core 2.2 app that’s using the in process hosting model, you can turn it off by setting the <AspNetCoreHostingModel> element to outofprocess in your .csproj file.

Template Updates

We’ve cleaned up the Bootstrap 4 project template work that we started in Preview 1. We’ve also added support to the default Identity UI for using both Bootstrap 3 & 4. For compatibility with existing apps the default Bootstrap version for the default UI is now Bootstrap 3, but you can select which version of Boostrap you want to use when calling AddDefaultUI.

HealthCheck Improvements

There are a few small, but important, changes to health checks in preview2.

You can now call AddCheck<T> where T is a type of IHealthCheck:

services.AddHealthChecks()
 .AddCheck<MyHealthCheck>();

This will register your health check as a transient service, meaning that each time the health check service is called a new instance will be created. We allow you to register IHealthCheck implementations with any service lifetime when you register them manually:

services.AddHealthChecks();
services.AddSingleton<IHealthCheck, MySingletonCheck>();

A scope is created for each invocation of the HealthChecksService. As with all DI lifetimes you should be careful when creating singleton objects that depend on services with other lifetimes as described here.

You can filter which checks you want to execute when using the middleware or the HealthCheckService directly. In this example we are executing all our health checks when a request is made on the ready path, but just returning a 200 OK when the live path is hit:

// The readiness check uses all of the registered health checks (default)
app.UseHealthChecks("/health/ready");

// The liveness check uses an 'identity' health check that always returns healthy
app.UseHealthChecks("/health/live", new HealthCheckOptions()
{
 // Exclude all checks, just return a 200.
 Predicate = (check) => false,
});

You might do this if, for example, you are using Kubernetes and want to run a comprehensive set of checks before traffic is sent to your application but otherwise are OK as long as you are reachable and still running.

What’s still to come?

We are investaging adding a tags mechanism to checks, so that they can be set and filtered on. We also want to provide an Entity Framework specific check that will check whatever database has been configured to be used with your DbContext.

Migrating an ASP.NET Core 2.1 project to 2.2

To migrate an ASP.NET Core project from 2.1.x to 2.2.0-preview2, open the project’s .csproj file and change the value of the the element to netcoreapp2.2. You do not need to do this if you’re targeting .NET Framework 4.x.

Giving Feedback

The main purpose of providing previews is to solicit feedback so we can refine and improve the product in time for the final release. Please help provide us feedback by logging issues in the appropriate repository at https://github.com/aspnet or https://github.com/dotnet. We look forward to receiving your feedback!

Posted on Leave a comment

Library Manager Released in 15.8

Microsoft Library Manager (LibMan) is now available in the general release of Visual Studio 2017 as of v15.8. LibMan first previewed earlier this year, and now, after a much-anticipated wait, LibMan is available in the stable release of Visual Studio 2017 bundled as a default component in the ASP.NET and web development workload.

In the announcement about the preview, we showed off the LibMan manifest (libman.json), providers for filesystem and CDNJS, and the menu options for Restore, Clean and Enable Restore-on-Build. Included as part of the release in v15.8 we’ve also added:
– a new dialog for adding library files
– a new library provider (UnPkg)
– the LibMan CLI (cross-platform DotNet global tool)

What is LibMan?

LibMan is a tool that helps to find common client-side library files and add them to your web project. If you need to pull JavaScript or CSS files into your project from libraries like jQuery or bootstrap, you can use LibMan to search various global providers to find and download the files you need.

Library Manager in Visual Studio

To learn more about LibMan, refer to the official Microsoft Docs: Client-side library acquisition in ASP.NET Core with LibMan.

What’s new?

New dialog for adding library files

We’ve added tooling inside Visual Studio to add library files to a web project. Inside a web project, you can right-click any folder (or the project root) and select Add–>Client-Side Library…
This will launch the Add Client-Side Library dialog, which provides a convenient interface for browsing the libraries and files available in various providers, as well as setting the target location for files in your project.

LibMan Add Files Dialog

New Provider: UnPkg

Along with CDNJS and FileSystem, we’ve built an UnPkg provider. Based on the UnPkg.com website, which sits on top of the npm repo, the UnPkg provider opens access to many more libraries than just those referenced by the CDNJS catalogue.

LibMan CLI available on NuGet

Timed with the release of Visual Studio 2017 v15.8, the LibMan command line interface (CLI) has been developed as a global tool for the DotNet CLI and is now available on NuGet. Look for Microsoft.Web.LibraryManager.Cli

You can install the LibMan CLI with the following command:


> dotnet tool install -g Microsoft.Web.LibraryManager.Cli

The CLI is cross-platform, so you’ll be able to use it anywhere that .NET Core is supported (Windows, Mac, Linux). You can perform a variety of LibMan operations including install, update, and restore, plus local cache management.

LibMan CLI example

To learn more about the LibMan CLI, see the blog post: LibMan CLI Release or refer to the official Microsoft Docs: Use the LibMan command-line interface (CLI) with ASP.NET Core

Related Links

Happy coding!

Justin Clareburt, Senior Program Manager, Visual Studio

Justin Clareburt (justcla) Profile Pic Justin Clareburt is the Web Tools PM on the Visual Studio team. He has over 20 years of Software Engineering experience and brings to the team his expert knowledge of IDEs and a passion for creating the ultimate development experience.

Follow Justin on Twitter @justcla78

Posted on Leave a comment

ASP.NET Core 2.2.0-preview1: Endpoint Routing

What is it?

We’re making a big investment in routing starting in 2.2 to make it interoperate more seamlessly with middleware. For 2.2 this will start with us making a few changes to the routing model, and adding some minor features. In 3.0 the plan is to introduce a model where routing and middleware operate together naturally. This post will focus on the 2.2 improvements, we’ll discuss 3.0 a bit further in the future.

So, without further ado, here are some changes coming to routing in 2.2.

How to use it?

The new routing features will be on by default for 2.2 applications using MVC. UseMvc and related methods with the 2.2 compatibility version will enable the new ‘Endpoint Routing’ feature set. Existing conventional routes (using MapRoute) or attribute routes will be mapped into the new system.

public void ConfigureServices(IServiceProvider services)
{
 ...
 
 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

public void Configure(IApplicationBuilder app)
{
 ....
 
 app.UseMvc();
}

If you need to specifically revert the new routing features, this can be done by setting an option. We’ve tried to make the new endpoint routing system as backwards compatible as is feasible. Please log issues at https://github.com/aspnet/Routing if you encounter problems.

We don’t plan to provide an experience in 2.2 for using the new features without MVC – our focus for right now is to make sure we can successfully shift MVC applications to the new infrastructure.

Link Generator Service

We’re introducing a new singleton service that will support generating a URL. This new service can be used from middleware, and does not require an HttpContext. For right now the set of things you can link to is limited to MVC actions, but this will expand in 3.0.

public class MyMiddleware
{
 public MyMiddleware(RequestDelegate next, LinkGenerator linkGenerator) { ... }
 
 public async Task Invoke(HttpContext httpContext)
 {
 var url = _linkGenerator.GenerateLink(new { controller = "Store",
 action = "ListProducts" });
 
 httpContext.Response.ContentType = "text/plain";
 return httpContext.Response.WriteAsync($"Go to {url} to see some cool stuff.");
 }
}

This looks a lot like MVC’s link generation support (IUrlHelper) for now — but it’s usable anywhere in your application. We plan to expand the set of things that are possible during 2.2.

Performance Improvements

One of the biggest reasons for us to revisit routing in 2.2 is to improve the performance of routing and MVC’s action selection.

We still have more work to, but the results so far are promising:
image

This chart shows the trend of Requests per Second (RPS) of our MVC implementation of the TechEmpower plaintext benchmark. We’ve improved the RPS of this benchmark about 10% from 445kRPS to 515kRPS.

To test more involved scenarios, we’ve used the Swagger/OpenAPI files published by Azure and Github to build code-generated routing benchmarks. The Azure API benchmark has 5160 distinct HTTP endpoints, and the Github benchmark has 243. The new routing system is significantly faster at processing the route table of these real world APIs than anything we’ve had before. In particular MVC’s features that select actions such as matching on HTTP methods and [Consumes(...)] are significantly less costly.

Improvements to link generation behavior for attribute routing

We’re also using this opportunity to revisit some of the behaviors that users find confusing when using attribute routing. Razor Pages is based on MVC’s attribute routing infrastructure and so many new users have become familiar with these problems lately. Inside the team, we refer to this feature as ‘route value invalidation’.

Without getting into too many details, conventional routing always invalidates extra route values when linking to another action. Attribute routing didn’t have this behavior in the past. This can lead to mistakes when linking to another action that uses the same route parameter names. Now both forms of routing invalidate values when linking to another action.

A conceptual understanding

The new routing system is called ‘Endpoint Routing’ because it represents the route table as a set of Endpoints that can be selected by the the routing system. If you’ve ever thought about how attribute routing might work in MVC, the above description should not be surprising. The new part is that a bunch of concerns traditionally handled by MVC have been pushed down to a very low level of the routing system. Endpoint routing now processes HTTP methods, [Consumes(...)], versioning, and other policies that used to be part of MVC’s action selection process.

In contrast to this, the existing routing system models the application is a list of ‘Routes’ that need to be processed in order. What each route does is a black-box to the routing system – you have to run the route to see if it will match.

To make MVC’s conventional routing work, we flatten the list of actions multiplied by the number of routes into a list of endpoints. This flattening allows us to process all of MVC’s requirements very efficiently inside the routing system.


The list of endpoints gets compiled into a tree that’s easy for us to walk efficiently. This is similar to what attribute routing does today but using a different algorithm and much lower complexity. Since routing builds a graph based on the endpoints, this means that the complexity of the tree scales very directly with your usage of features. We’re confident that we can scale up this design nicely while retaining the pay-for-play characteristics.

New round-tripping route parameter syntax

We are introducing a new catch-all parameter syntax {**myparametername}. During link generation, the routing system will encode all the content in the value captured by this parameter except the forward slashes.
Note that the old parameter syntax {*myparametername} will continue to work as it did before. Examples:

  • For a route defined using the old parameter syntax : /search/{*page},
    a call to Url.Action(new { category = "admin/products" }) would generate a link /search/admin%2Fproducts (notice that the forward slash is encoded)
  • For a route defined using the new parameter syntax : /search/{**page},
    a call to Url.Action(new { category = "admin/products" }) would generate a link /search/admin/products

What is coming next?

Expect more refinement and polish on the LinkGenerator API in the next preview. We want to make sure that this new API will support a variety of scenarios for the foreseeable future.

How can you help?

There are a few areas where you can provide useful feedback during this preview. We’re interested in any thoughts you have of course, these are a few specific things we’d like opinions on. The best place to provide feedback is by opening issues at https://github.com/aspnet/Routing

What are you using IRouter for? The ‘Endpoint Routing’ system doesn’t support IRouter-based extensibility, including inheriting from Route. We want what you’re using IRouter for today so we can figure out how to accomplish those things in the future.

What are you using IActionConstraint for? ‘Endpoint Routing’ supports IActionConstraint-based extensibility from MVC, but we’re trying to find better ways to accomplish these tasks.

What are your ‘most wanted’ issues from Routing? We’ve revisited a bunch of old closed bugs and brought back a few for reconsideration. If you feel like there are missing details or bugs in routing that we should consider please let us know.

Caveats and notes

We’ve worked to make the new routing system backwards compatible where possible. If you run into issues we’d love for you to report them at https://github.com/aspnet/Routing.

DataTokens are not supported in 2.2.0-preview1. We plan to address this for the next preview.

By nature the new routing system does not support IRouter based extensibility.

Generating links inside MVC to conventionally routed actions that don’t yet exist will fail (resulting in the empty string). This is in contrast to the current MVC behavior where linking usually succeeds even if the action being linked hasn’t been defined yet.

We know that the performance of link generation will be bad in 2.2.0-preview1. We worked hard to get the API definitions in so that you could try it out, and ignored performance. Expect the performance of URL generation to improve significantly for the next preview.

Endpoint routing does not support WebApiCompatShim. You must use the 2.1 compatibility switch to continue using the compat shim.

Posted on Leave a comment

ASP.NET Core 2.20-preview1: Open API Analyzers & Conventions

What is it?

Open API (alternatively known as Swagger) is a language-agnostic specification for describing REST APIs. The Open API ecosystem has tools that allows for discovering, testing and producing client code using the specification. Support for generating and visualizing Open API documents in ASP.NET Core MVC is provided via community driven projects such as NSwag, and Swashbuckle.AspNetCore. Visit https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-2.1 to learn more about Open API Swagger and for details on configuring your applications to use it.

For 2.2, we’re investing in tooling and runtime experiences to to allow developers to produce better Open API documents. This work ties in with ongoing work to perform client code SDK generation during build.

How to use it?

Analyzer

For 2.2, we’re introducing a new API-specific analyzers NuGet package – Microsoft.AspNetCore.Mvc.Api.Analyzers. These analyzers work with controllers annotated with ApiController introduced in 2.1, while building on API conventions that we’re also introducing in this release. To start using this, install the package:


<PackageReference Include="Microsoft.AspNetCore.Mvc.Api.Analyzers"
 Version="2.2.0-preview1-35029"
 PrivateAssets="All" />

Open API documents contain each status code and response type an operation may return. In MVC, you use attributes such as ProducesResponseType and Produces to document these. The analyzer inspects controllers annotated with ApiController and identifies actions that do not entirely document their responses. You should see this as warnings (squiggly lines) highlighting return types that aren’t documented as well as warnings in the output. In Visual Studio, this should additionally appear under the “Warnings” tab in the “Error List” dialog. You now have the opportunity to address these warnings using code fixes.

Let’s look at the analyzer in action:

The analyzer identified that the action returned a 404 but did not document it using a ProducesResponseTypeAttribute. We used a code fix to document this. The added attributes would now become available for Swagger / Open API tools to consume. It’s a great way to identify areas of your application that are lacking swagger documentation and correct it.

Conventions

If your controllers follows some common patterns, e.g. they are all primarily CRUD endpoints, and you aren’t already using ProducesResponseType or Produces to document them, you could consider using API conventions. Conventions let you define the most common “conventional” return types and status codes that you return from your action, and apply them to individual actions or controllers, or all controllers in an assembly. Conventions are a substitute to decorating individual actions with ProducesResponseType attributes.

By default, ASP.NET Core MVC 2.2 ships with a set of default conventions – DefaultApiConventions – that’s based on the controller that ASP.NET Core scaffolds. If your actions follow the pattern that scaffolding produces, you should be successful using the default conventions.

At runtime, ApiExplorer understand conventions. ApiExplorer is MVC’s abstraction to communicate with Open API document generators. Attributes from the applied convention get associated with an action and will be included in action’s Swagger documentation. API analyzers also understand conventions. If your action is unconventional i.e. it returns a status code that is not documented by the applied convention, it will produce a warning, encouraging you to document it.

There are 3 ways to apply a convention to a controller action:

  • Applying the ApiConventionType attribute as an assembly level attribute. This applies the specified convention to all controllers in an assembly.
[assembly: ApiConvention(typeof(DefaultApiConventions))]
  • Using the ApiConventionType attribute on a controller.
[ApiConvention(typeof(DefaultApiConventions))]
[ApiController]
[Route("/api/[controller]")]
public class PetsController : ControllerBase
{
 ...
}
  • Using ApiConventionMethod. This attributes accepts both the type and the convention method.
// PUT: api/Pets/5
[ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Put))]
[HttpPut("{id}")]
public async Task<ActionResult<Pet>> PutPet(long id, Pet pet)
{
 ...
}

Like many other features in MVC, more specific attributes will supersede less specific ones. An API metadata attribute such as ProducesResponseType or Produces applied to an action will stop applying any convention atributes. The ApiConventionMethod will supersede a ApiConventionType attribute applied to the method’s controller or the assembly; and an ApiConventionType attribute applied to a controller will supersede ones applied to the assembly.

Authoring conventions

A convention is a static type with methods. These methods are annotated with ProducesResponseType or ProducesDefaultResponseType attributes.

public static class MyAppConventions
{
 [ProducesResponseType(200)]
 [ProducesResponseType(404)]
 public static void Find(int id)
 {

 }
}

Applying this convention to an assembly would result in the convention method applying to any action with the name Find and having exactly one parameter named id, as long as they do not have other more specific metadata attributes.

In addition to ProducesResponseType and ProducesDefaultResponseType, two additional attributes – ApiConventionNameMatch and ApiConventionTypeMatch – can be applied to the convention method that determines the methods they apply to.

[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
public static void Find(
 [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Suffix)]
 int id)
{ }

The ApiConventionNameMatchBehavior.Prefix applied to the method, indicates that the convention can match any action as long as it starts with the prefix “Find”. This will include methods such as Find, FindPet or FindById. The ApiConventionNameMatchBehavior.Suffix applied to the parameter, indicates that the convention can match methods with exactly one parameter that terminate in the suffix id. This will include parameters such as id, or petId. ApiConventionTypeMatch can be similarly applied to types to constrain the type of the parameter. A params[] arguments can be used to indicate remaining parameters that do not need not be explicitly matched.

An easy way to get started authoring a custom convention is to start by copying the body of DefaultApiConventions and modifying it. Here’s a link to the source of the type: https://raw.githubusercontent.com/aspnet/Mvc/release/2.2/src/Microsoft.AspNetCore.Mvc.Core/DefaultApiConventions.cs

Feedback

This is one on our earliest forays in trying to use tooling to enhance runtime experiences. We’re interested in any thoughts you have about this as well as your experiences using this in your applications. The best place to provide feedback is by opening issues at https://github.com/aspnet/Mvc.

Additional help

Posted on Leave a comment

LibMan CLI Released

The Command Line Interface (CLI) is now available for Microsoft Library Manager (LibMan) and can be downloaded via NuGet. Look for Microsoft.Web.LibraryManager.Cli
The LibMan CLI is cross-platform, so you’ll be able to use it anywhere that .NET Core is supported (Windows, Mac, Linux).

Install the LibMan CLI

To install LibMan, type:

> dotnet tool install --global Microsoft.Web.LibraryManager.Cli

Once the LibMan CLI is installed, you can start using LibMan from the root of your web project (or any folder).

Using LibMan from the Command Line

When using LibMan CLI, begin commands with “libman” then follow with the action you wish to invoke.
For example, to install all files from the latest version of jquery, type:

> libman install jquery

Follow the prompts to select the provider and destination. Type the values you want, or press [Enter] to accept the defaults.

The install operation creates a libman.json file in the current directory if one does not already exist, then adds the new library configuration. It then downloads the files and places them in the destination folder. See the example below.

LibMan CLI example

To learn more about the LibMan CLI, refer to the LibMan CLI documentation on the Library Manager Wiki.

Happy coding!

Justin Clareburt, Senior Program Manager, Visual Studio

Justin Clareburt (justcla) Profile Pic Justin Clareburt is the Web Tools PM on the Visual Studio team. He has over 20 years of Software Engineering experience and brings to the team his expert knowledge of IDEs and a passion for creating the ultimate development experience.

Follow Justin on Twitter @justcla78

Posted on Leave a comment

Improvements in Visual Studio 2017 15.8 for web developers

This week we released Visual Studio 2017 version 15.8. Our 15.8 update brings the following improvements for web developers:

  • Custom docker image tags during Publish
  • Zip push deployment for Azure Functions
  • Managing user secrets in ASP.NET Framework projects (targeting .NET 4.7.1 or higher)
  • Enabling Application Insights as part of publishing to Azure App Service
  • Optimizing build performance for solutions containing ASP.NET Framework projects
  • Author and source information for ASP.NET Core templates

Custom docker image tags during Publish

You can now customize the “Image tag” for Docker containers when publishing them to a container registry. The value can either be automatically generated by Visual Studio every time you publish (the previous behavior), or it be manually changed if you need a consistent tag (e.g. “latest”):

Screenshot of new property called "Image Tag" in Publish

Zip push deployment & run from zip for Azure Functions

Visual Studio now provides the option to deploy and run Azure Functions projects as zip files:

Screenshot of publish and run from zip option in Publish

Run-From-Zip is a runtime feature that allows ‘mounting’ a zip file and running directly from it. Your App runs directly over the ‘mounted’ zip file, which completely takes over your wwwrootfolder (which becomes read-only).  Using run from Zip offers the following benefits:

  • Atomicity: when your application is deployed as as single unit, and updated as a single unit meaning publishing an update will never leave your app in a partially updated state
  • Faster deployment of large applications
  • Improved cold start performance

Managing user secrets in ASP.NET Framework projects (targeting .NET 4.7.1 or higher)

A feature that ASP.NET Framework projects were missing compared to ASP.NET Core was support for storing application secrets (e.g. connection strings, API keys, etc.) in a file outside of source control unique to each user. Now, with .NET Framework 4.7.1 and Visual Studio 15.8 it’s as simple as right clicking on the project in Solution Explorer and selecting “Manage User Secrets”:

Screenshot of the new "Manage user secrets" menu item when right clicking in Solution Explorer

Visual Studio will take care of the rest including downloading the necessary NuGet packages, updating the web.config file, creating the secrets file on disk and finally opening it for you to edit:

Screenshot of an example user secrets file

Note: Only available for projects targeting .NET Framework 4.7.1 or higher, if you can’t see the menu item make sure you have the 4.7.1 targeting pack installed and that the project is actually targeting 4.7.1, you can change it from project properties:

Screenshot of the run time drop-down available in project properties

Enabling Application Insights as part of publishing to Azure App Service

When publishing to Azure App Service, Visual Studio asks you to either create a new App Service or re-use an existing one. If you choose to create a new App Service to host your application, Visual Studio now offers you the ability to also provision and configure Application Insights:

Screenshot of new drop-down related to Application Insights when creating a new App Service

All you need to do is pick the region you would like Application Insights to be provisioned in and Visual Studio will make sure it’s configured to pick up telemetry events and metrics from the new App Service. If you wish to add custom events and metrics follow this guide. Of course, you can always set the field to “None” and Visual Studio will not provision nor configure Application Insights on your behalf.

Optimizing build performance for solutions containing ASP.NET Framework projects

We added a new menu item under Build | ASP.NET Compilation | Optimize Build Performance for Solution:

Screenshot of new menu item Build | ASP.NET Compilation | Optimize Build Performance for Solution

This new menu item is applicable to solutions containing ASP.NET Framework projects only and is not applicable to ASP.NET Core projects. Its purpose is to update specific ASP.NET related NuGet packages referenced by the codebase.

When an ASP.NET Framework codebase is using out-of-date packages, the inner loop performance of Visual Studio is impacted. The motivation behind updating these packages is to restore optimal inner loop performance for a given solution.  You will only have to do this once per solution and you will not have to deal with this problem in the future since the new package is designed in a way that even when it gets out of date it doesn’t affect the inner loop performance in Visual Studio.

Author and source information for ASP.NET Core templates

The dialog for new ASP.NET Core projects now shows you the author and source for the selected template:

Screenshot of author and source information available in the New Project Dialog

  • If the template is coming from a .NET Core SDK installed on the machine, the dialog will now display the version of the SDK as the source
  • If the template is coming from a VSIX (i.e. Visual Studio extension) installed on the machine, the dialog will now display the name of the VSIX as the source

Conclusion

If you’re interested in the many other great things that Visual Studio 2017 15.8 brings, check out our Visual Studio 15.8 post on the Visual Studio blog.

We hope that you’ll give 15.8 a try and let us know how it works for you. If you run into any issues please report them using Visual Studio, or let us know what you think below, or via Twitter.

Posted on Leave a comment

Blazor 0.5.0 experimental release now available

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

New features in this release:

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

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

Get Blazor 0.5.0

To get setup with Blazor 0.5.0:

  1. Install the .NET Core 2.1 SDK (2.1.300 or later).
  2. Install Visual Studio 2017 (15.7 or later) with the ASP.NET and web development workload selected.
  3. Install the latest Blazor Language Services extension from the Visual Studio Marketplace.
  4. Install the Blazor templates on the command-line:

    dotnet new -i Microsoft.AspNetCore.Blazor.Templates
    

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

Upgrade an existing project to Blazor 0.5.0

To upgrade an existing Blazor project from 0.4.0 to 0.5.0:

  • Install all of the required bits listed above.
  • Update your Blazor package and .NET CLI tool references to 0.5.0. Your upgraded Blazor project file should look like this:

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
    <PropertyGroup>
 <TargetFramework>netstandard2.0</TargetFramework>
 <RunCommand>dotnet</RunCommand>
 <RunArguments>blazor serve</RunArguments>
 <LangVersion>7.3</LangVersion>
    </PropertyGroup>
    
    <ItemGroup>
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Browser" Version="0.5.0" />
 <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.5.0" />
 <DotNetCliToolReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.5.0" />
    </ItemGroup>
    
    </Project>
    
  • Update index.html to replace the blazor-boot script tag with a normal script tag that references _framework/blazor.webassembly.js..

    index.html

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

    Program.cs

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

    Startup.cs

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

What is server-side Blazor?

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

Blazor client-side

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

Blazor web worker

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

Blazor Electron

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

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

Blazor server-side

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

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

Of course there are some downsides too:

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

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

Get started with server-side Blazor

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

dotnet new blazorserverside -o BlazorApp1

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

cd BlazorApp1.Server
dotnet run

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

Blazor server-side template

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

Blazor server-side running app

Blazor server-side download size

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

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

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

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

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

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

Startup model

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

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

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

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

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

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

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

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

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

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

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

State management

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

JavaScript interop changes

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

Calling JavaScript from .NET

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

exampleJsInterop.js

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

ExampleJsInterop.cs

using Microsoft.JSInterop;

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

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

Calling .NET from JavaScript

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

JavaScriptInteroperable.cs

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

dotnetInterop.js

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

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

ExampleJsInterop.cs

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

exampleJsInterop.js

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

HelloHelper.cs

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

 public string Name { get; set; }

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

Output

Hello, Blazor!

Add Blazor to any HTML file

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

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

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

Render raw HTML

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

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

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

@((MarkupString)myMarkup)

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

Component parameter snippet

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

Debugging

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

To debug your client-side Blazor app in Chrome:

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

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

Blazor debugging error page

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

Blazor debugging

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

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

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

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

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

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

Community

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

Give feedback

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

Blazor survey

Thanks for trying out Blazor!