Azure service bus - how to add metadata to the message - azure

I am using .net core web app as the publisher and .net core console app as subscriber.
I am able to successfully pass messages between these two systems using Managed Identities - set up in Azure portal.
My question is I need to add metadata to the the message that is being sent. How do I do that ?
Below is my publisher code :
string data = JsonConvert.SerializeObject(payloadEvents);
Message message = new Message(Encoding.UTF8.GetBytes(data));
var tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider();
TopicClient sendClient = new TopicClient(_serviceBusNamespace, _topicName, tokenProvider, retryPolicy: null);
await sendClient.SendAsync(message);

Message object has a property called UserProperties that can be used to set custom metadata for that message.
Something like:
string data = JsonConvert.SerializeObject(payloadEvents);
Message message = new Message(Encoding.UTF8.GetBytes(data));
message.UserProperties.Add("key1", "value1");
message.UserProperties.Add("key2", "value2");
var tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider();
TopicClient sendClient = new TopicClient(_serviceBusNamespace, _topicName, tokenProvider, retryPolicy: null);
await sendClient.SendAsync(message);

Related

Azure service bus - not seeing messages

I created a simple Azure Service bus (Queue) and a client that is sending message to service bus. Using below code to send message:
using Microsoft.Azure.ServiceBus;
using Microsoft.Extensions.Configuration;
public async Task SendMessageAsync<T>(T message, string queueName)
{
try
{
var queueClient = new QueueClient(_config.GetConnectionString("AzureServiceBus"), queueName);
string messageBody = JsonSerializer.Serialize(message);
var byteMessage = new Message(Encoding.UTF8.GetBytes(messageBody));
queueClient.SendAsync(byteMessage);
Console.WriteLine((message as Employee).FirstName);
}
catch (Exception ex)
{
var c = ex;
}
}
Sending message using:
using SenderApp;
Console.WriteLine("Hello, World!");
QueueService service = new QueueService();
for (int i = 0; i < 100; i++)
{
Employee e = new Employee();
e.FirstName = "1 " + i.ToString();
e.LastName = "2 " + i.ToString();
service.SendMessageAsync<Employee>(e, "employeequeue");
}
When I try to see active messages, There is nothing in the queue:
However I do see some traffic. But the number of message I sent (over 100) is not equal to number of incoming request show (62) at the bottom of the image. I am not sure what is happening to my messages? This defeats the purpose of the queue.
Please guide me why I am not seeing any messages. What is the best way to handle this ?
I am using following nuget packages:
<PackageReference Include="Microsoft.Azure.ServiceBus" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
A message sent to an Azure Service Bus queue will be delivered to the queue unless operation is failing. In that case, an exception will be thrown. Check the following:
Exception handling doesn't swollow exceptions
Await asynchronous send operations to ensure messages are dispatched
Namespace/queue used for sending is what you use to receive
There are no competing consumers, actively receiving messages from the queue.
Validate TCP ports needed for AMQP are not blocked. If those ports are blocked, you could configure your client to use WebSockets.
So I still dont know what caused this issue. But I realized Microsoft.Azure.ServiceBus package was deprecated and later I started using Azure.Messaging.ServiceBus package to connect to service bus and things started to work.
I used following code to send message to queue:
string connectionString = "Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=f3f+qMYTyVwE18YNl5J6ygJFi30v6J/Smph5HZvyQyE=";
string queueName = "employeequeue";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);
// create the sender
ServiceBusSender sender = client.CreateSender(queueName);
// create a message that we can send. UTF-8 encoding is used when providing a string.
ServiceBusMessage message = new ServiceBusMessage("Hello world! " + id);
// send the message
await sender.SendMessageAsync(message);
return "Sent";
Used following code to receive message:
string queueName = "employeequeue";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);
// create a receiver that we can use to receive and settle the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);
// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();
string body = receivedMessage.Body.ToString();
// complete the message, thereby deleting it from the service
await receiver.CompleteMessageAsync(receivedMessage);
More info is available # https://github.com/Azure/azure-sdk-for-net/blob/Azure.Messaging.ServiceBus_7.7.0/sdk/servicebus/Azure.Messaging.ServiceBus/README.md

