This article describes how to use the AMQP SDK for .NET to connect a client to Alibaba Cloud IoT Platform and receive messages from IoT Platform.

Development environment

The following table lists the requirements on development environment.

Framework Supported version
.Net Framework 3.5, 4.0, 4.5, or later
.NET Micro Framework 4.2 or later
.NET nanoFramework 1.0 or later
.NET Compact Framework 3.9 or later
.Net Core on Windows 10 and Ubuntu 14.04 1.0 or later
Mono 4.2.1 or later

Download the SDK

We recommend that you use the AMQP.Net Lite library. To download the library and view its instructions, visit AMQP.Net Lite.

Add the dependency

Add the following dependency to the packages.config file:

<packages>
  <package id="AMQPNetLite" version="2.2.0" targetFramework="net47" />
</packages>

Sample code

For more information about the parameters in the following sample code, see Connect an AMQP client to IoT Platform.

using System;
using System.Text;
using Amqp;
using Amqp.Sasl;
using Amqp.Framing;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Cryptography;

namespace amqp
{
    class MainClass
    {
        // For more information about how to configure the host(endpoint), see the "Connect an AMQP client to IoT Platform" topic.
        static string Host = "${YourHost}";
        static int Port = 5671;
        static string AccessKey = "${YourAccessKey}";
        static string AccessSecret = "${YourAccessSecret}";
        static string consumerGroupId = "${YourConsumerGroupId}";
        static string clientId = "${YourClientId}";
        // iotInstanceId: If you are using a purchased instance, you must specify the instance ID. If you are using a public instance, you can enter an empty string "".
        static string iotInstanceId = "${YourIotInstanceId}"; 
        static int Count = 0;
        static int IntervalTime = 10000;

        static Address address;

        public static void Main(string[] args)
        {
            long timestamp = GetCurrentMilliseconds();
            string param = "authId=" + AccessKey + "&timestamp=" + timestamp;
            // For more information about how to configure the userName, see the "Connect an AMQP client to IoT Platform" topic.
            string userName = clientId + "|authMode=aksign,signMethod=hmacmd5,consumerGroupId=" + consumerGroupId
               + ",iotInstanceId=" + iotInstanceId + ",authId=" + AccessKey + ",timestamp=" + timestamp + "|";
            // For more information about how to configure the password, see the "Connect an AMQP client to IoT Platform" topic.
            string password = doSign(param, AccessSecret, "HmacMD5");

            DoConnectAmqp(userName, password);

            ManualResetEvent resetEvent = new ManualResetEvent(false);
            resetEvent.WaitOne();
        }

        static void DoConnectAmqp(string userName, string password)
        {
            address = new Address(Host, Port, userName, password);
            //Create Connection.
            ConnectionFactory cf = new ConnectionFactory();
            //Use local tls if neccessary.
            //cf.SSL.ClientCertificates.Add(GetCert());
            //cf.SSL.RemoteCertificateValidationCallback = ValidateServerCertificate;
            cf.SASL.Profile = SaslProfile.External;
            cf.AMQP.IdleTimeout = 120000;
            //Please customize cf.AMQP.ContainerId, cf.AMQP.HostName.
            cf.AMQP.ContainerId = "client.1.2";
            cf.AMQP.HostName = "contoso.com";
            cf.AMQP.MaxFrameSize = 8 * 1024;
            var connection = cf.CreateAsync(address).Result;

            //Connection Exception Closed.
            connection.AddClosedCallback(ConnClosed);

            //Receive Message.
            DoReceive(connection);
        }

        static void DoReceive(Connection connection)
        {
            //Create Session.
            var session = new Session(connection);

            //Create Receiver Link and Receive Message.
            var receiver = new ReceiverLink(session, "queueName", null);


            receiver.Start(20, (link, message) =>
            {
                object messageId = message.ApplicationProperties["messageId"];
                object topic = message.ApplicationProperties["topic"];
                string body = Encoding.UTF8.GetString((Byte[])message.Body);
                // Note: Do not implement a time-consuming logic for this scenario. If you must implement a business process, use a new thread. Otherwise, message consumption may be blocked. If message consumption is continuously delayed, a potential repercussion is that more messages are re-sent.
                Console.WriteLine("receive message, topic=" + topic + ", messageId=" + messageId + ", body=" + body);

                //Acknowledge Message.
                link.Accept(message);
            });


        }

        // If an exception occurs, the client attempts to re-connect to IoT Platform.
        // This is a basic example. You can use an exponential backoff algorithm to improve the exception handling mechanism and the reconnection policy.
        static void ConnClosed(IAmqpObject _, Error e)
        {
            Console.WriteLine("ocurr error: " + e);
            if(Count < 3)
            {
                Count += 1;
                Thread.Sleep(IntervalTime * Count);
            }
            else
            {
                Thread.Sleep(120000);
            }

            //Reconnection.
            DoConnectAmqp(address.User, address.Password);
        }

        static X509Certificate GetCert()
        {
            string certPath = Environment.CurrentDirectory + "/root.crt";
            X509Certificate crt = new X509Certificate(certPath);

            return crt;
        }

        static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }

        static long GetCurrentMilliseconds()
        {
            DateTime dt1970 = new DateTime(1970, 1, 1);
            DateTime current = DateTime.Now;
            return (long)(current - dt1970).TotalMilliseconds;
        }

        //Signature method: hmacmd5, hmacsha1, or hmacsha256.
        static string doSign(string param, string accessSecret, string signMethod)
        {
            //signMethod = HmacMD5
            byte[] key = Encoding.UTF8.GetBytes(accessSecret);
            byte[] signContent = Encoding.UTF8.GetBytes(param);
            var hmac = new HMACMD5(key);
            byte[] hashBytes = hmac.ComputeHash(signContent);
            return Convert.ToBase64String(hashBytes);
        }
    }
}