Filtered Subscriptions with Azure Service Bus Topics

Download Complete Project: AzureTopicSubscriptionfilters

Azure Service Bus topics allow multiple subscribers to receive the same messages. So if we post an message to a topic, then one subscriber might send an order confirmation email, while another subscriber to the same event might handle payments.

The way this is done is that you create multiple “subscriptions” on the topic, and then you can listen for messages on those subscriptions, in the same way that you would listen for messages on a regular queue.

But what if your subscription is only interested in a subset of messages that are posted to that topic? Well, this is where filters come in. When we create a subscription, we can specify the properties of the messages we are interested in.

What is Rule Filter

As the filter’s type implies, it allows for defining a SQL92 standard expression in its constructor that will govern what messages are filtered out.

There are following types of filters :

  1.  SQLFilter – The filter that a number of other filters derive from such TrueFilter and FalseFilter
  2. TrueFilter – This is the default filter provided through the default rule that is generated for us when a rule or filter is not explicitly provided when creating a subscription.  Ultimately, this generates the SQL92 expression 1=1 and subscribes to receive all messages of the associated topic.
  3. FalseFilter – The antithesis of a TrueFilter that generates a SQL92 expression of 1=0; a subscription with this filter will never subscript to any messages of the associated topic.
  4. CorrelationFilter – This filter subscribes the subscription to all messages of a particular CorrelationId property of the message.
    Note:Be aware that the comparison values in your SQL expression are case-sensitive, while the property names are not (e.g. “Zone= ‘East’” is not the same as “zone= ‘east’”)

In earlier post we have seen how default rules works and how same message broadcast to all subscriptions. Now we will see how custom rules works and how specific message subscribe by the subscriber with custom filtering rules.

Example:

Let’s consider order processing system where some orders need to publish to topics and some region wise subscriptions are also setup in the topic.Instead of broadcast all orders to all subscriptions,only region wise orders will broadcast to specific subscriptions.

In our case orders belongs to two regions (East and North) and two subscriptions are setup to subscribe these messages,i.e East Subscription only receives east region orders and north subscription receives north region orders.

T18

Adding rules to the subscriptions:

Subscriptions are not limited to one rule however. We can add additional rules to an existing subscription.


public static void CreateTopicUnderServiceBus()
{
var TopicName = "OrderTopic";
string[] arrSubsription = new string[] { "NorthSubscription", "EastSubscription" };

//Create Topic
if (!nameSpaceManager.TopicExists(TopicName))
{
nameSpaceManager.CreateTopic(TopicName);
}

//CreateSubscription
foreach (string subsription in arrSubsription)
{
if (!nameSpaceManager.SubscriptionExists(TopicName, subsription))
{
SubscriptionDescription subscriptionDesc = new SubscriptionDescription(TopicName, subsription)
{
EnableDeadLetteringOnMessageExpiration = true,
EnableDeadLetteringOnFilterEvaluationExceptions = true,
DefaultMessageTimeToLive = TimeSpan.FromMinutes(5),
LockDuration = TimeSpan.FromSeconds(60),
};
var zone = subsription.Replace("Subscription", "");

// Rule for EastSubsrciption to recieve those message that belongs to specific zones.
RuleDescription ruleDescForSubscriptions = new RuleDescription("ZoneFilter", new SqlFilter("Zone='" + zone + "'"));

nameSpaceManager.CreateSubscription(subscriptionDesc,ruleDescForSubscriptions);
var ss = SubscriptionClient.FormatDeadLetterPath(TopicName, subsription);
}
}

}

Here RuleDescription class is used to create a filter rules. Above code will add two filter rules  in  subscriptions which are  “Zone=’East’ and “Zone=’North'”.

An additional properties also need to send with broker message along with creating filter rules.


public static void PublishOrder(TopicClient topicClient, Order order)
{
String Displaytext = string.Format("Order : orderId={0},customerName={1},ProductName={2},DeliveryAddress={3},Zone={4} " +
" Sent To Topic Successfully \n\n",
order.OrderId, order.CustomerName, order.ProductName, order.DeliveryAddress, order.Zone);

//Create broker message for order
BrokeredMessage brokerMessage = new BrokeredMessage(order);
brokerMessage.Properties.Add("Zone", order.Zone);
topicClient.Send(brokerMessage);
Console.Write(Displaytext);

}

See the “Zone” property set in broker message.

Complete Code For Message Publisher:


using Common;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using System;
using System.Threading;

