What's new in ASP.NET Core 3 for React SPAs?
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 viewsAddRazorPages
. This can be used when the app uses Razor pages. Note thatAddControllers
orAddControllersWithViews
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:
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:
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: