Use the Simple Message Queue (formerly MNS) SDK for C# to build a complete pub/sub messaging workflow: create a topic and queue, subscribe the queue to the topic, publish a message, receive and delete the message, then clean up resources.
Prerequisites
An Alibaba Cloud account or a RAM user with the required permissions
An AccessKey pair (AccessKey ID and AccessKey secret). To create one:
Alibaba Cloud account: Go to the AccessKey Management page in the Alibaba Cloud Management Console.
RAM user: Log on to the RAM console.
The endpoint for your region. Log on to the SMQ console to view endpoints. Endpoints vary by region. For details, see View the endpoints of a topic.
Store your AccessKey ID and AccessKey secret securely. Do not hard-code them in source files committed to version control.
Set up the environment
Download the latest version of the SDK for C#, decompress the package, and add the folder to Visual Studio as a solution.
The solution contains four projects. Right-click the AliyunSDK_MNS project and select Rebuild. This generates the
Aliyun.MNS.dllfile in the bin directory of the project. > Note: SetAliyun.MNS.dllas the reference for the other three projects.In the AliyunSDK_MNS_Sample project, open
SyncTopicOperations.cs:Set AliyunSDK_MNS_Sample as the startup project and SyncTopicOperations as the startup object.
Specify your AccessKey ID, AccessKey secret, and endpoint.
Create a topic
Create a topic with CreateTopicRequest. The default topic name is TestCSharpTopic.
// Create a topic. You can also specify other topic parameters.
var createTopicRequest = new CreateTopicRequest
{
TopicName = _topicName
};
Topic topic = null;
try
{
topic = client.CreateTopic(createTopicRequest);
Console.WriteLine("Create topic successfully, topic name: {0}", topic.TopicName);
}
catch (MNSException me)
{
// The operation fails if a network error occurs or the topic name already exists.
// Use CatchException or catch TopicAlreadyExistException to handle the failure.
Console.WriteLine("CreateTopic Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Create topic failed, exception info: " + ex.Message);
return;
}Create a queue
If you have not created a queue, you must first create one. The default queue name is myqueue. You can modify the code to specify a different queue name.
// 1. Specify the properties for the queue. For more information about queue properties, see Queue.
var createQueueRequest = new CreateQueueRequest
{
QueueName = _queueName,
Attributes =
{
// VisibilityTimeout is the most important property. The default value is 30 seconds.
VisibilityTimeout = 30,
MaximumMessageSize = 40960,
MessageRetentionPeriod = 345600,
// PollingWaitSeconds is the timeout period for long polling.
PollingWaitSeconds = 30
}
};
try
{
// 2. Create the queue. If you do not need to specify queue properties, you can call client.CreateQueue(_queueName).
var queue = client.CreateQueue(createQueueRequest);
Console.WriteLine("Create queue successfully, queue name: {0}", queue.QueueName);
}
catch (MNSException me)
{
// 3. If an error occurs when you create the queue, you can handle the error based on the error code. You can also catch exceptions such as QueueAlreadyExistException to handle them separately.
Console.WriteLine("CreateQueue Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Create queue failed, exception info: " + ex.Message);
} Create a subscription
Subscribe the queue to the topic. The subscription endpoint follows the format acs:mns:{region}:{accountId}:queues/{queueName}.
string region = "";
string accountId = "";
string queueName = "TestQueue";
try
{
// The second parameter specifies the endpoint that receives messages.
SubscribeResponse res = topic.Subscribe(_subscriptionName,
"acs:mns:" + region + ":" + accountId + ":queues/" + queueName);
Console.WriteLine("Subscribe succeed");
}
catch (MNSException me)
{
// The operation fails if a network error occurs or the subscription name already exists.
Console.WriteLine("Subscribe Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Subscribe failed, exception info: " + ex.Message);
}Replace region, accountId, and queueName with your actual values.
Publish a message
Publish a message to the topic. The topic pushes the message to all subscribed endpoints.
try
{
var response = topic.PublishMessage("message here </asdas\">");
Console.WriteLine("PublishMessage succeed! " + response.MessageId);
}
catch (MNSException me)
{
// The operation fails if a network error occurs.
Console.WriteLine("PublishMessage Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("PublishMessage failed, exception info: " + ex.Message);
}Receive and delete a message from the queue
After the topic pushes a message to the queue, receive and then delete the message.
Receive a message
Use long polling with WaitSeconds set to 30. The request holds until a message arrives or the timeout expires. The maximum value of WaitSeconds is 30.
try
{
// 1. Call the receiveMessage function.
// The receiveMessage function accepts the waitSeconds parameter. Set this parameter to 30.
// A waitSeconds value other than 0 indicates that this receiveMessage call is an HTTP long polling request. If no message exists in the queue, the request waits on the server until a message is available. The maximum wait time is the value of waitSeconds, up to a maximum of 30.
var receiveMessageResponse = nativeQueue.ReceiveMessage(30);
// 2. Get the receipt handle. This is a time-sensitive handle that you can use to set message properties and delete the message. For more information, see QueueMessage.
_receiptHandle = message.ReceiptHandle;
}
catch (MNSException me)
{
// 3. Similar to CreateQueue and SendMessage, an error can occur when you call ReceiveMessage. Catch the exception and handle it.
Console.WriteLine("ReceiveMessage Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("ReceiveMessage failed, exception info: " + ex.Message);
}
// Add your logic to process the message here. This step is omitted in the sample.
// If an exception such as a program crash or freeze occurs, the message becomes visible again after the VisibilityTimeout period expires. This allows other processes to handle the message and prevents message loss.
// 4. After the message is processed, delete it from the queue.
try
{
// 5. Call deleteMessage.
var deleteMessageResponse = nativeQueue.DeleteMessage(_receiptHandle);
}
catch (MNSException me)
{
// 6. Catch the exception and handle it.
// If the receipt handle has expired, the error code is MessageNotExist. This indicates that the message cannot be found using this receipt handle.
// To prevent the receipt handle from expiring, make sure that the VisibilityTimeout value is long enough for the message to be processed. During message processing, you can also call the changeMessageVisibility function to extend the VisibilityTimeout period of the message.
Console.WriteLine("DeleteMessage Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Delete message failed, exception info: " + ex.Message);
} Process and delete the message
After processing the message, delete it from the queue using the receipt handle. The VisibilityTimeout parameter controls how long a message stays in the Inactive state after a client consumes it. Once the timeout expires, the message returns to the Active state and becomes available to other clients. This prevents message loss from unexpected exits.
try
{
var deleteQueueResponse = client.DeleteQueue(deleteQueueRequest);
}
catch (MNSException me)
{
Console.WriteLine("DeleteQueue Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Delete queue failed, exception info: " + ex.Message);
} Delete the topic
Delete the topic when it is no longer needed.
try
{
client.DeleteTopic(_topicName);
Console.WriteLine("Delete topic succeed");
}
catch (Exception ex)
{
Console.WriteLine("Delete topic failed, exception info: " + ex.Message);
}Delete the queue
Delete the queue when it is no longer needed.
try
{
var deleteQueueResponse = client.DeleteQueue(deleteQueueRequest);
}
catch (MNSException me)
{
Console.WriteLine("DeleteQueue Failed! ErrorCode: " + me.ErrorCode);
}
catch (Exception ex)
{
Console.WriteLine("Delete queue failed, exception info: " + ex.Message);
} Error handling
All SDK operations can throw MNSException, which contains an ErrorCode property. Common failure causes include:
| Error scenario | Cause | Resolution |
|---|---|---|
| Topic or queue creation fails | Network error or resource name already exists | Check network connectivity. Use a unique name or catch TopicAlreadyExistException. |
MessageNotExist on delete | The receipt handle has expired | Increase VisibilityTimeout or call changeMessageVisibility() to extend it before the handle expires. |
| Subscription creation fails | Network error or subscription name already exists | Check network connectivity. Use a unique subscription name. |