21. 高级路由配置
21.1 自定义路由约束
除了使用默认的路由约束,你还可以创建自定义路由约束。自定义路由约束允许你根据特定的业务逻辑来决定一个路由是否匹配。例如,创建一个只允许特定年份的路由约束:
csharp
public class YearRouteConstraint : IRouteConstraint
{
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (values.TryGetValue(routeKey, out object value))
{
if (int.TryParse(value.ToString(), out int year))
{
return year >= 2000 && year <= 2030;
}
}
return false;
}
}
然后在路由配置中使用这个自定义约束:
routes.MapRoute(
name: "CustomYearRoute",
url: "products/{year}",
defaults: new { controller = "Product", action = "Index" },
constraints: new { year = new YearRouteConstraint() }
);
21.2 区域路由
当应用程序变得复杂时,可以使用区域(Areas)来组织代码。区域允许你将相关的控制器、视图和模型分组在一起。创建一个区域的步骤如下:
-
在项目中创建一个
Areas
文件夹。 -
在
Areas
文件夹下创建一个新的区域文件夹,例如Admin
。 -
在
Admin
文件夹下创建Controllers
、Views
和Models
文件夹。 -
在
Admin
文件夹下创建一个AdminAreaRegistration.cs
文件来配置区域路由:public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); }
}
在 RouteConfig.cs
中注册区域:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// 注册区域
AreaRegistration.RegisterAllAreas();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
22. 视图组件
22.1 视图组件的概念
视图组件是一种轻量级的可复用视图元素,类似于部分视图,但功能更强大。视图组件可以包含自己的逻辑和数据访问代码,并且可以异步加载。
22.2 创建视图组件
创建一个视图组件需要以下步骤:
-
创建一个继承自
ViewComponent
的类,例如:public class LatestProductsViewComponent : ViewComponent
{
private readonly ProductContext _context;public LatestProductsViewComponent(ProductContext context) { _context = context; } public async Task<IViewComponentResult> InvokeAsync() { var latestProducts = await _context.Products.OrderByDescending(p => p.CreatedDate).Take(5).ToListAsync(); return View(latestProducts); }
}
-
在
Views/Shared/Components/LatestProducts
文件夹下创建一个Default.cshtml
视图文件:@model IEnumerable<YourNamespace.Product>
最新产品
-
@foreach (var product in Model)
{
- @product.Name }
-
在其他视图中使用视图组件:
@await Component.InvokeAsync("LatestProducts")
23. 信号量与实时通信
23.1 使用 SignalR 实现实时通信
SignalR 是一个用于在服务器和客户端之间实现实时通信的库。可以使用 SignalR 来创建实时聊天、实时通知等功能。
-
安装
Microsoft.AspNetCore.SignalR
包。 -
创建一个继承自
Hub
的类,例如:public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
} -
在
Startup.cs
中配置 SignalR:public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddControllersWithViews();
}public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 其他配置...app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapHub<ChatHub>("/chatHub"); });
}
-
在客户端使用 JavaScript 连接到 SignalR 服务器:
html
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.1/signalr.min.js"></script>
<script>
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();
connection.on("ReceiveMessage", (user, message) => {
const msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
const encodedMsg = user + " says: " + msg;
const li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
connection.start().catch(err => console.error(err.toString()));
document.getElementById("sendButton").addEventListener("click", event => {
const user = document.getElementById("userInput").value;
const message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(err => console.error(err.toString()));
event.preventDefault();
});
</script>
24. 日志记录与监控
24.1 日志记录
在 ASP.NET MVC 中,可以使用 Microsoft.Extensions.Logging
进行日志记录。在 Startup.cs
中配置日志记录:
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
});
services.AddControllersWithViews();
}
在控制器中使用日志记录:
private readonly ILogger<ProductController> _logger;
public ProductController(ILogger<ProductController> logger)
{
_logger = logger;
}
public ActionResult Index()
{
_logger.LogInformation("访问产品列表页面");
return View();
}
24.2 监控
可以使用 Application Insights 来监控应用程序的性能和健康状况。在 Startup.cs
中配置 Application Insights:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"]);
services.AddControllersWithViews();
}
Application Insights 可以收集应用程序的请求数据、异常信息、性能指标等,帮助你快速发现和解决问题。
25. 微服务架构与 MVC
25.1 微服务架构概述
微服务架构是一种将应用程序拆分为多个小型、自治服务的架构模式。每个微服务都可以独立开发、部署和扩展。
25.2 在 MVC 中集成微服务
可以将 MVC 应用程序拆分为多个微服务,每个微服务负责一个特定的业务功能。例如,将产品管理、订单管理、用户管理等功能拆分为独立的微服务。可以使用 RESTful API 来实现微服务之间的通信。
// 产品微服务的控制器
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly ProductContext _context;
public ProductController(ProductContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
return await _context.Products.ToListAsync();
}
}
在其他微服务中调用产品微服务的 API:
using System.Net.Http;
using System.Threading.Tasks;
public class ProductService
{
private readonly HttpClient _httpClient;
public ProductService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<IEnumerable<Product>> GetAllProducts()
{
var response = await _httpClient.GetAsync("http://product-service/api/product");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<IEnumerable<Product>>();
}
}
通过以上这些高级内容的学习,你可以进一步提升自己在 ASP.NET MVC 开发方面的技能,应对更复杂的业务场景和项目需求。