nanoFramework.M2Mqtt 5.1.138
前缀已保留
dotnet add package nanoFramework.M2Mqtt --version 5.1.138
NuGet\Install-Package nanoFramework.M2Mqtt -Version 5.1.138
<PackageReference Include="nanoFramework.M2Mqtt" Version="5.1.138" />
paket add nanoFramework.M2Mqtt --version 5.1.138
#r "nuget: nanoFramework.M2Mqtt, 5.1.138"
// Install nanoFramework.M2Mqtt as a Cake Addin #addin nuget:?package=nanoFramework.M2Mqtt&version=5.1.138 // Install nanoFramework.M2Mqtt as a Cake Tool #tool nuget:?package=nanoFramework.M2Mqtt&version=5.1.138
.NET nanoFramework M2Mqtt
欢迎使用 .NET nanoFramework 的 MQTT 客户端库。当前版本支持 v3.1、v3.1.1 和 v5.0。
这是 MQTT 客户端库 M2Mqtt 的初期移植。原始项目有一个官方网站 在这里。
自那时以来,MQTT 客户端经历了一些变化,并已适应 .NET nanoFramework。
构建状态
组件 | 构建状态 | NuGet 包 |
---|---|---|
nanoFramework.M2Mqtt |
项目描述
M2Mqtt 是一种物联网和机器对机器 (M2M) 通信的 MQTT 客户端。
MQTT(消息队列遥测传输),是一种轻量级消息协议,允许资源有限的嵌入式设备在受限网络上执行异步通信。
MQTT 协议基于发布/订阅模式,因此客户端可以订阅一个或多个主题,并接收其他客户端发布到这些主题的消息。
此库包含一个示例 MQTT 客户端,您可以使用它连接到任何 MQTT 代理。
这些二进制文件可以作为 NuGet 包 获取。
有关 MQTT 协议的所有信息,请访问 MQTT 官方 网站。为了正确使用 MQTT 协议,建议您了解 MQTT 协议的工作方式。服务质量(QoS)机制是需要理解的一个重要方面。
使用方法
使用方法在所有版本中都是相同的。在 v3.1.1 和 v5.0 之间存在一些特定性。版本 5.0 带来了更多控制性和额外的属性。为了方便,所有属性的注释中都带有 仅 v5.0
。如果使用 v5.0 属性与 v3.1 或 v3.1.1 协议,它们将被忽略。
以下是一个创建 v3.1.1 服务器并将其连接的简单示例
MqttClient mqtt = new MqttClient("test.mosquitto.org", 8883, true, new X509Certificate(CertMosquitto), null, MqttSslProtocols.TLSv1_2);
var ret = mqtt.Connect("nanoTestDevice", true);
if (ret != MqttReasonCode.Success)
{
Debug.WriteLine($"ERROR connecting: {ret}");
mqtt.Disconnect();
return;
}
对于 v5.0,您只需在连接之前指定版本即可
MqttClient mqtt = new MqttClient("test.mosquitto.org", 8883, true, new X509Certificate(CertMosquitto), null, MqttSslProtocols.TLSv1_2);
mqtt.ProtocolVersion = MqttProtocolVersion.Version_5;
var ret = mqtt.Connect("nanoTestDevice", true);
if (ret != MqttReasonCode.Success)
{
Debug.WriteLine($"ERROR connecting: {ret}");
mqtt.Disconnect();
return;
}
注意:在以下示例中,需要特定的证书才能连接到 Mosquitto 服务器。您可以在 示例 中找到它。
v5.0 扩展认证流程
MQTT 5.0 支持特定的认证流程。在 Connect 之后,可以使用认证机制作为挑战请求。在这种情况下,您需要
- 确保已将 v5 设置为协议
- 将属性
IsAuthenticationFlow
设置为 true - 注册到
Authentication
事件 - 通过发送另一个认证消息或任何与您情况相关的其他内容来相应地管理答案。
注意:此协议使用 AuthenticationMethod
和 AuthenticationData
作为此类特定机制的属性。
以下是规范给出的示例
非规范性示例显示 SCRAM 挑战
- 客户端到服务器:CONNECT Authentication Method="SCRAM-SHA-1" Authentication Data=client-first-data
- 服务器到客户端:AUTH rc=0x18 Authentication Method="SCRAM-SHA-1" Authentication Data=server-first-data
- 客户端到服务器 AUTH rc=0x18 Authentication Method="SCRAM-SHA-1" Authentication Data=client-final-data
- 服务器到客户端 CONNACK rc=0 Authentication Method="SCRAM-SHA-1" Authentication Data=server-final-data
非规范性示例显示 Kerberos 挑战
- 客户端到服务器 CONNECT Authentication Method="GS2-KRB5"
- 服务器到客户端 AUTH rc=0x18 Authentication Method="GS2-KRB5"
- 客户端到服务器 AUTH rc=0x18 Authentication Method="GS2-KRB5" Authentication Data=initial context token
- 服务器到客户端 AUTH rc=0x18 Authentication Method="GS2-KRB5" Authentication Data=reply context token
- 客户端到服务器 AUTH rc=0x18 Authentication Method="GS2-KRB5"
- 服务器到客户端 CONNACK rc=0 Authentication Method="GS2-KRB5" Authentication Data=outcome of authentication
在这些机制中,只有在收到成功代码的 Connack 之后,IsConnected
属性才会被设置一次。由于这些认证机制是特定且用户配置的,这个特定的 MqttClient
提供了使用此机制的能力。
订阅事件
MqttClient 提供了事件。您可以订阅它们。例如,您可以使用 v5.0 协议获取连接打开时的额外信息。以下示例显示启用 MQTT v5.0 协议连接到 Azure IoT Hub 所需的内容
// Create the client
MqttClient mqtt = new MqttClient(IoTHub, 8883, true, new X509Certificate(CertAzure), null, MqttSslProtocols.TLSv1_2);
// Setup the version
mqtt.ProtocolVersion = MqttProtocolVersion.Version_5;
// Register to events
mqtt.ConnectionOpened += MqttConnectionOpened;
// You can add additional properties
var at = DateTime.UtcNow;
var atString = (at.ToUnixTimeSeconds() * 1000).ToString();
var expiry = at.AddMinutes(40);
var expiryString = (expiry.ToUnixTimeSeconds() * 1000).ToString();
string toSign = $"{IoTHub}\n{DeviceID}\n\n{atString}\n{expiryString}\n";
var hmac = new HMACSHA256(Convert.FromBase64String(Sas));
var sas = hmac.ComputeHash(Encoding.UTF8.GetBytes(toSign));
mqtt.AuthenticationMethod = "SAS";
mqtt.AuthenticationData = sas;
mqtt.UserProperties.Add(new UserProperty("sas-at", atString));
mqtt.UserProperties.Add(new UserProperty("sas-expiry", expiryString));
mqtt.UserProperties.Add(new UserProperty("api-version", "2020-10-01-preview"));
mqtt.UserProperties.Add(new UserProperty("host", IoTHub));
var ret = mqtt.Connect(DeviceID, null, null, false, MqttQoSLevel.AtLeastOnce, false, null, null, true, 60);
// You will have more code here
private static void MqttConnectionOpened(object sender, ConnectionOpenedEventArgs e)
{
Debug.WriteLine($"Connection open");
Debug.WriteLine($" ClientID: {((MqttClient)sender).ClientId}");
Debug.WriteLine($" Assigned client id: {e.Message.AssignedClientIdentifier}");
if (e.Message.AuthenticationData != null) Debug.WriteLine($" Auth data length: {e.Message.AuthenticationData.Length}");
Debug.WriteLine($" Auth method: {e.Message.AuthenticationMethod}");
Debug.WriteLine($" Dup flag: {e.Message.DupFlag}");
Debug.WriteLine($" Max packet size: {e.Message.MaximumPacketSize}");
Debug.WriteLine($" Max QoS: {e.Message.MaximumQoS}");
Debug.WriteLine($" Msg ID: {e.Message.MessageId}");
Debug.WriteLine($" Qos level: {e.Message.QosLevel}");
Debug.WriteLine($" Reason: {e.Message.Reason}");
Debug.WriteLine($" Receive max: {e.Message.ReceiveMaximum}");
Debug.WriteLine($" Rep info: {e.Message.ResponseInformation}");
Debug.WriteLine($" Retain: {e.Message.Retain}");
Debug.WriteLine($" Retain available: {e.Message.RetainAvailable}");
Debug.WriteLine($" Return code: {e.Message.ReturnCode}");
Debug.WriteLine($" Server keep alive: {e.Message.ServerKeepAlive}");
Debug.WriteLine($" Server ref: {e.Message.ServerReference}");
Debug.WriteLine($" Session exp inter: {e.Message.SessionExpiryInterval}");
Debug.WriteLine($" Session present: {e.Message.SessionPresent}");
Debug.WriteLine($" Shared subs available: {e.Message.SharedSubscriptionAvailable}");
Debug.WriteLine($" Shared identifier available: {e.Message.SubscriptionIdentifiersAvailable}");
Debug.WriteLine($" Topic alias max: {e.Message.TopicAliasMaximum}");
Debug.WriteLine($" Num user props: {e.Message.UserProperties.Count}");
foreach (UserProperty prop in e.Message.UserProperties)
{
Debug.WriteLine($" Key : {prop.Name}");
Debug.WriteLine($" Value: {prop.Value}");
}
Debug.WriteLine($" Wildcard available: {e.Message.WildcardSubscriptionAvailable}");
}
示例
M2Mqtt 库提供了一个表示连接到代理的 MQTT 客户端的 MqttClient
主类。您可以通过提供代理的 IP 地址或主机名以及可选的与 MQTT 协议相关的参数来连接到代理。
连接到代理后,您可以使用 Publish()
方法向主题发布消息,使用 Subscribe()
方法订阅主题并接收其上发布的消息。MqttClient
类是基于事件驱动的,因此在您订阅的主题上发布消息时,您会收到一个事件。您可以在消息发布完成、订阅或退订主题时接收事件。
以下是一个客户端订阅主题的示例
string MQTT_BROKER_ADDRESS = "192.168.1.2";
// create client instance
MqttClient client = new MqttClient(IPAddress.Parse(MQTT_BROKER_ADDRESS));
// register to message received
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
string clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
// subscribe to the topic "/home/temperature" with QoS 2
client.Subscribe(new string[] { "/home/temperature" }, new MqttQoSLevel[] { MqttMsgBase.ExactlyOnce });
// You can add some code here
static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
// handle message received
}
以下是一个客户端发布主题的示例
string MQTT_BROKER_ADDRESS = "192.168.1.2";
// create client instance
MqttClient client = new MqttClient(IPAddress.Parse(MQTT_BROKER_ADDRESS));
string clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
string strValue = Convert.ToString(value);
// publish a message on "/home/temperature" topic with QoS 2
client.Publish("/home/temperature", Encoding.UTF8.GetBytes(strValue), MqttQoSLevel.ExactlyOnce, false);
// More code goes here
避免证书检查
在某些情况下,通过 TLS 连接时,避免证书检查可能会很方便。虽然这种场景不建议使用,但您可以像这样进行调整
// You can specify no certificate at all
MqttClient mqtt = new MqttClient(IoTHub, 8883, true, null, null, MqttSslProtocols.TLSv1_2);
// And you have to setup the ValidateServerCertificate to false
mqtt.Settings.ValidateServerCertificate = false;
string clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
反馈和文档
有关文档、提供反馈、问题以及了解如何贡献的信息,请参阅首页仓库。
加入我们的 Discord 社区这里。
致谢
该项目贡献者的名单可在CONTRIBUTORS中找到。这个库是由Paolo Patierno 创建和维护的,它是Eclipse 项目的一部分。
许可协议
nanoFramework 类库根据 MIT 许可协议 许可。
行为准则
本项目采用了由贡献者承诺定义的行为准则,以阐明我们社群中预期的行为。有关更多信息,请参阅.NET 基金会行为准则。
.NET 基金会
本项目由.NET 基金会 支持。
产品 | 版本 兼容和额外的计算目标框架版本。 |
---|---|
.NET Framework | net 兼容。 |
-
- nanoFramework.CoreLibrary (>= 1.15.5)
- nanoFramework.Runtime.Events (>= 1.11.18)
- nanoFramework.Runtime.Native (>= 1.6.12)
- nanoFramework.System.Collections (>= 1.5.31)
- nanoFramework.System.Net (>= 1.11.1)
NuGet 包 (5)
显示依赖于 nanoFramework.M2Mqtt 的前 5 个 NuGet 包
包 | 下载 |
---|---|
nanoFramework.Azure.Devices.Client 此包包含用于 .NET nanoFramework 的 .NET nanoFramework.Azure.Devices.Client 程序集。这是一个基于 MQTT 代理的 Azure IoT Hub SDK。 |
|
nanoFramework.Aws.IoTCore.Devices 本包包含 nanoFramework C# 项目所需的 .NET nanoFramework.Aws.IoTCore.Devices 程序集。这是一个为 Aws IoTCore 提供的 SDK。 |
|
MakoIoT.Device.Services.Mqtt
MAKO-IoT 消息总线的 MQTT 库 |
|
MakoIoT.Device.Services.AzureIotHub
MAKO-IoT 的 AzureIoTHub 总线提供者 |
|
DevBot9.NanoFramework.Homie.Utilities
nanoFramework 的 Homie 实现 |
GitHub 仓库 (2)
显示依赖于 nanoFramework.M2Mqtt 的最流行的前 2 个 GitHub 仓库
仓库 | 星级 |
---|---|
dotnet/samples
.NET 文档中引用的示例代码
|
|
nanoframework/Samples
🍬 nanoFramework 团队用于测试、证明概念和其他探索性努力中的代码示例
|
版本 | 下载 | 最后更新 |
---|---|---|
5.1.138 | 202 | 7/30/2024 |
5.1.130 | 955 | 5/13/2024 |
5.1.128 | 210 | 5/10/2024 |
5.1.126 | 294 | 4/30/2024 |
5.1.123 | 412 | 4/9/2024 |
5.1.120 | 372 | 4/3/2024 |
5.1.116 | 792 | 1/29/2024 |
5.1.114 | 228 | 1/26/2024 |
5.1.112 | 240 | 1/24/2024 |
5.1.110 | 255 | 1/21/2024 |
5.1.107 | 1,478 | 11/10/2023 |
5.1.103 | 187 | 11/9/2023 |
5.1.101 | 255 | 11/8/2023 |
5.1.99 | 99 | 11/8/2023 |
5.1.96 | 674 | 10/10/2023 |
5.1.94 | 975 | 8/28/2023 |
5.1.92 | 230 | 8/28/2023 |
5.1.90 | 245 | 8/28/2023 |
5.1.79 | 3,060 | 1/14/2023 |
5.1.75 | 877 | 12/28/2022 |
5.1.70 | 653 | 12/27/2022 |
5.1.68 | 363 | 12/22/2022 |
5.1.61 | 957 | 11/24/2022 |
5.1.59 | 694 | 11/22/2022 |
5.1.53 | 1,224 | 11/4/2022 |
5.1.48 | 850 | 10/28/2022 |
5.1.46 | 394 | 10/28/2022 |
5.1.44 | 1,943 | 10/26/2022 |
5.1.42 | 622 | 10/25/2022 |
5.1.40 | 386 | 10/25/2022 |
5.1.34 | 3,155 | 10/14/2022 |
5.1.27 | 961 | 10/10/2022 |
5.1.25 | 1,153 | 10/8/2022 |
5.1.22 | 1,695 | 9/22/2022 |
5.1.20 | 992 | 9/22/2022 |
5.1.18 | 1,575 | 9/15/2022 |
5.1.16 | 979 | 9/15/2022 |
5.1.11 | 2,392 | 8/4/2022 |
5.1.9 | 729 | 8/4/2022 |
5.1.6 | 937 | 8/4/2022 |
5.1.4 | 665 | 8/3/2022 |
5.1.2 | 977 | 8/3/2022 |
5.0.2.28 | 673 | 8/3/2022 |
5.0.2.26 | 2,857 | 6/13/2022 |
5.0.2.24 | 1,294 | 6/8/2022 |
5.0.2.22 | 699 | 6/8/2022 |
5.0.2.17 | 1,085 | 5/26/2022 |
5.0.2.15 | 1,603 | 5/18/2022 |
5.0.2.13 | 1,350 | 5/3/2022 |
5.0.2 | 1,887 | 3/28/2022 |
5.0.2-preview.100 | 130 | 3/28/2022 |
5.0.2-preview.98 | 137 | 3/28/2022 |
5.0.2-preview.96 | 130 | 3/28/2022 |
5.0.2-preview.94 | 144 | 3/28/2022 |
5.0.2-preview.91 | 182 | 3/17/2022 |
5.0.2-preview.89 | 135 | 3/17/2022 |
5.0.2-preview.87 | 167 | 3/15/2022 |
5.0.2-preview.85 | 128 | 3/15/2022 |
5.0.2-preview.83 | 148 | 3/15/2022 |
5.0.2-preview.80 | 440 | 2/17/2022 |
5.0.2-preview.78 | 173 | 2/8/2022 |
5.0.2-preview.76 | 200 | 2/4/2022 |
5.0.2-preview.74 | 145 | 2/4/2022 |
5.0.2-preview.72 | 179 | 1/28/2022 |
5.0.2-preview.70 | 141 | 1/28/2022 |
5.0.2-preview.68 | 157 | 1/28/2022 |
5.0.2-preview.65 | 154 | 1/25/2022 |
5.0.2-preview.63 | 151 | 1/21/2022 |
5.0.2-preview.61 | 145 | 1/21/2022 |
5.0.2-preview.59 | 137 | 1/21/2022 |
5.0.2-preview.57 | 136 | 1/21/2022 |
5.0.2-preview.55 | 169 | 1/14/2022 |
5.0.2-preview.53 | 138 | 1/14/2022 |
5.0.2-preview.49 | 210 | 1/5/2022 |
5.0.2-preview.47 | 144 | 1/5/2022 |
5.0.2-preview.46 | 189 | 1/4/2022 |
5.0.2-preview.45 | 172 | 12/31/2021 |
5.0.2-preview.44 | 144 | 12/31/2021 |
5.0.2-preview.43 | 155 | 12/29/2021 |
5.0.2-preview.41 | 190 | 12/17/2021 |
5.0.2-preview.39 | 312 | 12/4/2021 |
5.0.2-preview.37 | 169 | 12/3/2021 |
5.0.2-preview.35 | 174 | 12/3/2021 |
5.0.2-preview.33 | 162 | 12/2/2021 |
5.0.2-preview.31 | 165 | 12/2/2021 |
5.0.2-preview.29 | 165 | 12/1/2021 |
5.0.2-preview.26 | 355 | 11/14/2021 |
5.0.2-preview.24 | 272 | 11/13/2021 |
5.0.2-preview.20 | 206 | 11/12/2021 |
5.0.2-preview.18 | 187 | 10/23/2021 |
5.0.2-preview.15 | 279 | 10/19/2021 |
5.0.2-preview.12 | 168 | 10/18/2021 |
5.0.2-preview.9 | 907 | 9/17/2021 |
5.0.2-preview.6 | 197 | 9/16/2021 |
5.0.2-preview.1 | 633 | 8/2/2021 |
5.0.1 | 947 | 8/2/2021 |
5.0.1-preview.5 | 237 | 7/27/2021 |
5.0.1-preview.4 | 193 | 7/26/2021 |
5.0.1-preview.3 | 250 | 7/17/2021 |
5.0.0 | 592 | 7/16/2021 |
5.0.0-preview.4 | 141 | 7/16/2021 |
5.0.0-preview.3 | 148 | 7/16/2021 |
5.0.0-preview.2 | 780 | 7/3/2021 |
4.6.1-preview.90 | 222 | 7/3/2021 |
4.6.1-preview.89 | 219 | 6/20/2021 |
4.6.1-preview.88 | 256 | 6/19/2021 |
4.6.1-preview.86 | 260 | 6/19/2021 |
4.6.1-preview.85 | 169 | 6/18/2021 |
4.6.1-preview.84 | 157 | 6/17/2021 |
4.6.1-preview.83 | 196 | 6/8/2021 |
4.6.1-preview.82 | 163 | 6/7/2021 |
4.6.1-preview.80 | 165 | 6/7/2021 |
4.6.1-preview.79 | 194 | 6/7/2021 |
4.6.1-preview.78 | 193 | 6/7/2021 |
4.6.1-preview.77 | 199 | 6/6/2021 |
4.6.1-preview.76 | 223 | 6/1/2021 |
4.6.1-preview.75 | 194 | 5/31/2021 |
4.6.1-preview.74 | 200 | 5/30/2021 |
4.6.1-preview.73 | 172 | 5/26/2021 |
4.6.1-preview.72 | 185 | 5/22/2021 |
4.6.1-preview.71 | 220 | 5/21/2021 |
4.6.1-preview.70 | 170 | 5/19/2021 |
4.6.1-preview.69 | 169 | 5/19/2021 |
4.6.1-preview.68 | 181 | 5/19/2021 |
4.6.1-preview.67 | 162 | 5/15/2021 |
4.6.1-preview.66 | 153 | 5/15/2021 |
4.6.1-preview.65 | 162 | 5/13/2021 |
4.6.1-preview.64 | 168 | 5/13/2021 |
4.6.1-preview.63 | 189 | 5/11/2021 |
4.6.1-preview.62 | 167 | 5/6/2021 |
4.6.1-preview.61 | 154 | 5/6/2021 |
4.6.1-preview.60 | 149 | 5/5/2021 |
4.6.1-preview.59 | 146 | 5/5/2021 |
4.6.1-preview.58 | 148 | 5/5/2021 |
4.6.1-preview.57 | 148 | 5/5/2021 |
4.6.1-preview.56 | 193 | 4/10/2021 |
4.6.1-preview.54 | 164 | 3/31/2021 |
4.6.1-preview.52 | 172 | 3/31/2021 |
4.6.1-preview.51 | 165 | 3/29/2021 |
4.6.1-preview.28 | 516 | 12/7/2020 |
4.6.1-preview.27 | 307 | 10/21/2020 |
4.6.1-preview.25 | 291 | 10/21/2020 |
4.6.1-preview.24 | 281 | 10/21/2020 |
4.6.1-preview.22 | 273 | 10/20/2020 |
4.6.1-preview.21 | 329 | 10/1/2020 |
4.6.1-preview.19 | 322 | 10/1/2020 |
4.6.1-preview.18 | 250 | 9/30/2020 |
4.6.1-preview.17 | 267 | 9/30/2020 |
4.6.1-preview.16 | 291 | 9/27/2020 |
4.6.1-preview.15 | 282 | 9/27/2020 |
4.6.1-preview.13 | 272 | 9/19/2020 |
4.6.1-preview.12 | 274 | 9/19/2020 |
4.6.1-preview.11 | 280 | 9/19/2020 |
4.6.1-preview.10 | 318 | 7/2/2020 |
4.6.0-preview.7 | 280 | 6/17/2020 |
4.4.1-preview.5 | 283 | 6/12/2020 |
4.4.1-preview.2 | 310 | 6/11/2020 |
4.4.1-preview.1 | 290 | 6/5/2020 |
4.4.0-preview.30 | 459 | 6/3/2020 |
4.4.0-preview.29 | 286 | 6/3/2020 |
4.4.0-preview.28 | 306 | 6/1/2020 |
4.4.0-preview.27 | 380 | 5/31/2020 |
4.4.0-preview.26 | 284 | 5/29/2020 |
4.4.0-preview.25 | 292 | 5/8/2020 |
4.4.0-preview.24 | 284 | 5/8/2020 |
4.4.0-preview.23 | 280 | 4/27/2020 |
4.4.0-preview.22 | 310 | 4/16/2020 |
4.4.0-preview.20 | 293 | 4/16/2020 |
4.4.0-preview.19 | 272 | 4/14/2020 |
4.4.0-preview.18 | 274 | 4/14/2020 |
4.4.0-preview.17 | 260 | 4/14/2020 |
4.4.0-preview.16 | 270 | 3/25/2020 |
4.4.0-preview.10 | 369 | 11/14/2019 |
4.4.0-preview.9 | 290 | 11/12/2019 |
4.4.0-preview.8 | 283 | 11/8/2019 |
4.4.0-preview.7 | 283 | 11/7/2019 |
4.4.0-preview.5 | 299 | 11/5/2019 |
4.4.0-preview.4 | 308 | 10/30/2019 |
4.4.0-preview.3 | 317 | 10/30/2019 |
4.3.1 | 844 | 10/15/2019 |
4.3.1-preview.17 | 297 | 10/15/2019 |
4.3.1-preview.16 | 290 | 9/24/2019 |
4.3.1-preview.15 | 301 | 9/24/2019 |
4.3.1-preview.14 | 306 | 9/11/2019 |
4.3.1-preview.13 | 300 | 9/11/2019 |
4.3.1-preview.10 | 297 | 7/20/2019 |
4.3.1-preview.6 | 399 | 7/15/2019 |
4.3.1-preview.3 | 312 | 7/12/2019 |
4.3.1-preview.1 | 387 | 7/10/2019 |