如何调用PublishAsync获取MqttClientPublishResult且不抛出异常?
解决MQTTnet PublishAsync() 抛出异常而非返回TopicNameInvalid结果的问题
核心原因
MQTTnet客户端在调用PublishAsync()前会做本地协议校验,像####这种明显违反MQTT主题格式规则(#仅允许作为最后一个字符的通配符)的内容,会直接触发MqttProtocolViolationException,根本不会将请求发送到MQTT服务器。因此你无法获取到服务器返回的MqttClientPublishReasonCode.TopicNameInvalid结果——这个结果只有当请求送达服务器,由服务器判定主题无效后才会返回。
可行解决方案
1. 提前手动校验主题格式
使用MQTTnet内置的MqttTopicValidator在调用PublishAsync()前校验主题,提前拦截无效主题并生成符合你预期的结果:
using MQTTnet.Protocol; using MQTTnet.Validators; // 待校验的主题 var targetTopic = "####"; // 根据你使用的MQTT协议版本选择(示例为V5.0) var validationResult = MqttTopicValidator.Validate(targetTopic, MqttProtocolVersion.V500); if (!validationResult.IsValid) { // 生成符合预期的结果对象 var customPublishResult = new MqttClientPublishResult { ReasonCode = MqttClientPublishReasonCode.TopicNameInvalid, ReasonString = validationResult.ErrorMessage }; // 执行你的统一错误处理逻辑 HandlePublishError(customPublishResult); } else { // 主题合法,正常发送消息 var client = new MqttFactory().CreateMqttClient(); var publishResult = await client.PublishAsync(new MqttApplicationMessage { Topic = targetTopic, Payload = System.Text.Encoding.UTF8.GetBytes("test content") }); // 处理正常返回结果 }
2. 捕获异常并映射为结果
如果不想提前校验,可以捕获MqttProtocolViolationException,根据异常信息映射到对应的错误码:
try { var publishResult = await client.PublishAsync(new MqttApplicationMessage { Topic = "####", Payload = System.Text.Encoding.UTF8.GetBytes("test content") }); // 处理正常结果 } catch (MqttProtocolViolationException ex) { MqttClientPublishResult errorResult; if (ex.Message.Contains("'#' is not allowed in topics")) { errorResult = new MqttClientPublishResult { ReasonCode = MqttClientPublishReasonCode.TopicNameInvalid, ReasonString = ex.Message }; } else { // 处理其他协议违规异常,比如主题包含非法字符等 errorResult = new MqttClientPublishResult { ReasonCode = MqttClientPublishReasonCode.ProtocolError, ReasonString = ex.Message }; } // 执行统一错误处理 HandlePublishError(errorResult); }
3. 关于RequestProblemInformation的说明
你尝试的WithRequestProblemInformation()和WithRequestResponseInformation()是MQTT 5.0的特性,用于让服务器返回更详细的错误信息,但前提是请求能发送到服务器。而本地校验失败的情况不会触发网络请求,所以这些配置不会生效。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

