top of page
  • Writer's pictureScott J. Swindell

Setting up a Complete Framework for .NET 6 React Apps in Visual Studio 2022

Using Node.js, React.js, SASS, Jest, xUnit, Moq, NLog, Identity Framework, Entity Framework, and dependency injection


By now, I hope you've had a chance to check out Visual Studio 2022. I recently used it to create my first .NET 6 single-page application (SPA), using Node.js for hosting, React.js for a responsive frontend, Identity Framework for Authentication and Authorization, Entity Framework for data access, SASS for awesome styling, dependency injection, NLog for logging, and Jest, xUnit, plus Moq for automated testing the entire thing. This provides a robust framework, for building powerful, high-quality applications. In this tutorial, we’ll walk through the steps to set everything up.



Install Visual Studio 2022

Visual Studio 2022 Logo

First, if you haven’t done so, download and install Visual Studio (VS) 2022. The Community version is free and has all the features you need, for non-enterprise development.




Create the Project and Solution

Once you have Visual Studio 2022 installed, it’s time to create the project and solution. On the Visual Studio start screen, click on Create a new project.

Visual Studio 2022 Start Screen
Visual Studio 2022 Start Screen

This will bring up a wizard that lets you select the type of project to create. For our purposes, we’re going to select ASP.NET Core with React.js. Once you’ve selected it, click Next to enter the project name and location.

Create New Project Dialog with "ASP.NET Core with React.js" selected
Create a new project

This brings us to the Configure your new project screen. Here, you’re going to enter your Project name, select the Location of your repository, and set the Solution name, which by default is the same as the Project name. Once you’ve set the names and location, click Next. For this tutorial, I'll be using the name Net6ReactApp.

Configure your new project dialog screenshot
Configure your new project

That leads us to the Additional information screen. Here, we’re going to select .NET 6 (Long-term support) for the Framework. The Authentication type really depends on how you’re planning to authenticate your users. If anyone can use the app, then select None. For basic login functions, Individual Accounts sets up the fundamentals for user accounts. If you require Windows Authentication, then you'll have to go back a step and select the ASP.NET Core MVC application template and manually add React later.


We’re going to select Individual Accounts, because it uses Microsoft Identity Framework, which gives us an excellent platform, for authentication and authorization. Leave Configure for HTTPS configured, so the app’s connections to the users will be secure.

Additional information screenshot, with Framework .NET 6.0 and Individual Accounts Authentication, configured for HTTPS
Additional information

Once you have everything entered and selected, click Create, to have Visual Studio scaffold-out your new project. Once Visual Studio is finished creating your project and solution, it will take you to an overview of your app. Feel free to have a look around your solution, or explore some of the documentation, on the overview page. I’ll cover publishing your app to the cloud in a future article.

Project Overview screenshot
Project Overview

Run the App

As the project was scaffolded, Visual Studio created all the necessary files to run your React.js app using Node.js. When you’re done looking around, click on the Debug button on the toolbar to run the app. If you don't have the Debug button on your toolbar, right-click on the toolbar and select Debug from the list of options.


The first time you run the app, it has to restore all of the Node.js packages with Node Package Manager (NPM), which can take several minutes. Once NPM is finished, you’ll be prompted to trust the self-signed SSL certificate. This avoids getting a security warning when you view the app in a browser. Click Yes to continue.




This will lead to a more serious sounding prompt. Just click Yes again to trust the certificate.

Security Warning dialog
Accept the Security Warning

Upon trusting the certificate, the website should start to load in the browser.

Launching the SPA proxy screenshot
Launching the Website

While the site loads, you may be prompted, by Windows Defender Firewall, to allow access to Node.js. This is required for the site to operate correctly, so click Allow Access.

Windows Defender Firewall dialog
Allow Node.js through the firewall

Finally, after everything has loaded, Node.js will serve up your new single-page application (SPA). Take a look around the site to learn about your app.

Screenshot of the single-page application running
Single-page application running

Explore the Solution

After you’re finished looking around, let’s take a look at Solution Explorer. We have a Properties folder, which has important settings for the app. There’s also a ClientApp folder. This is where the React.js code for the project resides. Just like regular MVC projects, you’ll find Controllers and Models directories. In the Data folder, you’ll find the Entity Framework context and migrations. There’s also a Pages folder for the few pages that React.js won’t be handling, like an error page. Finally, we have appsettings.json and Program.cs for launching and initializing up the app.


Screenshot of Solution Explorer showing the files in the Solution.
Solution Explorer

Dependency Injection, Authentication, and Authorization