namespace MessageSender
{
class Publisher
{
static NamespaceManager nameSpaceManager;

static void Main()
{
nameSpaceManager = NamespaceManager.CreateFromConnectionString(TopicConfigurations.Namespace);
CreateTopicUnderServiceBus();

TopicClient tClient = TopicClient.CreateFromConnectionString(TopicConfigurations.Namespace, "OrderTopic");

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("======================================================");
Console.WriteLine("-----------Publishing Start---------------------------");
Console.WriteLine("======================================================");

Console.ForegroundColor = ConsoleColor.Green;
PublishOrder(tClient, new Order()
{
OrderId = 5656,
CustomerName = "Vivek Jadon",
ProductName = "Iphone6",
DeliveryAddress = "MG Road Gurgaon",
Zone = "East"
});
PublishOrder(tClient, new Order()
{
OrderId = 5657,
CustomerName = "Rakesh ",
ProductName = "Samsung S8",
DeliveryAddress = "12/3 Ring Road Delhi",
Zone = "East",
});
PublishOrder(tClient, new Order()
{
OrderId = 5658,
CustomerName = "Prakash Nayal",
ProductName = "OnePlus 5T",
DeliveryAddress = "12/3 Ring Road Delhi",
Zone = "North",
});
PublishOrder(tClient, new Order()
{
OrderId = 5659,
CustomerName = "Gautom Anand",
ProductName = "Samsung S8",
DeliveryAddress = "12/3 Ring Road Delhi",
Zone = "North",
});

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("-----------Publishing End---------------------------");
Console.ReadLine();
}

public static void CreateTopicUnderServiceBus()
{
var TopicName = "OrderTopic";
string[] arrSubsription = new string[] { "NorthSubscription", "EastSubscription" };

//Create Topic
if (!nameSpaceManager.TopicExists(TopicName))
{
nameSpaceManager.CreateTopic(TopicName);
}

//CreateSubscription
foreach (string subsription in arrSubsription)
{
if (!nameSpaceManager.SubscriptionExists(TopicName, subsription))
{
SubscriptionDescription subscriptionDesc = new SubscriptionDescription(TopicName, subsription)
{
EnableDeadLetteringOnMessageExpiration = true,
EnableDeadLetteringOnFilterEvaluationExceptions = true,
DefaultMessageTimeToLive = TimeSpan.FromMinutes(5),
LockDuration = TimeSpan.FromSeconds(60),
};
var zone = subsription.Replace("Subscription", "");

// Rule for EastSubsrciption to recieve those message that belongs to specific zones.
RuleDescription ruleDescForSubscriptions = new RuleDescription("ZoneFilter", new SqlFilter("Zone='" + zone + "'"));

nameSpaceManager.CreateSubscription(subscriptionDesc,ruleDescForSubscriptions);
var ss = SubscriptionClient.FormatDeadLetterPath(TopicName, subsription);
}
}

}
public static void PublishOrder(TopicClient topicClient, Order order)
{
String Displaytext = string.Format("Order : orderId={0},customerName={1},ProductName={2},DeliveryAddress={3},Zone={4} " +
" Sent To Topic Successfully \n\n",
order.OrderId, order.CustomerName, order.ProductName, order.DeliveryAddress, order.Zone);

//Create broker message for order
BrokeredMessage brokerMessage = new BrokeredMessage(order);
brokerMessage.Properties.Add("Zone", order.Zone);
topicClient.Send(brokerMessage);
Console.Write(Displaytext);

}
}
}

Complete code for message receiver:


using Common;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using System;

namespace MessageReciever
{
class Subscriber
{
static NamespaceManager nameSpaceManager;

static void Main()
{
nameSpaceManager = NamespaceManager.CreateFromConnectionString(TopicConfigurations.Namespace);
ReadMessageFromSubscription("OrderTopic");
Console.ReadLine();
}

public static void ReadMessageFromSubscription(string TopicName)
{

foreach (SubscriptionDescription description in nameSpaceManager.GetSubscriptions(TopicName))
{
SubscriptionClient sClient = SubscriptionClient.CreateFromConnectionString(TopicConfigurations.Namespace,"OrderTopic", description.Name);

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("=======================================");
Console.WriteLine("---Order Recieving From [" + description.Name + "]---");
Console.WriteLine("=======================================");
while (true)
{
BrokeredMessage bmessgage = sClient.Receive(TimeSpan.FromSeconds(2));

if (bmessgage != null)
{
Order order = bmessgage.GetBody<Order>();
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(" Request Recieved, ProductName: {0},Zone : {1},CustomerName: {2},DeliveryAddress: {3} \n\n",
order.ProductName, order.Zone, order.CustomerName, order.DeliveryAddress);

Console.ForegroundColor = ConsoleColor.Yellow;

bmessgage.Complete();
}
else
{
break;
}
}
sClient.Close();
}

}
}
}

Once the messages are sent to Topic, the subscriber should start showing the appropriate message count. In our case if we send a message with East and North as Zone, as per the rules set, EastSubscriber should receive only 2 message which is East region messages and Northsubscriber should receive also 2 messages as north region has 2  messages.

Let’s run complete application and then talk about the output.

Here we can see there are 4 orders publish to order topic,there are 2 orders that belongs to East region and 2 orders for North reagion.Important thing that this time all 4 messages has not broadcast to both subscriptions because we have created 2 filters rule for both regions.

t19

Take a look on azure portal , here we can see each subscriptions received 2 messages according to their filter rule.

t20.jpg

Now see topic & subscription details with azure service bus explorer.We can see custom filters with name “ZoneFilter” has created in both subscripiton with filter rule.

t21.jpg

Of course, you can get away without using filters at all, if you just set up plain subscriptions and only respond to messages of interest in your handlers. But using the filters will reduce network traffic and save unnecessary work processing messages that aren’t of interest.

Read more about service bus explorer :Link

Leave a comment