如何在ASP.NET Core Razor页面中实现地图实时订单配送位置追踪?
实现ASP.NET Core Razor页面订单实时位置追踪方案
核心逻辑
整个功能分为三个关键环节:
- 配送端(如骑手APP)定时上报当前位置到后端
- 后端接收并存储位置数据,同时支持实时推送或查询
- 前端Razor页面获取位置数据,在地图上渲染并更新
后端实现
1. 定义数据实体
用EF Core创建订单和位置存储模型:
public class Order { public int Id { get; set; } public string CustomerId { get; set; } public OrderStatus Status { get; set; } // 其他订单字段(如收货人、地址等) } public class DeliveryLocation { public int Id { get; set; } public int OrderId { get; set; } public decimal Longitude { get; set; } public decimal Latitude { get; set; } public DateTime UpdateTime { get; set; } public Order Order { get; set; } } public enum OrderStatus { Processing, Delivering, Completed }
2. 位置上报API
创建API控制器接收配送端的位置请求:
[ApiController] [Route("api/delivery")] public class DeliveryController : ControllerBase { private readonly AppDbContext _dbContext; private readonly IHubContext<LocationHub> _hubContext; public DeliveryController(AppDbContext dbContext, IHubContext<LocationHub> hubContext) { _dbContext = dbContext; _hubContext = hubContext; } [HttpPost("location")] public async Task<IActionResult> UpdateLocation([FromBody] LocationUpdateRequest request) { // 验证订单有效性 var order = await _dbContext.Orders.FindAsync(request.OrderId); if (order == null || order.Status != OrderStatus.Delivering) return BadRequest("无效订单或当前不处于配送状态"); // 存储最新位置 var location = new DeliveryLocation { OrderId = request.OrderId, Longitude = request.Longitude, Latitude = request.Latitude, UpdateTime = DateTime.UtcNow }; _dbContext.DeliveryLocations.Add(location); await _dbContext.SaveChangesAsync(); // 通过SignalR推送给对应订单的客户 await _hubContext.Clients.Group($"Order_{request.OrderId}") .SendAsync("ReceiveLocationUpdate", new { Longitude = request.Longitude, Latitude = request.Latitude, UpdateTime = location.UpdateTime }); return Ok(); } } public class LocationUpdateRequest { public int OrderId { get; set; } public decimal Longitude { get; set; } public decimal Latitude { get; set; } }
3. SignalR实时推送配置
如果需要低延迟的实时更新,配置SignalR服务:
// Program.cs builder.Services.AddSignalR(); app.MapHub<LocationHub>("/locationHub");
创建SignalR Hub类:
public class LocationHub : Hub { public async Task JoinOrderGroup(int orderId) { await Groups.AddToGroupAsync(Context.ConnectionId, $"Order_{orderId}"); } }
前端Razor页面实现
1. 页面结构(带地图容器)
@page "/orders/track/{orderId:int}" @model TrackOrderModel <div class="container mt-4"> <h3>订单实时追踪</h3> <div id="map" style="width: 100%; height: 600px; border-radius: 8px;"></div> </div>
2. JavaScript逻辑(SignalR+地图渲染)
@section Scripts { <script src="https://webapi.amap.com/maps?v=1.4.15&key=你的高德地图API密钥"></script> <script src="/js/signalr/dist/browser/signalr.js"></script> <script> const orderId = @Model.OrderId; let map, marker; // 初始化地图 function initMap() { map = new AMap.Map('map', { zoom: 15, resizeEnable: true }); // 获取初始位置 fetch(`/api/orders/${orderId}/latest-location`) .then(res => res.json()) .then(data => { if (data) updateMarker(data.longitude, data.latitude); }); } // 更新地图标记位置 function updateMarker(lng, lat) { const position = new AMap.LngLat(lng, lat); if (!marker) { marker = new AMap.Marker({ position }); map.add(marker); map.setCenter(position); } else { marker.setPosition(position); map.setCenter(position); } } // 连接SignalR接收实时更新 const connection = new signalR.HubConnectionBuilder() .withUrl("/locationHub") .build(); connection.on("ReceiveLocationUpdate", (data) => { updateMarker(data.longitude, data.latitude); }); connection.start() .then(() => connection.invoke("JoinOrderGroup", orderId)) .catch(err => console.error(err)); window.onload = initMap; </script> }
3. Razor页面模型(权限验证)
public class TrackOrderModel : PageModel { private readonly AppDbContext _dbContext; public int OrderId { get; set; } public TrackOrderModel(AppDbContext dbContext) { _dbContext = dbContext; } public async Task<IActionResult> OnGet(int orderId) { // 验证当前用户是订单所属客户 var order = await _dbContext.Orders.FirstOrDefaultAsync(o => o.Id == orderId && o.CustomerId == User.Identity.Name); if (order == null || order.Status != OrderStatus.Delivering) return NotFound(); OrderId = orderId; return Page(); } }
可选方案:轮询(无SignalR场景)
如果不需要低延迟,用简单轮询替代SignalR:
// 替换SignalR相关代码 setInterval(() => { fetch(`/api/orders/${orderId}/latest-location`) .then(res => res.json()) .then(data => { if (data) updateMarker(data.longitude, data.latitude); }); }, 5000); // 每5秒查询一次最新位置
关键注意事项
- 权限控制:必须验证访问用户是订单的所属客户,防止位置信息泄露
- 数据优化:用Redis缓存每个订单的最新位置,减少数据库查询压力;定期归档历史位置数据
- 异常处理:前端需处理网络异常、后端返回错误的情况,给用户友好提示
- 地图服务:可根据需求选择高德、百度或谷歌地图JS API,注意申请合法的API密钥
内容的提问来源于stack exchange,提问作者Amal
相关产品推荐
相关产品推荐

