如何创建接收原始NMEA消息的API并将GPS数据存入SQL表
解决方案:ASP.NET Web API接收NMEA格式GPS数据并存入SQL表
1. 修改API控制器,接收原始NMEA文本
原控制器绑定JSON模型的方式无法处理纯文本格式的NMEA数据,需要改为直接读取请求的原始内容。调整后的代码如下:
public class GPSStatusController : ApiController { public async Task<HttpResponseMessage> Post() { // 读取请求中的原始NMEA文本 string nmeaData = await Request.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(nmeaData)) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "NMEA数据不能为空"); } using (LocationEntities entities = new LocationEntities()) { var gpsRecord = new GPSStatu(); // 设备ID建议从请求头(如Device-ID)或NMEA数据中提取,这里替换为实际逻辑 gpsRecord.ID = Request.Headers.GetValues("Device-ID").FirstOrDefault() ?? "未知设备"; gpsRecord.GPSData = nmeaData; // 若需存原始NMEA字符串,直接赋值即可 // 注意:原代码中BatteryStatus应为对应GPSStatu的DbSet名称,需根据实际项目调整 entities.GPSStatu.Add(gpsRecord); entities.SaveChanges(); } return Request.CreateResponse(HttpStatusCode.OK, "数据已成功保存"); } }
2. 配置API支持text/plain请求格式
默认ASP.NET Web API不支持解析text/plain类型的请求,需要添加自定义格式化器。在WebApiConfig.cs中添加以下配置:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // 添加text/plain格式支持 config.Formatters.Add(new PlainTextFormatter()); // 原有路由配置保持不变 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } // 自定义文本格式化器 public class PlainTextFormatter : MediaTypeFormatter { public PlainTextFormatter() { SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain")); } public override bool CanReadType(Type type) => type == typeof(string); public override bool CanWriteType(Type type) => type == typeof(string); public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) { using (var reader = new StreamReader(readStream)) { return await reader.ReadToEndAsync(); } } public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) { if (value is string text) { using (var writer = new StreamWriter(writeStream)) { await writer.WriteAsync(text); } } } }
3. 可选:解析NMEA为结构化数据存储
如果需要将NMEA解析为经纬度、时间等结构化数据存入数据库,可添加解析逻辑示例:
// 解析NMEA语句为结构化数据 private GPSStatu ParseNmeaToStructuredData(string nmeaData) { var gpsData = new GPSStatu(); var lines = nmeaData.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (!line.StartsWith("$")) continue; var parts = line.Split('*'); var fields = parts[0].Split(','); switch (fields[0]) { case "$GPGLL": // 解析纬度、经度、时间 gpsData.Latitude = ConvertNmeaCoordinate(fields[1], fields[2]); gpsData.Longitude = ConvertNmeaCoordinate(fields[3], fields[4]); gpsData.Timestamp = ParseNmeaUtcTime(fields[5]); break; case "$GPGSA": // 解析定位类型、卫星数量 gpsData.FixType = fields[1]; gpsData.SatelliteCount = int.TryParse(fields[2], out var count) ? count : 0; break; } } return gpsData; } // 将NMEA坐标转换为十进制格式 private double ConvertNmeaCoordinate(string coordStr, string direction) { if (string.IsNullOrWhiteSpace(coordStr)) return 0; var degreeIndex = coordStr.IndexOf('.') - 2; var degrees = double.Parse(coordStr.Substring(0, degreeIndex)); var minutes = double.Parse(coordStr.Substring(degreeIndex)); var decimalDeg = degrees + minutes / 60; // 根据方向调整正负(南/S、西/W为负) return (direction == "S" || direction == "W") ? -decimalDeg : decimalDeg; } // 解析NMEA UTC时间为DateTime private DateTime ParseNmeaUtcTime(string timeStr) { if (string.IsNullOrWhiteSpace(timeStr)) return DateTime.UtcNow; var hours = int.Parse(timeStr.Substring(0, 2)); var minutes = int.Parse(timeStr.Substring(2, 2)); var seconds = double.Parse(timeStr.Substring(4)); var utcDate = DateTime.UtcNow.Date; return new DateTime(utcDate.Year, utcDate.Month, utcDate.Day, hours, minutes, (int)seconds, DateTimeKind.Utc); }
修改控制器Post方法使用该解析逻辑:
public async Task<HttpResponseMessage> Post() { string nmeaData = await Request.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(nmeaData)) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "NMEA数据不能为空"); } var parsedData = ParseNmeaToStructuredData(nmeaData); parsedData.ID = Request.Headers.GetValues("Device-ID").FirstOrDefault() ?? "未知设备"; using (LocationEntities entities = new LocationEntities()) { entities.GPSStatu.Add(parsedData); entities.SaveChanges(); } return Request.CreateResponse(HttpStatusCode.OK, "数据已解析并保存"); }
4. 测试方法
用Postman或curl发起请求:
- 请求方法:POST
- URL:
http://你的API地址/api/GPSStatus - 请求头:
Content-Type: text/plain - 请求体:粘贴提供的NMEA数据示例
内容的提问来源于stack exchange,提问作者Sudhe
相关产品推荐
相关产品推荐

