I want to use Azure Service Bus from inside an .NET Core 2.1 application. I'm familiar with the SDK coming with the Nuget package Microsoft.Azure.ServiceBus
and using this I'm currently writing to a topic and receiving messages from there.
What I want now is to create subscriptions on this topic for every client. The point is that I want to create a filtered subscription using the SqlFilter
. This means, I have to create the subscription by code.
BTW: As far as I've seen it the only other way then doing it in code is using ARM template for the deployment because the portal will not allow me to create a filtered subscription.
I understood, that Microsoft.Azure.ServiceBus
is not able to create ressources and so I went to the Nuget package Microsoft.Azure.Management.ServiceBus
. So I now can create a new subscription from code now like this:
private static async Task CreateSubscriptionAsync()
{
var context = new AuthenticationContext($"https://login.microsoftonline.com/{Configuration["AppSettings:AzureManagement:TenantId"]}");
var token = await context.AcquireTokenAsync(
"https://management.core.windows.net/",
new ClientCredential(Configuration["AppSettings:AzureManagement:ClientId"], Configuration["AppSettings:AzureManagement:ClientSecret"]));
var creds = new TokenCredentials(token.AccessToken);
using (var sbClient = new ServiceBusManagementClient(creds)
{
SubscriptionId = VariableHelper.Configuration["AppSettings:AzureManagement:AzureSubscriptionId"]
})
{
var queueParams = new SBSubscription
{
LockDuration = TimeSpan.FromSeconds(10)
};
await sbClient.Subscriptions.CreateOrUpdateAsync(
Configuration["AppSettings:ServiceBus:ResourceGroup"],
Configuration["AppSettings:ServiceBus:Namespace"],
Configuration["AppSettings:ServiceBus:TopicName"],
"mysub",
queueParams);
}
}
This works so I have a new subscription which I'm also able to delete. But now where can I define the filter? The SBSubscription
-type contains no option to define a filter and there is no method-overload in sbClient.Subscriptions.CreateOrUpdateAsync
.
The only way I found to do this in code is based on the old Nuget WindowsAzure.ServiceBus
which is not available for .NET Core. So there I would use a NamespaceManager
like this:
var manager = NamespaceManager.CreateFromConnectionString("MyConnectionString");
var rule = new RuleDescription("property > 4");
var sub = manager.CreateSubscriptionAsync(new SubscriptionDescription("mytopic", "mysub"), rule);
Without this feature the complete topic-thing seems to be very useless to me and I can't believe that this means that Azure Service Bus is simply not ready for .NET Core.
Edit: Solution as suggested by Arunprabhu
I just wanted to present the solution in complete.
Microsoft.Azure.Management.ServiceBus
.Microsoft.Azure.ServiceBus
.private static async Task CreateSubscriptionAsync()
{
// this is to show that it works with any subscription-name
var subName = Guid.NewGuid().ToString("N");
// create the subscription using Azure Management API
var context = new AuthenticationContext($"https://login.microsoftonline.com/{Configuration["AppSettings:AzureManagement:TenantId"]}");
var token = await context.AcquireTokenAsync(
"https://management.core.windows.net/",
new ClientCredential(Configuration["AppSettings:AzureManagement:ClientId"], Configuration["AppSettings:AzureManagement:ClientSecret"]));
var creds = new TokenCredentials(token.AccessToken);
using (var sbClient = new ServiceBusManagementClient(creds)
{
SubscriptionId = VariableHelper.Configuration["AppSettings:AzureManagement:AzureSubscriptionId"]
})
{
var queueParams = new SBSubscription
{
LockDuration = TimeSpan.FromSeconds(10)
};
await sbClient.Subscriptions.CreateOrUpdateAsync(
Configuration["AppSettings:ServiceBus:ResourceGroup"],
Configuration["AppSettings:ServiceBus:Namespace"],
Configuration["AppSettings:ServiceBus:TopicName"],
subName,
queueParams);
}
// add filter-rule using Azure ServiceBus API
var client = new SubscriptionClient(ServiceBusConnectionString, Configuration["AppSettings:ServiceBus:TopicName"], subName);
await client.AddRuleAsync("default", new SqlFilter("1=1"));
// That's it
}
I understood, that Microsoft.Azure.ServiceBus is not able to create ressources
As of version 3.1.0-preview of Microsoft.Azure.ServiceBus you can create entities using ManagementClient
without the need in the Microsoft.Azure.Management.ServiceBus library. It has an overload of CreateSubscriptionAsync()
that takes in RuleDescription
to be created as the default rule. Alternatively, providing no RuleDescription
will set up a default rule for you automatically.
There are similar methods available for rules management under SubscriptionClient in Microsoft.Azure.ServiceBus. Look here for samples.
Expounding on Sean Feldman's answer since his example link is now broken, you can do something like this:
public static async Task CreateSubscription(
string connection,
string topicPath,
string subscriptionName,
string matchExpression,
string ruleDescription,
bool checkForExisting = false,
CancellationToken cancellationToken = default(CancellationToken)
)
{
if (checkForExisting)
{
var exists = (await new ManagementClient(connection)
.GetSubscriptionsAsync(topicPath, cancellationToken: cancellationToken))
.Any(sub => sub.SubscriptionName == subscriptionName);
if (exists) return;
}
var subscriptionDescription = new SubscriptionDescription(topicPath, subscriptionName);
var rule = new RuleDescription(ruleDescription, new SqlFilter(matchExpression));
await new ManagementClient(connection).CreateSubscriptionAsync(subscriptionDescription, rule, cancellationToken);
}
For simplicity I've removed the obligatory input validations like empty strings or non-valid characters. I've also included a way to check whether the subscription already exists. Ideally you'd only perform that check once, then keep a running tab in memory so you're not performing that API call each time.
For your matchExpression
you'd define the filter for that subscription in SQLish syntax, based on user properties that were added to the message when it was published.
The implementation would look something like:
await CreateSubscription(
Configuration.GetConnectionString("MyServiceBusConnectionString"),
"myTopicName",
"mySubscription",
"MyUserProperty='MyValue'",
"MyRule",
true
)
You can create filters with the Microsoft.Azure.Management.ServiceBus
package, they're part of Rules.
await client.Rules.CreateOrUpdateAsync(resourceGroupName, namespaceName,
topicName, subscriptionName, filterName, new Rule {
SqlFilter = new SqlFilter(sql)
});
You see the filter name and SQL string in the screenshot below from the Azure Portal:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With