Error while deserializing Azure ServiceBus Queue message sent from node.js (azure sdk) - c#

Here's my scenario:
I'm sending an Azure ServiceBus Queue message from Node.js using the node azure sdk like so:
var message = {
body: JSON.stringify({ foo: 'Bar' })
};
serviceBusService.sendQueueMessage('myQueue', message, function (error) {
if (!error) {
console.log('msessage sent');
}
});
I have a c# worker role that is listening to the Queue:
QueueClient Client = QueueClient.CreateFromConnectionString(connStr, QueueName);
Client.OnMessage((receivedMessage) =>
{
var body = receivedMessage.GetBody<string>();
});
When the GetBody method gets executed, i get the following error:
There was an error deserializing the object of type System.String. The input source is not correctly formatted

After some digging around, i found THIS article that helped me get a solution:
Client.OnMessage((receivedMessage) =>
{
var bodyJson = new StreamReader(receivedMessage.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
var myMessage = JsonConvert.DeserializeObject<MyMessage>(bodyJson);
});
If anyone has faced this issue and found a better solution, please let me know!
Thanks!

To anyone who found this question if they were getting this error from sending the message using Service Bus Explorer (like me).
Make sure you specify the correct message type in the drop down:

Thanks for the update, I was doing the reverse and this helped me. I thought I'd add to your solution for completeness. The DeserializeObject method needs the "MyMessage" class defining. In your original post, your JSON is:
{ foo: 'Bar' }
If we drop that into json2csharp (json2csharp.com) we now have the class required to complete your solution:
public class MyMessage
{
public string foo { get; set; }
}
Of course, the dependency is having Newtonsoft.Json package added to your Visual Studio solution:
Install-Package Newtonsoft.Json -Pre

Using the nuget package: Microsoft.Azure.ServiceBus
The following info is contained inside as as comment:
If a message is only being sent and received using this Microsoft.Azure.ServiceBus
client library, then the below extension methods are not relevant and should not be used.
If this client library will be used to receive messages that were sent using both WindowsAzure.Messaging client library and this (Microsoft.Azure.ServiceBus) library, then the Users need to add a User property Microsoft.Azure.ServiceBus.Message.UserProperties while sending the message. On receiving the message, this property can be examined to determine if the message was from WindowsAzure.Messaging client library and if so use the message.GetBody() extension method to get the actual body associated with the message.
---------------------------------------------- Scenarios to
use the GetBody Extension method: ----------------------------------------------
If message was constructed using the WindowsAzure.Messaging client library as
follows:
var message1 = new BrokeredMessage("contoso"); // Sending a plain string var
message2 = new BrokeredMessage(sampleObject); // Sending an actual customer object
var message3 = new BrokeredMessage(Encoding.UTF8.GetBytes("contoso")); // Sending
a UTF8 encoded byte array object await messageSender.SendAsync(message1); await
messageSender.SendAsync(message2); await messageSender.SendAsync(message3);
Then retrieve the original objects using this client library as follows: (By
default Microsoft.Azure.ServiceBus.InteropExtensions.DataContractBinarySerializer
will be used to deserialize and retrieve the body. If a serializer other than
that was used, pass in the serializer explicitly.)
var message1 = await messageReceiver.ReceiveAsync(); var returnedData1 = message1.GetBody();
var message2 = await messageReceiver.ReceiveAsync(); var returnedData2 = message1.GetBody();
var message3 = await messageReceiver.ReceiveAsync(); var returnedData3Bytes =
message1.GetBody(); Console.WriteLine($"Message3 String: {Encoding.UTF8.GetString(returnedData3Bytes)}");
------------------------------------------------- Scenarios to NOT use the GetBody
Extension method: ------------------------------------------------- If message
was sent using the WindowsAzure.Messaging client library as follows: var message4
= new BrokeredMessage(new MemoryStream(Encoding.UTF8.GetBytes("contoso"))); await
messageSender.SendAsync(message4); Then retrieve the original objects using this
client library as follows: var message4 = await messageReceiver.ReceiveAsync();
string returned = Encoding.UTF8.GetString(message4.Body); // Since message was
sent as Stream, no deserialization required here.
May it help you

With the latest Service Bus client libraries (.NET, JS, Java, Python), you can send message(s) using the JS library like this:
const serviceBusClient = new ServiceBusClient("<connectionstring>");
const sender = serviceBusClient.createSender("<queuename>");
await sender.sendMessages([{
body: {
title: "hello"
}
}]);
Note that .sendMessages takes a list as an input, even if you're just sending one message.
And get the body of the received message using .NET library like this:
await using var client = new ServiceBusClient("<connectionstring>");
ServiceBusReceiver receiver = client.CreateReceiver("<queuename>");
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();
string body = receivedMessage.Body.ToString();
Console.WriteLine(body); //prints {"title":"hello"}

Related

Microsoft DirectLine API to bot does not work

So to explain my problem, I have to give you the context.
I got a Bot built with microsoft bot framework deployed on slack. Now it can happen these "events" on my backend that the bot communicates with. When a event occurs, I want to notify my bot of it and then let it send a message to all of it's conversations that something has happend. So basicly:
Backend>Microserivce>Bot>users
To do this I have to store all conversations in my backend, which I do in a database there. When a event happends, the backend will post an activity to the bot with all the conversations(basicly their id's) and the event it should show them.
So in essence my backend need to post a message to my bot.
For doing this I found the microsoft directline api which acts as a middleman here, a more abstract way to talk with the bot. The problem is that I don't know how to do it. I followed microsofts own tutorial but it doesn't seem to work for me:
This is the endpoint that my backend uses to notify the bot. "content" contains conversations and events as a json formated string.
[HttpPost]
[Route("conversationsEvents")]
public HttpResponseMessage PostConversationsEvents([FromBody]string content)
{
NotifyBot.Notify(content);
return Request.CreateResponse(HttpStatusCode.NoContent );
}
NotifyBot.Notify(content) looks like this:
private static async Task StartBotConversation( string contents)
{
string directLineSecret = "secret";
string fromUser = "microserviceNotifyEndpoint";
Activity activity = new Activity
{
From = new ChannelAccount(fromUser),
Text = contents,
Type = ActivityTypes.Event
};
DirectLineClient client = new DirectLineClient(directLineSecret);
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, activity);
}
Basicly the execution get's stuck at var conversation = await client.Conversations.StartConversationAsync(); , it just waits forever.
I tried changing it to var conversation = await client.Conversations.StartConversationAsync().ConfigureAwait(continueOnCapturedContext: false);´the execution goes on but the activity doesn't seem to get posted.
I'm not sure why the call to .StartConversationAsync() would freeze in your case. Maybe you haven't enabled the Direct Line channel on dev.botframework.com/bots? Nonetheless, as pointed out by Sergey, the Direct Line is a Channel and not a means for communicating with your bot on other channels.
Check out the Connector Client: bot-builder-dotnet-connector
Here is a static example of using it to proactively send a message to a user from a bot: MicrosoftDX/botFramework-proactiveMessages - sample: ConversationStarter.cs
pertinent code from sample:
public static async Task Resume(string conversationId,string channelId)
{
var userAccount = new ChannelAccount(toId,toName);
var botAccount = new ChannelAccount(fromId, fromName);
var connector = new ConnectorClient(new Uri(serviceUrl));
IMessageActivity message = Activity.CreateMessageActivity();
if (!string.IsNullOrEmpty(conversationId) && !string.IsNullOrEmpty(channelId))
{
message.ChannelId = channelId;
}
else
{
conversationId = (await connector.Conversations.CreateDirectConversationAsync( botAccount, userAccount)).Id;
}
message.From = botAccount;
message.Recipient = userAccount;
message.Conversation = new ConversationAccount(id: conversationId);
message.Text = "Hello, this is a notification";
message.Locale = "en-Us";
await connector.Conversations.SendToConversationAsync((Activity)message);
}
The serviceUrl, the channelId, conversationId, toId, fromId, etc are cached from previous communication by the user to the bot (these are statically stored in this example, so only work for one user). This example shows how it is possible to proactively send a message to a user from a bot. The Direct Line api is not required.
You don't need to use DirectLine, it is designed for creating alternative bot UIs.
To implementing what your want, you may try the following:
First, you need to store users addresses to whom you want to send the messages. It my be done by storing the ResumptionCookie of a user last message in your backend database.
var state = new ResumptionCookie(message).GZipSerialize();
When your PostConversationsEvents is called, you may resume the conversation at the latest point with each users.
var resumptionCookie = ResumptionCookie.GZipDeserialize(state);
var message = resumptionCookie.GetMessage();
message.Text = content;
await Conversation.ResumeAsync(resumptionCookie, message);
It is not the only solution. As I said, in this case you just resumed the conversation with the user at the latest point. Another solution is to save the user address (user the same ResumptionCookie class) but start the conversation when you need to:
var resumptionCookie = ResumptionCookie.GZipDeserialize(state);
var message = cookie.GetMessage();
ConnectorClient client = new ConnectorClient(new Uri(message.ServiceUrl));
var conversation = await
client.Conversations.CreateDirectConversationAsync(message.Recipient, message.From);
message.Conversation.Id = conversation.Id;
var newMessage = message.CreateReply();
newMessage.Text = content;
await client.Conversations.SendToConversationAsync(newMessage);
See more details on BotFramework documentation.

send an email from azure functions when a process finishes

I have a device that sends data in text form to a blob on AZURE, once the blob receives the data it triggers a function in azure functions which is basically and executable file made from c++ code, when it finishes it generates another text file which is stored in other blob
it is a very simple operation. But now I would like to receive an email each time the function goes trough successfully, I have searched on the web but the tutorial are very confusing or does not address this simple task.
I did developed the executable file with c++ but I inherited the azure function from someone else and I have zero experience with azure (i am electrical engineer not computer science). The azure function is written in C#, I just need a guide.
Thank you in advance!!
Use can add SendGrid output binding to you C# Azure Function. The binding in function.json would look something like this:
{
"name": "mail",
"type": "sendGrid",
"direction": "out",
"apiKey" : "MySendGridKey"
}
and function body like this:
#r "SendGrid"
using SendGrid.Helpers.Mail;
public static void Run(string input, out string yourExistingOutput, out Mail message)
{
// Do the work you already do
message = new Mail
{
Subject = "Your Subject"
};
var personalization = new Personalization();
personalization.AddTo(new Email("recipient#contoso.com"));
Content content = new Content
{
Type = "text/plain",
Value = "Email Body"
};
message.AddContent(content);
message.AddPersonalization(personalization);
}
Read about SendGrid and SendGrid bindings.
I had a similar problem which Mikhail's solution helped me solve. In my case I wanted the static Run method to be asynchronously, which meant I couldn't use the out parameter modifier. My solution's slightly different as it is a timer trigger and was implemented using Visual Studio and the NuGet package Microsoft.Azure.Webjobs.Extensions.SendGrid v2.1.0.
[FunctionName("MyFunction")]
public static async Task Run(
[TimerTrigger("%TimerInterval%")]TimerInfo myTimer,
[SendGrid] IAsyncCollector<Mail> messages,
TraceWriter log)
{
log.Info($"C# Timer trigger function started execution at: {DateTime.Now}");
// Do the work you already do...
log.Info($"C# Timer trigger function finished execution at: {DateTime.Now}");
var message = new Mail();
message.From = new Email("from#email.com");
var personalization = new Personalization();
personalization.AddTo(new Email("to#email.com"));
personalization.Subject = "Azure Function Executed Succesfully";
message.AddPersonalization(personalization);
var content = new Content
{
Type = "text/plain",
Value = $"Function ran at {DateTime.Now}",
};
message.AddContent(content);
await messages.AddAsync(message);
}
This solution used Zain Rivzi's answer to How can I bind output values to my async Azure Function?
and the SendGrid Web API v3 quick start guide.
The answer can be slightly simplified:
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using SendGrid.Helpers.Mail;
public static class ExtractArchiveBlob
{
[FunctionName("MyFunction")]
public static async Task RunAsync(string input,
[SendGrid(ApiKey = "SendGridApiKey")]
IAsyncCollector<SendGridMessage> messageCollector)
{
var message = new SendGridMessage();
message.AddContent("text/plain", "Example content");
message.SetSubject("Example subject");
message.SetFrom("from#email.com");
message.AddTo("to#email.com");
await messageCollector.AddAsync(message);
}
}
Where SendGridApiKey is the app setting holding your Send Grid api key.

SignalR, passing an object from the HUB to the Client (MVC C#)

I've looked around at other questions but they don't seem to fully answer this question, I'm trying to pass an object via JSON to the client Javascript. I'm using Newtonsoft.Json to make the process easier, but I can't seem to recieve the object.
Here's the code:
When a connection is made, I call the Hub using start().done() in the client javascript:
//start comm with server
$.connection.hub.start().done(function () {
console.log('Grabbing playlist data');
Playlist.server.requestPlaylist();
});
This calls the following method, which is supposed to grab the object and pass it back:
public void requestPlaylist()
{
var playlistData = (from c in db.Playlist where c.ID > 0 select c).Include(h => h.Song).ToList();
Playlist player = new Playlist();
foreach (var item in playlistData)
{
player.ID = item.ID;
player.Profile = item.Profile;
player.Song.ID = item.Song.ID;
player.Song.name = item.Song.name;
player.upvotes = item.upvotes;
}
string jsonObject = JsonConvert.SerializeObject(player);
Clients.All.recievePlaylist(jsonObject);
}
SO here, I'm searching the database, getting the results and storing it into the playlist model, then using newtonsoft.json to convert the model into a json object (Its roughly the same principle they have as an example on their site).
The client javascript that is invoked from this is:
function recievePlaylist(jsonObject) {
console.log('test to recieve data: ' + jsonObject.ID + ' test.');
};
Now just for testing purposes I'm just logging out out to the console, but this come back with nothing:
"test to recieve data: test." is how it comes back.
What am I missing?
Because you convert the object to a string on the server before passing it to the client, the client receives a string. Your string representation of a json object doesnt have an ID property so the value will be "undefined".
On the client you can use this to convert the string to a json object:
jsonObject = JSON.parse(jsonObject);
Just add that line to the top of your recievePlaylist function.
Note: You shouldn't actually need to convert your server object to a json string on the server side. SignalR automatically converts your server side objects to json objects on the client.
If you call WebAPI and receive json response/result on client side (JavaScript/jQuery). The way is general for both SignalR or WebAPI in regards of parse jsone response and the use it as object.
var obj = jQuery.parseJSON( '{ "name": "John" }' );
alert( obj.name === "John" );

cannot assign void to an implicitly typed local varial Twilio Api

i want to send a message to mobile device using the twilio api i am using asp.net c# Mvc4, so for that i downloaded the twilio.mvc and twilio library following the tutorial on the website, but now its giving me error whats i the problem is it with the API code or libraries.
string AccountSid = "AC45b00a5504e242b8a486ebf4cad405c9";
string AuthToken = "9b192f3af2c286c387772076a5360d89";
var twilio = new TwilioRestClient(AccountSid, AuthToken);
var message = twilio.SendMessage("+17036394054", "+923437142161", "Hey its a test message from twilio", "", null);
Console.WriteLine(message.Sid);
responce.StatusCode = 401;
return responce;
Twilio evangelist here.
You're using an overload of SendMessage that accepts an Action and returns void, so there is no return value to assign to the message variable.
You can either change your code to:
var message = twilio.SendMessage("+17036394054", "+923437142161", "Hey its a test message from twilio");
Console.WriteLine(message.Sid);
or this:
var message = twilio.SendMessage("+17036394054", "+923437142161", "Hey its a test message from twilio", "", r => r {
Console.WriteLine(message.Sid);
});
Hope that helps.

Read request message body while binding dependency using ninject.extensions.wcf

I am using Ninject.Extensions.Wcf in a WCF service, and also have the Ninject.Web.Common package in my project.
In the NinjectWebCommon class this is how I bind my dependency
kernel.Bind<ISomething>().To<ConcreteSomething>();
straightforward binding, and everything works..
Now, I want to do the resolution based on some members in the message request body, so I create a provider
kernel.Bind<ISomething>().ToProvider<SomethingProvider>();
And SomethingProvider tries to read the request message like this
public class SomethingProvider : Provider<ISomething>
{
protected override ISomething CreateInstance(IContext context)
{
var message = OperationContext.Current.RequestContext.RequestMessage;
//message.State is Read here, so CreateBufferedCopy throws an InvalidOperationException.
var buffer = message.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
var messageCopy = buffer.CreateMessage();
var body = messageCopy.GetBody<string>();
//Parse body, check some members and return one of the "Somethings"
return new AnotherConcreteSomething();
}
}
This throws an invalid operation exception. The RequestMessage in the operationcontext is already in read state, so I cant read it again.
I read that RequestMessage.ToString() is not always reliable since it truncates the body. And, I will have to get the body from the whole SOAP message.
Is there any other way I can do this? Is this approach even correct?

Categories