How to set the first message as unread for the receiver? - c#

I have a conversation with two participants:
var createdConversation = await ConversationResource.CreateAsync(uniqueName: uniqueName);
var sender = await ParticipantResource.CreateAsync(pathConversationSid: createdConversation.Sid, identity: "sender");
var receiver = await ParticipantResource.CreateAsync(pathConversationSid: createdConversation.Sid, identity: "receiver");
And I want to send a initial message in this newly created conversation:
var message = await MessageResource.CreateAsync(
pathConversationSid: createdConversation.Sid,
author: sender.Identity,
body: intitialMessage);
After that, I want this new message to be read for the sender and unread for receiver which seems not possible.
I can set the lastReadMessageIndex of the sender to the created message.Index but this won't create read horizon for the receiver. And as long as the lastReadMessageIndex of the receiver is null, the unreadMessagesCount will be also null, and it will look like the receiver has no new messages in this conversation.
Any suggestions on how I can create a new conversation with initial message, which will be displayed as unread for one of the users?

Currently it is not possible to do this. This has been raised internally at Twilio as a feature gap.
In the meantime you may need to workaround it. One thing I thought of would be to mark any conversations that have a lastReadMessageIndex of null as unread in your UI.

As there is no "easy way" to achieve this, I am loading the conversation and its messages to calculate the unreadMessagesCount.
var conversation = await UserConversationResource.FetchAsync(
pathUserSid: userSid,
pathConversationSid: conversationSid);
var conversationHasNoReadHorizon = conversation.UnreadMessagesCount == null;
if (conversationHasNoReadHorizon)
{
var messages = await MessageResource.ReadAsync(pathConversationSid: conversationSid);
return messages.Count(message => message.Author != callerId);
}
else
{
return conversation.UnreadMessagesCount ?? 0;
}

Related

Azure Service Bus Receive Messages continuously when ever new message placed in web application [duplicate]

I am using Azure.Messaging.ServiceBus nuget package to work with Azure service bus. We have created a topic and a subscription. The subscription has 100+ messages. We want to read all the message and continue to read message as they arrive.
Microsoft.Azure.ServiceBus package (deprecated now) provided RegisterMessageHandler which use to process every incoming message. I am not able to find similar option under Azure.Messaging.ServiceBus nuget package.
I am able to read one message at a time but I have to call await receiver.ReceiveMessageAsync(); every time manually.
To receive multiple messages (a batch), you should use ServiceBusReceiver.ReceiveMessagesAsync() (not plural, not singular 'message'). This method will return whatever number of messages it can send back. To ensure you retrieve all 100+ messages, you'll need to loop until no messages are available.
If you'd like to use a processor, that's also available in the new SDK. See my answer to a similar question here.
As suggested by #gaurav Mantri, I used ServiceBusProcessor class to implement event based model for processing messages
public async Task ReceiveAll()
{
string connectionString = "Endpoint=sb://sb-test-today.servicebus.windows.net/;SharedAccessKeyName=manage;SharedAccessKey=8e+6SWp3skB3Aedsadsadasdwz5DU=;";
string topicName = "topicone";
string subscriptionName = "subone";
await using var client = new ServiceBusClient(connectionString, new ServiceBusClientOptions
{
TransportType = ServiceBusTransportType.AmqpWebSockets
});
var options = new ServiceBusProcessorOptions
{
// By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
// Set AutoCompleteMessages to false to [settle messages](https://learn.microsoft.com/en-us/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
// In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
AutoCompleteMessages = false,
// I can also allow for multi-threading
MaxConcurrentCalls = 1
};
await using ServiceBusProcessor processor = client.CreateProcessor(topicName, subscriptionName, options);
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;
await processor.StartProcessingAsync();
Console.ReadKey();
}
public async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
Console.WriteLine(body);
// we can evaluate application logic and use that to determine how to settle the message.
await args.CompleteMessageAsync(args.Message);
}
public Task ErrorHandler(ProcessErrorEventArgs args)
{
// the error source tells me at what point in the processing an error occurred
Console.WriteLine(args.ErrorSource);
// the fully qualified namespace is available
Console.WriteLine(args.FullyQualifiedNamespace);
// as well as the entity path
Console.WriteLine(args.EntityPath);
Console.WriteLine(args.Exception.ToString());
return Task.CompletedTask;
}

