DEV Community

Cover image for Deploying Scalable Multi-Page Web Apps with ASP.NET and Vite.js (Windows & Linux/macOS)
Fussionlabs
Fussionlabs

Posted on

Deploying Scalable Multi-Page Web Apps with ASP.NET and Vite.js (Windows & Linux/macOS)

Creating a modern multi-page web application that combines the power of ASP.NET for backend logic and Vite.js for frontend development offers a fast, modular, and scalable solution. This guide walks you through the setup, starting with the essential dependencies.

Step 1: Dependencies

To get started, make sure you have the following installed:

Required Tools

  • .NET SDK (7.0 or later)
  • Node.js (v18 or later)
  • Vite.js (installed via npm)
  • A code editor like Visual Studio Code
  • Project Structure Your project will be structured like this: /MyApp /ClientApp ← Vite.js frontend /Controllers ← ASP.NET MVC controllers /Models ← ASP.NET Model /Properties ← ASP.NET launch setting /Views ← Razor views (optional) /wwwroot ← Final build path Program.cs Startup.cs or minimal hosting

1: Set Up ASP.NET Core Backend

Create a new ASP.NET Core Web App (MVC or Empty):

dotnet new web -n MyApp
cd MyApp
code .

2. Configure Program.cs to serve static files and fallback to index.html in production:

 var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseStaticFiles(); app.MapFallbackToFile("index.html"); } app.UseRouting(); app.MapControllers(); app.Run(); 
Enter fullscreen mode Exit fullscreen mode

3. Setup Routing Controller for Client App

Modify Controllers/HomeController.cs as follows: using Microsoft.AspNetCore.Mvc; public class HomeController : Controller { [HttpGet("{*url}", Order = int.MaxValue)] public IActionResult Index(string url) { return View(); } } 
Enter fullscreen mode Exit fullscreen mode

You can remove the default Privacy() action and its view since this will be handled by your SPA.

Step 2: Add WeatherForecast API

  1. Create WeatherForecastController.cs Controller

Should create controller inside

/Controller/Api/WeatherForecastController.cs

using Microsoft.AspNetCore.Mvc; namespace MyApp.Controllers.Api; // change the namespace [ApiController] [Route("api/[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }); } } 
Enter fullscreen mode Exit fullscreen mode
  1. Create a Model for the Controller

Should create model inside /Models/WeatherForecast.cs

namespace MyApp.Models // change the namespace public class WeatherForecast { public DateOnly Date { get; set; } public int TemperatureC { get; set; } public string? Summary { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); } 
Enter fullscreen mode Exit fullscreen mode
  1. Update Razor Views

Clear all inside the /Views/Home/Index.cshtml and add:

@{ Layout = "_Layout"; } Modify the _Layout file <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - MyApp</title> <!-- Only for the React Refresh, for other templates remove this --> <script type="module"> import { injectIntoGlobalHook } from "http://localhost:5173/@react-refresh"; injectIntoGlobalHook(window); window.$RefreshReg$ = () => {}; window.$RefreshSig$ = () => (type) => type; </script> <!-- End Refresh --> <script type="module" src="http://localhost:5173/@vite/client"></script> </head> <body> @RenderBody() <script type="module" src="http://localhost:5173/src/main.tsx"></script> @await RenderSectionAsync("Scripts", required: false) </body> </html> 
Enter fullscreen mode Exit fullscreen mode

Here I use React template in Vite so we need to add the React refresh lines. For other templates we can remove them.

Step 3: Set Up React Frontend with Vite

  1. Create your Vite app:
npm create vite@latest ClientApp 
Enter fullscreen mode Exit fullscreen mode

Package name: clientapp
Template: react, react-ts, or vue (your choice)

  1. Navigate and install dependencies:
 cd ClientApp npm i npm i react-router axios 
Enter fullscreen mode Exit fullscreen mode
  1. Recommended Folder Structure

/src
/components ← Header, Footer
/pages ← Home, WeatherList
main.tsx
App.tsx

  1. Setup Axios API: /src/api/weather.tsx
import axios from "axios"; //can use JavaScript Fetch export const getWeatherForecast = () => axios.get("/api/weatherforecast").then((res) => res.data); // fetch() 
Enter fullscreen mode Exit fullscreen mode
  1. Create Home Page and Weather Page
import { useEffect, useState } from "react"; import { getWeatherForecast } from "../api/weather"; function WeatherList() { const [forecasts, setForecasts] = useState([]); useEffect(() => { getWeatherForecast().then(setForecasts); }, []); return ( <div> <h2>Weather Forecast</h2>  <ul> {forecasts.map((f, i) => ( <li key={i}> {f.date}: {f.summary} ({f.temperatureC}°C) </li>  ))} </ul>  </div>  ); } export default WeatherList; 
Enter fullscreen mode Exit fullscreen mode
function Home() { return ( <div className="container mt-5"> <div className="row justify-content-center"> <div className="col-md-8 text-center"> <h1 className="mb-4">Welcome to the Movie Application!</h1>  <p className="lead">Discover, explore, and enjoy our collection of movies.</p>  <p>Use the navigation bar to browse through different sections.</p>  </div>  </div>  </div>  ); } export default Home; 
Enter fullscreen mode Exit fullscreen mode
  1. Configure Routing in /src/App.tsx
import { BrowserRouter, Routes, Route } from "react-router"; import { WeatherList } from "./pages/WeatherList"; import Home from "./pages/Home"; function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} />  <Route path="/weather" element={<WeatherList />} />  </Routes>  </BrowserRouter>  ); } export default App; 
Enter fullscreen mode Exit fullscreen mode

Final Step: Run the App

Open two terminals:

Terminal 1: ASP.NET Core Backend

dotnet dev-certs https --trust dotnet watch run # for https dotnet watch -lp https 
Enter fullscreen mode Exit fullscreen mode

Terminal 2: React Frontend with Vite

cd ClientApp npm run dev 
Enter fullscreen mode Exit fullscreen mode

In single Powershell based run both at a time

 Start-Process -WorkingDirectory ".\ClientApp" -NoNewWindow -FilePath "powershell" -ArgumentList "npm run dev" dotnet watch run 
Enter fullscreen mode Exit fullscreen mode

Summary
You now have a scalable, modern full-stack application using:

ASP.NET Core for APIs and static file hosting
React (or other template) + Vite for fast frontend development
Axios + React Router for API calls and navigation
This setup is easily extendable to include authentication, advanced state management, and deployment pipelines.

Top comments (1)

Collapse
 
lamri_abdellahramdane_15 profile image
Lamri Abdellah Ramdane

Great walkthrough—ASP.NET and Vite together make a super modern stack! On Windows, I often lean on ServBay to quickly spin up .NET, Node, HTTPS, and database services with a single click. Makes testing frontend-backend combos like this effortless.