Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

What's new in ASP.NET Core 3 for React SPAs?

September 10, 2019
dotnetreact

ASP.NET Core 3 has recently been released. What are the new features that React SPAs can take advantage of? Let’s find out …

MVC service registration

There are some new extension methods for adding the MVC related services in the ConfigureServices method in Startup class. AddMvc will continue to work as usual adding all the MVC related services. However we now have AddControllers, AddControllersWithViews and AddRazorPages which add services for more specific scenarios:

  • AddControllers. This can be used when the app is purely a web API and doesn’t need any server side views or Razor pages
public void ConfigureServices(IServiceCollection services)
{
  services.AddControllers();
}
  • AddControllersWithViews. This can be used when the app is a web API some some server side views
  • AddRazorPages. This can be used when the app uses Razor pages. Note that AddControllers or AddControllersWithViews will need to be called as well in order to get the web API features

Endpoint routing

Endpoint routing separates the process of matching which endpoint will execute from the actual running of that endpoint.  This allows route information to be available earlier in the HTTP request processing pipeline.

To create endpoints for all our API controllers in ASP.NET Core 3.0 we replace app.UseMvc with app.UseEndpoints:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  ...

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

For more information on endpoint routing see this great post from Areg Sarkissian.

Built-in JSON support

ASP.NET Core no longer relies on Json.NET to serialize and deserialize JSON. A JsonSerializer class has been added in the System.Text.Json namespace containing Serialize and Deserialize methods. Internally ASP.NET Core uses this in the model binding process. If our web API needs to call other web APIs we can use this to deserialize the response:

var jsonContent = await response.Content.ReadAsStringAsync();
var user = JsonSerializer.Deserialize<User>(jsonContent, new JsonSerializerOptions
{
  PropertyNameCaseInsensitive = true
});

C# 8

C# is packed with useful features including nullable reference types. We need to enable nullable reference types in our project file as follows:

<PropertyGroup>
  ...
  <LangVersion>8.0</LangVersion>
  <Nullable>enable</Nullable>
</PropertyGroup>

Reference types are then not nullable by default. Visual Studio will then warn us when a null reference exception may occur in our code:

nullable reference types

Switch expressions are cool as well. These are ideal for mapping code, saving us some valuable key strokes:

public static string GetLevel(int level) =>
  level switch
  {
    1 => "low",
    2 => "medium",
    3 => "high",
    _ => throw new ArgumentException("invalid level"),
  };

Checkout the docs to learn about the other C# 8 features.

SPA template can include authentication and authorisation

When using the SPA template to create a new project, the option to include authentication is now available:

spa with auth 1024x732

The example web API controller implements a protected endpoint using the Authorize attribute:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    ...
}

Notice also that the example web API controller now inherits from ControllerBase and is decorated with the ApiController attribute. Using ControllerBase means that the class doesn’t contain unnecessary stuff for handling server side views. The ApiController attribute means that invalid request models will return HTTP status code 400 (bad request) without us having to do any work in action methods.

The React client uses a AuthorizeService class to encapsulate the interaction with the identity server. This is a nice wrapper around the oidc-client npm package.

The React client also contains AuthorizeRoute component so that authorized paths can easily be implemented:

<Layout>
  <Route exact path='/' component={Home} />
  <Route path='/counter' component={Counter} />
  <AuthorizeRoute path='/fetch-data' component={FetchData} />
  <Route path={ApplicationPaths.ApiAuthorizationPrefix} component={ApiAuthorizationRoutes} />
</Layout>

If an unauthenticated user accesses a protected route, they will be redirected to the identity server to authenticate. Neat!

Create React App 3.x

The version of Create React App that the SPA template uses has been bumped from v1 to v3. Don’t get too excited though, the React version is still very old and pre hooks. TypeScript is also listed as a dependency but the project doesn’t appear to use it.

"dependencies": {
  "babel-eslint": "10.0.1",
  "bootstrap": "^4.1.3",
  "jquery": "^3.4.1",
  "merge": "^1.2.1",
  "oidc-client": "^1.9.0-beta.4",
  "react": "^16.0.0",
  "react-dom": "^16.0.0",
  "react-router-bootstrap": "^0.24.4",
  "react-router-dom": "^4.2.2",
  "react-scripts": "^3.0.1",
  "reactstrap": "^6.3.0",
  "rimraf": "^2.6.2"
},
"devDependencies": {
  "ajv": "^6.9.1",
  "cross-env": "^5.2.0",
  "eslint": "^5.12.0",
  "eslint-config-react-app": "^4.0.1",
  "eslint-plugin-flowtype": "^2.0.0",
  "eslint-plugin-import": "^2.14.0",
  "eslint-plugin-jsx-a11y": "^6.2.1",
  "eslint-plugin-react": "^7.11.1",
  "typescript": "^3.5.2"
}

SignalR endpoints and automatic reconnect

Like web API endpoints, SignalR endpoints can use the new endpoint routing:

app.UseEndpoints(endpoints =>
{
  endpoints.MapControllers();
  endpoints.MapHub<QuestionsHub>("/questionshub");
});

In the React client, when establishing the SignalR connection, we can tell it to automatically reconnect when a connection is lost:

const connection = new HubConnectionBuilder()
  .withUrl(`${server}/questionshub`)
  .withAutomaticReconnect()
  .build();

If you to learn about using React with ASP.NET Core you might find my book useful:

ASP.NET Core 5 and React

ASP.NET Core 5 and React
Find out more

Want more content like this?

Subscribe to receive notifications on new blog posts and courses

Required
© Carl Rippon
Privacy Policy