If you take a look at Program.cs, you’ll notice that we’re already set up for dependency injection. It initializes authentication and authorization, using Microsoft Identity Framework. This is because we selected Individual Accounts during scaffolding. It also sets up Entity Framework, URL routing, and HTTPS redirection.


using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Net6ReactApp.Data;
using Net6ReactApp.Models;
using NLog;
using NLog.Web;

// Initialize NLog
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Debug("Initializing Program");

try
{
	var builder = WebApplication.CreateBuilder(args);

	// Add services to the container.
	var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
	builder.Services.AddDbContext<ApplicationDbContext>(options =>
		options.UseSqlServer(connectionString));
	builder.Services.AddDatabaseDeveloperPageExceptionFilter();

	builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
		.AddEntityFrameworkStores<ApplicationDbContext>();

	builder.Services.AddIdentityServer()
		.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

	builder.Services.AddAuthentication()
		.AddIdentityServerJwt();

	builder.Services.AddControllersWithViews();
	builder.Services.AddRazorPages();

	// Setup NLog for Dependency injection
	builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
	builder.Host.UseNLog();

	var app = builder.Build();

	// Configure the HTTP request pipeline.
	if (app.Environment.IsDevelopment())
	{
		app.UseMigrationsEndPoint();
	}
	else
	{
		// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
		app.UseHsts();
	}

	app.UseHttpsRedirection();
	app.UseStaticFiles();
	app.UseRouting();

	app.UseAuthentication();
	app.UseIdentityServer();
	app.UseAuthorization();

	app.MapControllerRoute(
		name: "default",
		pattern: "{controller}/{action=Index}/{id?}");
	app.MapRazorPages();

	app.MapFallbackToFile("index.html"); ;

	app.Run();
}
catch (Exception exception)
{
	logger.Error(exception, "Execution stoped, due to Exception");
	throw;
}
finally
{
	LogManager.Shutdown();
}

Program.cs


Add NLog for better logging

Every app needs logging, in order to gain insight into what the app is doing, at any given time. ASP.NET has some basic support for logging, out of the box. However, for more power and flexibility, we’re going to use a popular third-party logger named NLog. It’s highly configurable. You can log to a file or database, and you have complete control over everything that gets logged.


Add NLog.Web.AspNetCore NuGet Package

To get started, first install the NLog NuGet package. If you’re not familiar with how to get there, just right-click on the project, and select Manage NuGet packages... from the context menu.

Context menu in Solution Explorer, highlighting Manage NuGet Packages
Navigate to Manage NuGet Packages

Next, search for NLog.Web.AspNetCore, under the Browse tab. Once you locate it, select the latest stable version, then click Install. It should be pretty quick, and it will pop up a readme.txt file, when it’s complete.

Screenshot of Installing NLog.Web.AspNetCore using NuGet Package Manager
Install NLog.Web.AspNetCore using NuGet Package Manager

Configure NLog

After installing the NLog NuGet package, it’s time to configure it. The settings for NLog reside in nlog.config, which we’ll have to create. To do this, right-click on the project in Solution Explorer. Click Add on the context menu, then New Item...


Screenshot of context menu in Solution Explorer highlighting Add New Item.
Add New File

This will bring up a dialog box. Select Text File and enter nlog.config as the filename.

Screenshot of Add New Item highlighting Text File and the name nlog.config
Add NLog Configuration File

Once the file is created, copy and paste the following configuration XML into the file. For complete information on the configuration options, visit the NLog config section on their website.


Once you’ve copied the content into the nlog.config file, replace instances of Net6ReactApp with the name of your own app, and make any other changes you’d like.


<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
	  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  autoReload="true"
	  internalLogLevel="Info"
	  internalLogFile=".\logs\internal-nlog-Net6ReactApp.txt">
 
	<!-- ASP.NET Core Renderer -->
	<extensions>
		<add assembly="NLog.Web.AspNetCore"/>
	</extensions>
 
	<!-- Logging Targets -->
	<targets>
		<!-- File Target for general logging  -->
		<target xsi:type="File" name="allfile" fileName=".\logs\Net6ReactApp-${shortdate}.log"
				layout="${longdate} | ${event-properties:item=EventId_Id:whenEmpty=0} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=tostring}" />
 
		<!-- File Target for own logging -->
		<target xsi:type="File" name="ownFile-web" fileName=".\logs\Net6ReactApp-own-${shortdate}.log"
				layout="${longdate} | ${event-properties:item=EventId_Id:whenEmpty=0} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=tostring} | url: ${aspnet-request-url} | action: ${aspnet-mvc-action} | ${callsite}" />
 
		<!-- Console Target to improve startup detection -->
		<target xsi:type=