Tổng quan về Single Page Apps (SPA) trong ASP.NET Core
Visual Studio cung cấp các project template (mẫu dự án) để tạo các ứng dụng trang đơn (SPA - Single Page App) dựa trên các công nghệ JavaScript, chẳng hạn như Angular, React, và Vue, có backend ASP.NET Core. Các template này:
- Tạo một Visual Studio solution với một dự án frontend và một dự án backend.
- Sử dụng loại dự án Visual Studio cho JavaScript và TypeScript (.esproj) cho frontend.
- Sử dụng dự án ASP.NET Core cho backend.
Các dự án được tạo bằng Visual Studio template có thể chạy từ dòng lệnh trên Windows, Linux và macOS. Để chạy ứng dụng, hãy dùng dotnet run --launch-profile https để chạy server project. Việc chạy server project sẽ tự động khởi động frontend JavaScript development server. Launch profile https hiện là bắt buộc.
Hướng dẫn của Visual Studio
Để bắt đầu, hãy làm theo một trong các hướng dẫn trong tài liệu Visual Studio:
- Tạo ứng dụng ASP.NET Core với Angular
- Tạo ứng dụng ASP.NET Core với React
- Tạo ứng dụng ASP.NET Core với Vue
Để biết thêm thông tin, xem JavaScript and TypeScript in Visual Studio.
ASP.NET Core SPA templates
Visual Studio bao gồm các template để xây dựng ứng dụng ASP.NET Core với frontend JavaScript hoặc TypeScript. Các template này có sẵn trong Visual Studio 2022 phiên bản 17.8 trở lên với workload ASP.NET and web development được cài đặt.
Các Visual Studio template để xây dựng ứng dụng ASP.NET Core với frontend JavaScript hoặc TypeScript mang lại những lợi ích sau:
- Phân tách dự án rõ ràng cho frontend và backend.
- Cập nhật với các phiên bản framework frontend mới nhất.
- Tích hợp với công cụ dòng lệnh framework frontend mới nhất, chẳng hạn như Vite.
- Template cho cả JavaScript và TypeScript (chỉ TypeScript cho Angular).
- Trải nghiệm chỉnh sửa mã JavaScript và TypeScript phong phú.
- Tích hợp JavaScript build tools với .NET build.
- Giao diện quản lý phụ thuộc npm.
- Tương thích với cấu hình gỡ lỗi và khởi chạy của Visual Studio Code.
- Chạy unit test frontend trong Test Explorer bằng cách sử dụng các framework test JavaScript.
Legacy ASP.NET Core SPA templates (Template cũ)
Các phiên bản trước của .NET SDK bao gồm những gì bây giờ là các template cũ để xây dựng ứng dụng SPA với ASP.NET Core. Để xem tài liệu về các template cũ hơn này, hãy xem phiên bản .NET 7 của SPA overview và các bài viết Angular và React.
Kiến trúc của Single Page Application templates (Phiên bản .NET 6/7)
Các SPA template cho Angular và React cung cấp khả năng phát triển ứng dụng Angular và React được lưu trữ bên trong máy chủ backend .NET.
Khi xuất bản (publish), các tệp của ứng dụng Angular và React được sao chép vào thư mục wwwroot và được phục vụ thông qua Static File Middleware (phần mềm trung gian tệp tĩnh).
Thay vì trả về HTTP 404 (Not Found), một fallback route (tuyến dự phòng) xử lý các yêu cầu không xác định đến backend và phục vụ index.html cho SPA.
Trong quá trình phát triển, ứng dụng được cấu hình để sử dụng frontend proxy. React và Angular sử dụng cùng một frontend proxy.
Khi ứng dụng khởi chạy, trang index.html được mở trong trình duyệt. Một middleware đặc biệt chỉ được bật trong môi trường phát triển:
- Chặn các yêu cầu đến.
- Kiểm tra xem proxy có đang chạy không.
- Chuyển hướng đến URL của proxy nếu đang chạy hoặc khởi chạy một phiên bản mới của proxy.
- Trả về một trang cho trình duyệt tự động làm mới sau vài giây cho đến khi proxy hoạt động và trình duyệt được chuyển hướng.
Lợi ích chính mà các ASP.NET Core SPA template cung cấp:
- Khởi chạy proxy nếu chưa chạy.
- Thiết lập HTTPS.
- Cấu hình một số yêu cầu được proxy đến máy chủ ASP.NET Core backend.
Khi trình duyệt gửi yêu cầu đến một backend endpoint, ví dụ /weatherforecast trong các template. SPA proxy nhận yêu cầu và gửi trở lại máy chủ một cách trong suốt. Máy chủ phản hồi và SPA proxy gửi yêu cầu trở lại trình duyệt.
Single Page Apps đã xuất bản (Published)
Khi ứng dụng được xuất bản, SPA trở thành một tập hợp các tệp trong thư mục wwwroot.
Không cần thành phần runtime (thời gian chạy) nào để phục vụ ứng dụng:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html");
app.Run();Trong tệp Program.cs được tạo từ template ở trên:
app.UseStaticFilescho phép các tệp được phục vụ.app.MapFallbackToFile("index.html")cho phép phục vụ tài liệu mặc định cho bất kỳ yêu cầu không xác định nào mà máy chủ nhận được.
Khi ứng dụng được xuất bản với dotnet publish, các tác vụ sau trong tệp csproj đảm bảo rằng npm restore chạy và script npm phù hợp chạy để tạo ra các artifacts production:
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>Phát triển Single Page Apps
Tệp project xác định một số thuộc tính kiểm soát hành vi của ứng dụng trong quá trình phát triển:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<SpaProxyServerUrl>https://localhost:44414</SpaProxyServerUrl>
<SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.1" />
</ItemGroup>
...
</Project>SpaProxyServerUrl: Kiểm soát URL nơi máy chủ kỳ vọng SPA proxy đang chạy. Đây là URL mà máy chủ ping sau khi khởi chạy proxy để biết nó đã sẵn sàng chưa, và nơi chuyển hướng trình duyệt sau khi nhận được phản hồi thành công.SpaProxyLaunchCommand: Lệnh mà máy chủ sử dụng để khởi chạy SPA proxy khi nó phát hiện proxy chưa chạy.
Package Microsoft.AspNetCore.SpaProxy chịu trách nhiệm cho logic trên để phát hiện proxy và chuyển hướng trình duyệt.
Hosting startup assembly được định nghĩa trong Properties/launchSettings.json được sử dụng để tự động thêm các thành phần cần thiết trong quá trình phát triển để phát hiện xem proxy có đang chạy không và khởi chạy nó nếu không:
{
"profiles": {
"MyReact": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:7145;http://localhost:5273",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
}
}
}Thiết lập cho ứng dụng client
Thiết lập này dành riêng cho framework frontend mà ứng dụng sử dụng, tuy nhiên nhiều khía cạnh của cấu hình là tương tự nhau.
Thiết lập Angular
Tệp ClientApp/package.json được tạo từ template chứa các script để khởi chạy Angular development server trong quá trình phát triển. Script prestart gọi ClientApp/aspnetcore-https.js để đảm bảo certificate HTTPS của development server có sẵn cho SPA proxy server. Các script start:windows và start:default khởi chạy Angular development server qua ng serve với port, HTTPS và đường dẫn certificate phù hợp.
Tệp ClientApp/angular.json chứa lệnh serve và phần tử proxyConfig trong cấu hình development để chỉ định rằng proxy.conf.js sẽ được sử dụng để cấu hình frontend proxy.
ClientApp/proxy.conf.js xác định các tuyến cần được proxy đến backend server. Các tùy chọn chung được xác định tại http-proxy-middleware cho React và Angular vì chúng đều sử dụng cùng một proxy.
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51951';
const PROXY_CONFIG = [
{
context: [
"/weatherforecast",
],
target: target,
secure: false,
headers: {
Connection: 'Keep-Alive'
}
}
]
module.exports = PROXY_CONFIG;Thiết lập React
Script prestart trong package.json gọi aspnetcore-https.js và aspnetcore-react.js. Script aspnetcore-react.js cấu hình certificate HTTPS local development bằng cách thêm SSL_CRT_FILE=<certificate-path> và SSL_KEY_FILE=<key-path> vào tệp .env.development.local.
Tệp src/setupProxy.js cấu hình SPA proxy để chuyển tiếp các yêu cầu đến backend:
const { createProxyMiddleware } = require('http-proxy-middleware');
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51783';
const context = [
"/weatherforecast",
];
module.exports = function (app) {
const appProxy = createProxyMiddleware(context, {
target: target,
onError: (err, req, resp, target) => { console.error(`${err.message}`); },
secure: false,
headers: {
Connection: 'Keep-Alive'
}
});
app.use(appProxy);
};Phiên bản SPA framework được hỗ trợ trong ASP.NET Core SPA templates
Các SPA project template đi kèm với mỗi bản phát hành ASP.NET Core tham chiếu đến phiên bản mới nhất của framework SPA tương ứng.
Các framework SPA thường có chu kỳ phát hành ngắn hơn .NET. Do hai chu kỳ phát hành khác nhau, phiên bản được hỗ trợ của framework SPA và .NET có thể bị lệch nhau: phiên bản SPA framework chính mà .NET phụ thuộc vào có thể hết hỗ trợ, trong khi phiên bản .NET mà framework SPA được xuất bản cùng vẫn còn được hỗ trợ.
Các ASP.NET Core SPA template có thể được cập nhật trong bản phát hành patch lên phiên bản framework SPA mới để giữ cho các template ở trạng thái được hỗ trợ và an toàn.