Microsoft.Azure.ServiceBus.MessagingEntityDisabledException: ReceiveDisabled

I have changed the Azure Service Bus Queue status from Active to ReceiveDisabled. Because I don’t want to process whenever message available in the queue. i.e. reason I have changed status to ReceiveDisabled.
After I changed the queue status to ReceiveDisabled, then I’m not able to post any message to that queue because I’m getting the below error.
Microsoft.Azure.ServiceBus.MessagingEntityDisabledException: Messaging entity 'sb://xxx-xxx-xxx.servicebus.windows.net/test-queue' is currently disabled
.Net Core code to change the queue status:
var serviceBusManagementClient = new ManagementClient(_serviceBusSettings.Connection);
foreach (var queueItem in queueItems)
{
var queueDescription = await serviceBusManagementClient.GetQueueAsync(queueItem.Value);
queueDescription.Status = EntityStatus.ReceiveDisabled;
await serviceBusManagementClient.UpdateQueueAsync(queueDescription);
}
.Net Core code to post messages to queue.
var messageSender = new MessageSender(serviceBusSettings.Connection, serviceBusSettings.MainQueueName);
var message = new Message(Encoding.UTF8.GetBytes(id))
{
//Assign a SessionId for the message
MessageId = id
};
// Send a message corresponding to this sessionId to the queue
messageSender.SendAsync(message);
I’m using the below references.
Microsoft.Azure.ServiceBus
Microsoft.Azure.ServiceBus.Management
Reference documentation https://learn.microsoft.com/en-us/azure/service-bus-messaging/entity-suspend
So, how can I post messages to Queue which is having ReceiveDisabled status?

How to send writable property data in Azure IoT Central

I'm developing small IoT app using IoT Central. below is my device DCM
I'm sending telemetry & property data using .Net simulator, but I cannot see TelemetryInterval property data in Azure IoT Central. (Telemetry data visible properly)
Simulator Code
var telemetryDataPoint = new
{
MessageTime = messageTime,
Moisture = randMoisture
};
var telemetryDataString = JsonConvert.SerializeObject(telemetryDataPoint);
//set the body of the message to the serialized value of the telemetry data
var message = new Message(Encoding.ASCII.GetBytes(telemetryDataString));
message.Properties.Add("TelemetryInterval", "10");
message.ContentEncoding = "utf-8";
message.ContentType = "application/json";
message.MessageId = Guid.NewGuid().ToString();
await deviceClient.SendEventAsync(message);
I'm able to fix this.
This is reported property of device twin, We can use TwinCollection to update this property.
private static async void SendTwinData()
{
var twinProperties = new Microsoft.Azure.Devices.Shared.TwinCollection();
twinProperties["TelemetryInterval"] = "2";
await s_deviceClient.UpdateReportedPropertiesAsync(twinProperties);
}

Sending message to a specific group of subscriber in azure service bus topic with masstransit

