You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#/ASP.NET串口通信开发:设备按键读取及页面串口监听问题

解决ASP.NET中串口设备按键输入的实时感知问题

嘿,我来帮你搞定这个串口通信的难题——首先得敲黑板明确一个核心点:ASP.NET Web Forms(.aspx)的页面是无状态的,后台代码只在页面请求、加载的短暂周期内运行,页面渲染完成后后台逻辑就停止了。这就是你在Zxx.aspx里没法持续感知设备按键输入的根本原因。

下面给你两种实用的解决方案,结合实时通信和后台监听来实现需求:

方案一:Windows服务 + SignalR (推荐生产环境使用)

这种方案把串口监听和Web应用解耦,稳定性更高,不会受ASP.NET应用池回收的影响。

1. 编写Windows服务持续监听串口

创建一个Windows服务项目,在服务里初始化串口并监听设备输入,用SignalR把数据推送到前端页面:

using System.IO.Ports;
using Microsoft.AspNet.SignalR;

namespace SerialListenerService
{
    public partial class SerialListener : ServiceBase
    {
        private SerialPort _serialPort;

        public SerialListener()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // 配置串口参数,和你的设备保持一致
            _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
            _serialPort.Encoding = System.Text.Encoding.ASCII; // 根据设备编码调整
            _serialPort.DataReceived += SerialPort_DataReceived;
            
            try
            {
                _serialPort.Open();
            }
            catch (Exception ex)
            {
                // 记录日志,处理串口打开失败的情况
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // 读取设备发送的数据(比如按键输入)
            string inputData = _serialPort.ReadExisting().Trim();
            
            if (!string.IsNullOrEmpty(inputData))
            {
                // 通过SignalR把数据推送到所有连接的前端页面
                var hubContext = GlobalHost.ConnectionManager.GetHubContext<SerialHub>();
                hubContext.Clients.All.receiveDeviceInput(inputData);
            }
        }

        protected override void OnStop()
        {
            if (_serialPort != null && _serialPort.IsOpen)
            {
                _serialPort.Close();
                _serialPort.Dispose();
            }
        }
    }
}

2. 在ASP.NET项目中添加SignalR Hub

创建一个SignalR Hub类,作为前端和后台服务的通信中转:

using Microsoft.AspNet.SignalR;

public class SerialHub : Hub
{
    // 这里可以留空,主要负责维护前端连接,转发数据
}

3. 在Zxx.aspx页面中接收实时数据

在页面中引入SignalR脚本,连接Hub并处理设备输入:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Zxx.aspx.cs" Inherits="YourWebApp.Zxx" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>串口设备监听</title>
    <script src="Scripts/jquery-3.6.0.min.js"></script>
    <script src="Scripts/jquery.signalR-2.4.3.min.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
        $(function () {
            // 初始化SignalR连接
            var serialHub = $.connection.serialHub;
            
            // 定义接收设备输入的回调函数
            serialHub.client.receiveDeviceInput = function (data) {
                // 在这里处理设备按键输入,比如显示在页面上
                console.log("设备按键输入:" + data);
                $("#deviceInputDisplay").text("最新按键:" + data);
            };
            
            // 启动连接
            $.connection.hub.start().done(function () {
                console.log("已连接到串口监听服务");
            }).fail(function (err) {
                console.error("连接失败:" + err);
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div id="deviceInputDisplay">等待设备输入...</div>
    </form>
</body>
</html>

4. 串口操作页面的指令写入

点击按钮跳转到串口操作页面后,你可以通过SignalR调用Hub方法,让后台服务向串口写入指令:

// 在串口操作页面的后台代码中
protected void btnSendCommand_Click(object sender, EventArgs e)
{
    var hubContext = GlobalHost.ConnectionManager.GetHubContext<SerialHub>();
    // 调用Hub的方法,让后台服务发送指令(需要在Hub中定义对应的方法)
    hubContext.Clients.All.sendSerialCommand("你的指令内容");
}

// 在SerialHub中添加方法
public void SendSerialCommand(string command)
{
    // 这里调用Windows服务中的串口写入逻辑,或者直接在Hub所在的应用中处理(如果用方案二的话)
    // 注意:如果是Windows服务,需要通过进程间通信或者其他方式传递指令,比如用数据库、消息队列
}

方案二:ASP.NET后台线程 + SignalR (适合测试或小型应用)

如果不想部署Windows服务,可以在ASP.NET应用中启动后台线程监听串口,但要注意应用池回收会导致线程终止,需要配置应用池避免自动回收:

1. 在Global.asax中启动后台监听线程

using System.IO.Ports;
using System.Threading;
using Microsoft.AspNet.SignalR;

protected void Application_Start(object sender, EventArgs e)
{
    Thread listenThread = new Thread(ListenSerialPort);
    listenThread.IsBackground = true;
    listenThread.Start();
}

private void ListenSerialPort()
{
    SerialPort serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
    serialPort.Encoding = System.Text.Encoding.ASCII;
    
    try
    {
        serialPort.Open();
        while (true)
        {
            if (serialPort.BytesToRead > 0)
            {
                string inputData = serialPort.ReadExisting().Trim();
                var hubContext = GlobalHost.ConnectionManager.GetHubContext<SerialHub>();
                hubContext.Clients.All.receiveDeviceInput(inputData);
            }
            Thread.Sleep(100); // 避免占用过多CPU
        }
    }
    catch (Exception ex)
    {
        // 记录日志
    }
    finally
    {
        if (serialPort.IsOpen)
            serialPort.Close();
    }
}

2. 前端页面和指令写入的逻辑和方案一一致

同样用SignalR接收数据,页面跳转后通过Hub发送指令。

关键注意事项

  • 串口参数匹配:波特率、奇偶校验、数据位、停止位必须和设备完全一致,否则无法正常通信。
  • 权限问题:ASP.NET应用池的运行身份(或Windows服务的运行身份)需要有访问串口的权限,建议用管理员身份测试,再调整到合适的权限。
  • 数据编码:设备发送的编码要和SerialPort.Encoding一致,常见的是ASCII或UTF-8。
  • 异常处理:一定要添加串口操作的异常捕获,比如串口被占用、断开连接等情况,避免程序崩溃。

内容的提问来源于stack exchange,提问作者João Costa

火山引擎 最新活动