基于路由混合使用Angular 4与ASP.NET Core MVC Razor视图的技术咨询
我来帮你搞定ASP.NET Core MVC混合Angular 4和Razor渲染的需求,咱们一步步来配置:
首先得修改后端的路由配置,让/Schedule开头的请求都转发到Angular的入口文件。如果是.NET 6+的项目,直接在Program.cs里调整中间件顺序:
var app = builder.Build(); // 先处理静态文件(Angular的js、css这些资源都靠它加载) app.UseStaticFiles(); // 别忘了Identity的认证授权中间件 app.UseAuthentication(); app.UseAuthorization(); // 先让MVC处理常规的Razor路由 app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); // 重点:把/Schedule开头的请求转发到Angular的index.html app.MapWhen(context => context.Request.Path.StartsWithSegments("/Schedule"), appBuilder => { appBuilder.Use(async (context, next) => { // 把请求路径重定向到Angular的入口文件 context.Request.Path = "/ClientApp/index.html"; await next(); }); // 确保Angular的静态资源能被访问到 appBuilder.UseStaticFiles(); });
这里要注意中间件顺序:先处理MVC路由,再处理Angular的转发,不然会把常规Razor页面的请求也导去Angular。
打开Angular项目里的app-routing.module.ts,设置路由规则让ScheduleComponent对应/Schedule路径:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ScheduleComponent } from './schedule/schedule.component'; const routes: Routes = [ { path: 'Schedule', component: ScheduleComponent, // 如果有子页面比如/Schedule/detail,这里可以加children配置子路由 children: [ // 示例:{ path: 'detail', component: ScheduleDetailComponent } ] } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
另外,记得在Angular的index.html里设置正确的base href,比如你的Angular文件在wwwroot/ClientApp下,就写:
<base href="/ClientApp/">
这样Angular才能正确加载自己的资源文件。
因为你用了ASP.NET Identity,Angular页面可能需要知道用户是否登录、用户名这些信息,有两种简单的方式:
方式一:服务器端嵌入用户信息
在刚才的MapWhen中间件里,把用户信息直接嵌入到Angular的index.html里:
app.MapWhen(context => context.Request.Path.StartsWithSegments("/Schedule"), appBuilder => { appBuilder.Use(async (context, next) => { var indexPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "ClientApp", "index.html"); var htmlContent = await File.ReadAllTextAsync(indexPath); // 从当前请求里拿用户信息 var user = context.User; var userInfo = new { IsAuthenticated = user.Identity.IsAuthenticated, UserName = user.Identity.Name }; var userJson = System.Text.Json.JsonSerializer.Serialize(userInfo); // 在index.html里加个注释占位符<!-- USER_INFO -->,替换成用户信息的全局变量 htmlContent = htmlContent.Replace("<!-- USER_INFO -->", $"<script>window.userInfo = {userJson};</script>"); context.Response.ContentType = "text/html"; await context.Response.WriteAsync(htmlContent); }); });
然后在Angular的index.html里加一行<!-- USER_INFO -->,之后在Angular组件里就能通过window.userInfo获取用户信息了。
方式二:通过API获取用户信息
写一个简单的API端点返回用户信息,比如在ASP.NET里加个AuthController:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { [HttpGet("user")] public IActionResult GetUserInfo() { if (!User.Identity.IsAuthenticated) { return Unauthorized(); } return Ok(new { UserName = User.Identity.Name, IsAuthenticated = true }); } }
然后在Angular里用HttpClient调用这个API,记得开启withCredentials带上认证Cookie:
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private http: HttpClient) {} getUserInfo() { return this.http.get('/api/auth/user', { withCredentials: true }); } }
在组件里注入这个服务就能拿到用户信息了。
如果用Angular CLI开发,配置一个proxy.conf.json把API请求转发到ASP.NET后端,避免跨域问题:
{ "/api": { "target": "https://localhost:5001", // 你的ASP.NET后端地址 "secure": false, "changeOrigin": true } }
然后在Angular的package.json里的start命令加上代理配置:
"scripts": { "start": "ng serve --proxy-config proxy.conf.json", ... }
这样开发时Angular的API请求会自动转发到后端。
最后提醒下:发布的时候,记得把Angular打包后的文件放到wwwroot/ClientApp目录下,可以在Angular的angular.json里设置outputPath为../wwwroot/ClientApp/dist,这样打包后直接就到正确的位置了。
内容的提问来源于stack exchange,提问作者user2270653