I'm new to azure service bus and masstransit. I'm looking for a solution to a specific situation.
I have a azure service bus topic with multiple subscribers. Subscriber will receive message based on filters. I've created the topic and subscriber with code below
class Program
{
static void Main(string[] args)
{
string connectionString = "Endpoint connection string";
// the names of topics and subscriptions we'll be working with
const string topicName = "MyTestTopic";
const string allMessagesSubName = "AllMessages";
const string filteredSubName1 = "Filtered1";
const string filteredSubName2 = "Filtered2";
// let's create the topic if it doesn't already exist...
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.TopicExists(topicName))
{
var td = new TopicDescription(topicName);
namespaceManager.CreateTopic(td.Path);
}
if (!namespaceManager.SubscriptionExists(topicName, allMessagesSubName))
{
namespaceManager.CreateSubscription(topicName, allMessagesSubName);
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName1))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName1),
new Microsoft.ServiceBus.Messaging.SqlFilter("From LIKE '%Smith'"));
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName2))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName2),
new Microsoft.ServiceBus.Messaging.SqlFilter("sys.Label='important'"));
}
var message1 = new BrokeredMessage("Hello World");
var message2 = new BrokeredMessage("Second message");
message2.Label = "important";
var message3 = new BrokeredMessage("Third message");
message3.Properties["From"] = "Kelly Smith";
message3.Label = "information";
var client = TopicClient.CreateFromConnectionString(connectionString, topicName);
client.Send(message1);
client.Send(message2);
client.Send(message3);
client.Close();
}
}
Here in the code we're adding Message custom properties like From.
Now I want to send such message using masstransit. In masstransit I cannot find any option of adding Message custom properties using the Publish() method. Is there any way that I can send these messages using masstransit where these filters can be used?
NB: I've read the answer of this question But the anwer here tells us to filter the messages in subscriber side. What I want is that this filtering will occur before reaching the subscriber.
When using Azure Service Bus with MassTransit, you can add subscription endpoints in additional to regular endpoints. When configuring a subscription endpoint, you should be able to specify rules and/or filters as part of the subscription. Which is exactly what you're doing above, so that is handled.
The other part, adding properties to the message, can be done by adding text headers to the SendContext. Those headers are copied to the message Properties collection, which I believe can be used to filter messages using a "SQL" filter (which is configured on the subscription endpoint, or the topic subscription on a receive endpoint).

Azure service bus - Read messages sent by .NET Core 2 with BrokeredMessage.GetBody

I am using .NET Core 2 for an application which needs to put a message on the Service bus and read by a legacy .NET 4.6 receiver. The receiver listens to messages from other legacy applications as well.
Legacy sender:
UserData obj = new UserData()
{
id = 1,
name = "Alisha"
};
BrokeredMessage message = new BrokeredMessage(consentInstated);
_client.Send(message);
Legacy Receiver:
var dataObj = objBrokeredMessage.GetBody<UserData>();
businessFunc(dataObj.id, dataObj.name);
.NET Core 2 sender: as described in https://stackoverflow.com/a/45069423/1773900
var ser = new System.Runtime.Serialization.DataContractSerializer(typeof(UserData));
var ms = new MemoryStream();
ser.WriteObject(ms, objUserData);
var message = new Message(ms.ToArray());
_client.Send(message);
However, the reciever fails to deserialize the message and throws the following error
System.Runtime.Serialization.SerializationException: There was an
error deserializing the object of type UserData. The input source is
not correctly formatted. ---> System.Xml.XmlException: The input
source is not correctly formatted.
What can I do to make both senders work with the same receiver?
BrokeredMessage is using XML Binary Reader to deserialize the messages. So your sending part should look like this:
var ser = new DataContractSerializer(typeof(UserData));
var ms = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ms);
ser.WriteObject(binaryDictionaryWriter, obj);
binaryDictionaryWriter.Flush();
var message = new Message(ms.ToArray());
We could send serialize json Object string directly from .net core side, and we could get the message with following code in the .net side. It works correctly on my side.
var dataObj = message.GetBody<UserData>(new DataContractJsonSerializer(typeof(UserData)));
.net core side send message code:
var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(objUserData));
_client.SendAsync(new Message{Body = body,ContentType = "text/plain"}).Wait();
.net side receive message code:
var dataObj = message.GetBody<UserData>(new DataContractJsonSerializer(typeof(UserData)));
I also encountered the same problem, but neither solution worked. For me below code works
// model is the object that you want to sent to Topic
Model model = new Model();
var serializator = new DataContractSerializer(typeof(string));
var json = JsonConvert.SerializeObject(model);
var memoryStream = new MemoryStream();
XmlDictionaryWriter binaryDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memoryStream);
serializator.WriteObject(binaryDictionaryWriter, json);
binaryDictionaryWriter.Flush();
// below message can be sent to Topic via .NET Core and will be properly deserialized in .NET Framework subscriber
var message = new Message(memoryStream.ToArray());
var client = new TopicClient(_endpoint, _channelName );
await client.SendAsync(message);

Resources