Filter Duplicate Messages IoT Device

I am working on a console application program that receives messages from an Azure IoT Device and is using a timer to receive the messages every two seconds. Upon receiving a message the device sends out a call to complete it. The issue that I am experiencing is that the message does not complete in Azure before the device receives it again, which results in the message getting reprocessed. I have tried to filter incoming messages when it is the same message coming in multiple times, but the messages are coming in with the same message id whether or not they are duplicate messages or new messages. I do not have access to control the incoming message's message id field and make it unique, but that would solve the problem. The sequence number is unique for every message that comes in whether it is duplicate or not so I cannot use that as a filter either. Is there a way to filter a message to see if it is a duplicate without the message id field?
//Within Program.cs > Main():
_timer = new Timer(Operations, null, 0, _timerInterval); //_timerInterval is set to 2000
//Within Initialize class used to setup device client:
//Fully qualified namespace for DeviceClient:
//Microsoft.Azure.Devices.Client.DeviceClient
string connectionString = "code removed for example";
var deviceClient = DeviceClient.CreateFromConnectionString(connectionString);
//Within Operations class:
var message = await deviceClient.ReceiveAsync();
if (message != null && !string.IsNullOrEmpty(message?.MessageId))
{
//Filtering message based on MessageId
if (_memoryCache.Get(message.MessageId) == null)
{
_memoryCache.Set(message.MessageId, message.MessageId, DateTimeOffset.UtcNow.AddMinutes(10));
await deviceClient.CompleteAsync(message);
//Processing message
await ProcessMessage(message);
}
else
{
await deviceClient.RejectAsync(message);
}
}
You can use Microsoft.Azure.Devices.Client.Message package to retrieve the Device client message values.
Use the IOT explicit unique id in message to check the duplicates while receiving.
Follow the below code to check the duplicate value
List<string> FinalResponse = new List<string>();
Microsoft.Azure.Devices.Client.Message Response = await deviceClient.ReceiveAsync(TimeSpan.FromSeconds(10));
if (Response == null)
{
await Task.Delay(10).ConfigureAwait(false);
continue;
}
//here you can use the explicit properties like message id or correlation Id
Trace.WriteLine(Response.MessageId.ToString());
await this.deviceClient.CompleteAsync(Response);
var content = Encoding.UTF8.GetString(Response.GetBytes());
FinalResponse.Add(content);
Either you can use above one or use below conditions
Create a List and ADD all values to the list which get from Device
Add condition to ignore If any duplicates occur while insert into list.
Then send unduplicated values to Azure.

Using MessageReceiver only first time getting message from topic using Azure Function HttpTrigger

Using MessageReceiver only first time getting messages from topic using Azure Function after that next time when execute Function though I have messages into service bus topic still getting null into variable messages.
Using below code to get messages from Service Bus Topic , whats the cause?
string serviceBusConnectionString = Environment.GetEnvironmentVariable("ConnectionString");
var messageReceiver = new MessageReceiver(serviceBusConnectionString, Environment.GetEnvironmentVariable("topicName/subscriptions/subscriptionName"), ReceiveMode.PeekLock, null, 500);
var messages = await messageReceiver.ReceiveAsync(500, TimeSpan.FromSeconds(1));
i can't understand this - after every 15 minutes when LA call FA then
FA should able to read new available messages but it is coming null
is there anything related with lock duration ?
var messages = await messageReceiver.ReceiveAsync(500, TimeSpan.FromSeconds(1));
will wait until it receives one or more messages and will then return. Any messages that come in later will not be read. If you want to do that (and I want to doubt that this is a good idea inside an Azure Function), put this in a loop:
while(/* some condition */)
{
messages = await messageReceiver.ReceiveAsync(500, TimeSpan.FromSeconds(1));
// do something with the received messages
}
If i didn't understand it wrong, you use a timer trigger logic app to call the function to get the service bus message and you always get the old message and you don't want it.
You always get the old message because your ReceiveMode is PeekLock, about this ReceiveMode you could check this description:Receive mode. After complete the message, the message wouldn't be deleted, that's why you always get the old message.
First way is you could change it to ReceiveAndDelete when you create MessageReceiver like the below code.
string serviceBusConnectionString = Environment.GetEnvironmentVariable("servicebuscon");
var messageReceiver = new MessageReceiver(serviceBusConnectionString, "myqueue", ReceiveMode.ReceiveAndDelete, null, 500);
var tempMessages = await messageReceiver.ReceiveAsync(500, TimeSpan.FromSeconds(1));
Note: if your function go exception or other errors and the message doesn't get processed completely, this message will be deleted with this mode.
The other way is after process the message call the CompleteAsync method, after process the message will be deleted.
You could refer to the below code.
var messageReceiver = new MessageReceiver(serviceBusConnectionString, "myqueue", ReceiveMode.PeekLock, null, 500);
var tempMessages = await messageReceiver.ReceiveAsync(500, TimeSpan.FromSeconds(1));
foreach (Message m1 in tempMessages)
{
log.LogInformation($"C# HTTP trigger function processed message: {Encoding.UTF8.GetString(m1.Body)}");
await messageReceiver.CompleteAsync(m1.SystemProperties.LockToken);
}
Enable Batch Operation should be false.
But this is also working for random times - not a reliable solution for the problem.
Check the below screenshot:

