This code provides .NET v3.5 bindings written in C# to communicate with the SoftLayer Message Queue API.
The following are required to build and use the Message Queue library:
- Microsoft .NET 3.5 Client Profile or higher (we've tested in 4.0 as well)
- RestSharp v104.0+ (this is available via NuGet, if you use it; otherwise, a
pre-built binary is included in the
Dependencies
folder. We've also included this specific release of RestSharp underDependencies\RestSharp
as a git submodule, in case you wish to build this specific release yourself). - A SoftLayer customer account with message queue service already activated. (Since the service is usage-based, the initial order required to activate it on your account does not charge anything. During each billing period thereafter, you will be billed based on your usage over that period.)
You may include the code in your Visual Studio solution as a reference and build it from there alongside your main project, or you can build separately and add the binary to your project as a reference.
Once you have included the client as a reference, you can use the
SoftLayer.Messaging
namespace in your code and follow the usage examples below
to get started.
If you wish to run the supplied unit tests, you'll need NUnit with its shadow copying disabled.
Once you know your user name, account ID, and API key, and datacenter (all can be obtained from the SoftLayer Customer Portal), you can pass them into a new MessagingClient instance. This instance provides the conduit through which you must pass Queue, Message, Topic, and ITopicSubscription-based objects to the Message Queue API with your requests.
First, make sure you're using the Messaging namespace:
using SoftLayer.Messaging;
Next, you can initialize a client session to the API:
string myUserName = "happycustomer";
string myAccountId = "5yc2z";
string myApiKey = "98b0c8158e633d5c5ed63ad24584cadfa0e6e047c4c9e7e3adb3368aaa02964";
string myDatacenter = "DAL05";
MessagingClient client = new MessagingClient(myUserName, myAccountId, myApiKey, myDatacenter);
try {
client.Authenticate();
}
catch (UnauthorizedException e) {
Console.WriteLine("Exception: " + e.Message);
}
Alternatively, you may use your application's app.config file to store your Message Queue credentials. An example is located under SoftLayer.Messaging\example.config, but follows this format:
<!--your application's app.config-->
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="SoftLayer.Messaging.AccountID" value="5yc2z" />
<add key="SoftLayer.Messaging.UserName" value="happycustomer" />
<add key="SoftLayer.Messaging.APIKey" value="98b0c8158e633d5c5ed63ad24584cadfa0e6e047c4c9e7e3adb3368aaa02964" />
<add key="SoftLayer.Messaging.DataCenter" value="dal05" />
<add key="SoftLayer.Messaging.PrivateEndpoint" value="false" />
</appSettings>
</configuration>
You can then call the MessagingClient
constructor with no arguments, and it
will use the settings you've defined in app.config.
MessagingClient client = new MessagingClient();
After successfully authenticating, you can create a new queue several ways:
Queue widgetQueue = client.CreateQueue("widget_queue");
// or...
Queue widgetQueue = new Queue("widget_queue");
client.CreateQueue(widgetQueue);
Once you've created your new queue, you can begin pushing messages to it easily:
Message myMessage = new Message("Hello, world!");
client.PublishToQueue(widgetQueue, myMessage);
// or...
Message myMessage = client.PublishToQueue(
widgetQueue,
new Message("Hello, world!"));
The Message object you receive back from MessagingClient::PublishToQueue()
will
provide the resulting unique message ID.
While not always necessary, you might wish to keep track of the message ID so that you can explicitly delete it later once you've retrieved it from the queue, or to accomodate more advanced scenarios like redundancy checks within your application that are based on a message's unique ID.
Topics allow for more advanced scenarios where you may wish to publish messages to multiple queues, or even notify remote endpoints via HTTP/HTTPS, but they work much the same way on the client side. Just like queues, you can publish messages directly to them.
For additional information on how topics work and the kinds of scenarios they can accomodate, see our Exploring Topics guide.
Creating a new topic is just as straightforward as creating a new queue:
Topic widgetsTopic = client.CreateTopic("widgets");
// or:
Topic widgetsTopic = new Topic("widgets");
client.createTopic(widgetsTopic);
Since topics simply serve as a single point of input that routes messages to as many different places as needed, they don't store messages themselves, so at least one topic subscription is necessary.
Now that the widgets topic exists, we'll create a QueueTopicSubscription
to
allow our widget_queue
to receive messages published to the widgets
topic:
QueueTopicSubscription queueSubscription =
new QueueTopicSubscription(widgetQueue.Name);
client.CreateTopicSubscription(widgetsTopic, queueSubscription);
We may also wish to receive an HTTP POST to a remote URL each time a message is
published to widgets
. In this case, we use a HttpTopicSubscription
instance,
optionally specifying additional query string parameters (via the Parameters
property) HTTP headers (via the Headers
property), or, in the case of a POST
or PUT, a corresponding HTTP body (the Body
property).
HTTP notifications can include variables that include various bits of information about each message published to a topic. These variables are enclosed by curly braces ("{" and "}") and can be included in the subscription's URL, headers, body, and URL parameters.
HttpTopicSubscription httpSubscription = new
HttpTopicSubscription("https://example.com/api/topic_notify");
httpSubscription.HttpMethod = HttpTopicSubscriptionMethod.POST;
httpSubscription.Parameters.Add("topic_id", "{topic_id}");
httpSubscription.Parameters.Add("subscription_id", "{subscription_id}");
httpSubscription.Headers.Add("X-Topic-Id", "{topic_id}");
httpSubscription.Headers.Add("X-Subscription-Id", "{subscription_id}");
httpSubscription.Body =
"{\"topic_id\":\"{topic_id}\",\"body\":\"{body}\",\"widget\":\"{widget\"}";
client.CreateTopicSubscription("widgets", httpSubscription);
From now on, any messages published to our topic widgets
will publish into
the previously created widget_queue
queue, and an HTTP POST request will
also be sent to the URL we've specified in the HTTP subscription. If we include
a field in each message with the key "widget", its value will also be
substituted within the HTTP notification body.
Publishing to a topic is nearly identical as publishing to a lone queue:
// Simplest form:
client.PublishToTopic(widgetsTopic, new Message("Hello, universe!"));
// Alternatively:
Message myMessage = new Message("Hello, universe!");
client.PublishToTopic("widgets", myMessage);
Messages submitted through queues and topics can be consumed by periodically polling a queue for messages.
Assuming we've created a method called processMessage
, which accepts a Message
object as its only argument and returns a boolean value indicating whether or
not the message was successfully processed, the main message polling loop might
look like the following:
string queueName = "widget_queue";
int sleepTimeMsec = 2000; // 2 seconds
while (true) {
Message message = client.PopMessage(queueName);
if (message != null) {
if (processMessage(message)) {
client.DeleteMessage(queueName, message.ID);
}
}
System.Threading.Thread.Sleep(sleepTimeMsec);
}
The above ensures messages would only be deleted after being successfully processed; you can tune your visibility intervals over time to ensure another worker doesn't pick up the same message within the average amount of time it takes to process a single message.
Messages can also be popped in groups by calling the
MessagingClient::PopMessages
method (plural) instead, which will always return
a List, even if empty.
string queueName = "widget_queue";
int maxPopCount = 5;
while (true) {
List<Message> messages = client.PopMessages(queueName, maxPopCount);
foreach (Message message in messages) {
if (processMessage(message)) {
client.DeleteMessage(queueName, message.ID);
}
}
}
If you use queues and topics in more of a time-based manner you may wish to
often delete them. This is accomplished with DeleteQueue
and DeleteTopic
:
client.DeleteQueue(widgetsQueue); // providing a Queue object is allowed
client.DeleteQueue("myqueue");
client.DeleteTopic(widgetsTopic); // providing a Topic object is allowed
client.DeleteTopic("mytopic");
Subscriptions can also be deleted individually using DeleteTopicSubscription
.
Queues cannot be deleted unless you have consumed or deleted all messages from
them; to force the deletion of the queue and all its messages, you can
optionally pass a true boolean value as the third argument to DeleteQueue
.
Topics follow the same rule--if subscriptions are attached to a topic and you
wish to delete the topic without having to iterate through and delete each
subscription individually, you can pass in a true boolean value to DeleteTopic
as an optional second argument.
For additional guidance and information, check out the Message Queue API reference or the SoftLayer Developer Network forum.
For specific issues with the C# client library, get in touch with us via the SoftLayer Developer Network forum or the Issues page on our GitHub repository.
Copyright (c) 2012 SoftLayer Technologies, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.