ASP.NET Core餐饮点餐系统开发实战
1. 项目背景与核心需求去年接手了一个餐饮连锁企业的数字化改造项目他们急需一套能够打通线上线下点餐流程的系统。经过多方对比最终选择了ASP.NET Core作为技术栈主要看中其高性能、跨平台特性和丰富的生态系统。这个点餐系统需要满足以下核心需求支持微信小程序和网页端双渠道点餐实时同步后厨订单数据会员积分与优惠券系统智能推荐菜品功能多门店库存管理2. 技术架构设计2.1 整体架构方案系统采用经典的三层架构表现层微信小程序管理后台网页业务逻辑层ASP.NET Core Web API数据访问层Entity Framework Core SQL Server特别加入了SignalR实现实时通信当后厨完成菜品制作时前台和大屏能实时收到通知。数据库方面采用读写分离设计主库负责订单写入从库处理查询请求。2.2 关键技术选型跨域处理使用EnableCorsAttribute配置services.AddCors(options { options.AddPolicy(AllowAll, builder { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); });实际生产环境中不建议使用AllowAnyOrigin()我们后期改为指定具体域名ORM选择Entity Framework Core 6.0缓存方案Redis缓存热门菜品数据文件存储阿里云OSS存储菜品图片3. 核心功能实现3.1 微信小程序接入小程序端采用uniapp框架开发与ASP.NET后端通过JWT进行认证。关键点在于处理微信支付回调[HttpPost] [Route(api/payment/notify)] public async TaskIActionResult WechatPayNotify() { using var reader new StreamReader(Request.Body); var xmlData await reader.ReadToEndAsync(); // 验证签名逻辑 if(!VerifyWechatSign(xmlData)) { return BadRequest(); } // 更新订单状态 var orderId GetOrderIdFromXml(xmlData); await _orderService.CompletePaymentAsync(orderId); return Ok(xmlreturn_codeSUCCESS/return_code/xml); }3.2 实时订单处理使用SignalR实现订单状态实时推送public class OrderHub : Hub { public async Task JoinKitchenGroup() { await Groups.AddToGroupAsync(Context.ConnectionId, Kitchen); } } // 订单状态变更时通知 await _hubContext.Clients.Group(Kitchen) .SendAsync(OrderUpdated, orderId, status);前端通过监听事件更新UIconnection.on(OrderUpdated, (orderId, status) { const orderElement document.getElementById(order-${orderId}); orderElement.classList.add(status-${status}); });4. 数据库设计要点4.1 主要表结构CREATE TABLE [dbo].[Dishes] ( [Id] INT IDENTITY PRIMARY KEY, [Name] NVARCHAR(100) NOT NULL, [Price] DECIMAL(10,2) NOT NULL, [ImageUrl] NVARCHAR(255), [IsRecommend] BIT DEFAULT 0 ); CREATE TABLE [dbo].[Orders] ( [Id] UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(), [OrderNo] VARCHAR(20) NOT NULL, [TotalAmount] DECIMAL(10,2) NOT NULL, [Status] TINYINT NOT NULL DEFAULT 0, [CreateTime] DATETIME2 DEFAULT SYSDATETIME() );4.2 性能优化措施为高频查询字段添加索引CREATE INDEX IX_Orders_Status ON Orders(Status); CREATE INDEX IX_Orders_CreateTime ON Orders(CreateTime);使用表分区处理历史订单数据引入Redis缓存菜单数据5. 踩坑经验分享5.1 跨域问题排查开发初期遇到CORS问题发现即使配置了EnableCorsAttribute(,,*)某些请求仍然失败。后来发现预检请求(OPTIONS)需要单独处理带凭证的请求不能使用*某些特殊Header需要显式暴露最终解决方案services.AddCors(options { options.AddPolicy(ProductionPolicy, builder { builder.WithOrigins(https://client.domain.com) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() .SetPreflightMaxAge(TimeSpan.FromHours(1)) .WithExposedHeaders(X-Custom-Header); }); });5.2 并发订单处理高峰期出现超卖问题通过三种方案对比测试乐观并发控制EF Core原生支持try { var dish await _context.Dishes.FindAsync(id); dish.Stock - quantity; await _context.SaveChangesAsync(); } catch(DbUpdateConcurrencyException) { // 处理冲突 }使用数据库事务using var transaction await _context.Database.BeginTransactionAsync(); // 业务逻辑 await transaction.CommitAsync();Redis分布式锁最终采用方案using var redLock await _redLockFactory.CreateLockAsync( $dish_{dishId}_lock, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(0.5) ); if(redLock.IsAcquired) { // 处理库存 }6. 部署与监控6.1 容器化部署使用Docker编排服务FROM mcr.microsoft.com/dotnet/aspnet:6.0 WORKDIR /app COPY ./publish . ENTRYPOINT [dotnet, RestaurantSystem.dll]配合docker-compose.yml管理多个服务version: 3.8 services: web: build: . ports: - 5000:80 environment: - ConnectionStrings__DefaultServerdb;DatabaseRestaurant;Usersa;Passwordyourpassword; db: image: mssql/server:2019-latest environment: - ACCEPT_EULAY - SA_PASSWORDyourpassword6.2 监控配置健康检查端点app.MapHealthChecks(/health, new HealthCheckOptions { ResponseWriter async (context, report) { context.Response.ContentType application/json; await context.Response.WriteAsync(/* 自定义格式 */); } });使用Application Insights收集日志配置警报规则监控订单失败率这个项目从零开始到最终上线历时4个月期间遇到了各种技术挑战特别是高并发场景下的数据一致性问题。建议后续可以考虑引入领域驱动设计(DDD)来更好地处理复杂业务逻辑同时将部分服务拆分为微服务架构以提升扩展性。