Discord.NET If a message has a file attached wait until it's uploaded and delete it

My problem is this; I'm making a bot with Discord.NET 1.0.2 that when a user sends a message, check if there is a file attached to that message and then remove it.
Now I made it, but there is one issue with that. The message won't be deleted until the file was uploaded. I have tried various ways but I can't come up with a solution to how I can wait until the file is uploaded, and then delete the message.
Any help is greatly appreciated.
This is what I'm working with:
private async Task CheckForImageMessage(SocketMessage s)
{
var msg = s as SocketUserMessage;
if (msg == null) return;
var context = new SocketCommandContext(_client, msg);
if (context.Message.Attachments.ElementAt(0) != null)
{
}
}
}
First of all, you are not making a command, so there is very little reason for you to be using a command context at all - message is already accessible to you as s (Attachments collection exists under the IMessage interface).
Second, you can't possibly intercept messages before the file is uploaded. If I understood correctly, you wish to delete any messages with attachments included? If so, an Any method on the Attachments collection would do.
private async Task RemoveAttachmentMsgsAsync(SocketMessage msg)
{
// check if the source channel is a message channel in a guild
if (msg.Channel is SocketTextChannel textChannel)
{
// get the current user to check for permissions
var currentUser = textChannel.Guild.CurrentUser;
// bail if the bot does not have manage message permission
if (!currentUser.GetPermissions(textChannel).ManageMessages) return;
}
// if we made it this far, we can assume that the bot has permission for
// the channel (including DM channel)
// use LINQ Any to check if the attachment contains anything
if (msg.Attachments.Any())
await msg.DeleteAsync();
}

MessageReceiver.ReceiveBatch() not working as intended

I am trying to receive messages in batch from the ServiceBus using the ReceiveBatch method in the MessageReceiver:
IEnumerable<BrokeredMessage> messages;
var messagingfactory = MessagingFactory.CreateFromConnectionString("ConnectionString");
var msgrcvr = messagingfactory.CreateMessageReceiver("queueName", ReceiveMode.ReceiveAndDelete);
messages = msgrcvr.ReceiveBatch(20, timeoutInSecs);
I have checked that my queue contains 20 messages using the Service Bus Explorer.
This code returns only one message in the messages structure. Is there some property I am missing?
This is only a partial-answer or work-around; the following code reliably gets all elements, but doesn't use the "ReceiveBatch"; note, as far as I can discern, Peek(i) operates on a one-based index. Also: depending on which server one is running on, if you are charged by the message pull, this may (or may not) be more expensive, so use at your own risk:
List<BrokeredMessage> dlIE = new List<BrokeredMessage>();
BrokeredMessage potentialMessage = null;
int loopCount = 1;
while ((potentialMessage = deadletterSubscriptionClient.Peek(loopCount)) != null)
{
dlIE.Add(potentialMessage); loopCount++;
}

Categories

Resources