Azure Service Bus GetBody<Stream> encoding cannot be determined - c#-4.0

I'm trying to get a BrokeredMessage from AzureServiceBus in a .NET client and choose how to deal with the message based on the type of message coming in, but ContentType and other message properties are not set.
My test message sending looks like this:
var client =
QueueClient.CreateFromConnectionString(connectionString, queueName);
var message = new BrokeredMessage("test");
client.Send(message);
My code to receive is using GetBody so that I can inspect the serialized data and decide how to deal with it:
var stream = message.GetBody<Stream>();
string s = null;
using (StreamReader sr = new StreamReader(stream))
{
s = sr.ReadToEnd();
}
The problem is that "s" above ends up with what looks like it should be XML created from a DataContractSerializer, but it is strangely encoded. I've tried many encodings on the receiving side and none seem to get me valid xml. Example results:
#string3http://schemas.microsoft.com/2003/10/Serialization/�test
I see the serialization namespace and what looks like it should start with <string, but as you can see I'm getting control characters. Does any one know how I can try to get the serialized data here as valid XML so I can dynamically handle it?
TIA for any help.
To be really clear I want to test the body so I can do something like:
if (BodyIsString(s)) { do something }
if (BodyIsPerson(s)) { do something else }
If I could getbody twice this would be really easy.

As Sean Feldman mentioned when send message is string type we could use
var body = message.GetBody<string>();
to get message body, after I decompile the WindowsAzure.ServiceBus.dll then get the code:
public T GetBody<T>()
{
if (typeof (T) == typeof (Stream))
{
this.SetGetBodyCalled();
return (T) this.BodyStream;
}
if (!this.bodyObjectDecoded || this.bodyObject == null)
return this.GetBody<T>((XmlObjectSerializer) new DataContractBinarySerializer(typeof (T)));
this.SetGetBodyCalled();
return (T) this.bodyObject;
}
I find that if the send message
is not Stream type it will be DataContractBinarySerializer. so we also could get the message body with following way
var stream = message.GetBody<Stream>();
var messageBody = new DataContractSerializer(typeof(string)).ReadObject(XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max));
From the decompiled code we could know that if we send the stream message, we could get the message body with the way you mentioned.
Send stream message code :
var client = QueueClient.CreateFromConnectionString(connectionString, queueName);
var byteArray = Encoding.UTF8.GetBytes("test stream");
MemoryStream stream = new MemoryStream(byteArray);
client.Send(new BrokeredMessage(stream));
then receive message as you mentioned it should work:
var stream = message.GetBody<Stream>();
string s = null;
using (StreamReader sr = new StreamReader(stream))
{
s = sr.ReadToEnd();
}
Edit :According to update question:
If I could getbody twice this would be really easy.
we could clone the BrokerMessage
var newMessage = receiveMessage.Clone();
Edit2:
We also can get the message Properties to know the body type if we set it during sending. Take Label for example:
var message = new BrokeredMessage(object);
message.Label = "Type of message body";
client.Send(message);
While we receive the message we could get the message Label value then select the corresponding way to get the body.

You passed your payload as a string
var message = new BrokeredMessage("test");
therefore it was serialized as a string. Upon receive you should get the body as a string as well in the following manner:
var body = message.GetBody<string>();
You would use Stream if you'd actually construct your brokered message using a stream.

Related

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);

How to log the response message in a Registered Handler - ServiceStack RabbitMQ

Given this snippet of code:
//DirectApi
mqServer.RegisterHandler<LeadInformationInfo>(m =>
{
repository.SaveMessage(m as Message);
LeadInformationInfoResponse response = new LeadInformationInfoResponse();
try
{
var client = new JsonServiceClient(settingsFactory.GetMasterSetting("ProcessorApi:baseUri"));
response = client.Post(m.GetBody());
}
catch (WebServiceException webServiceException)
{
_log.Error("RegisterHandler<LeadInformationInfo>", webServiceException);
response = ((LeadInformationInfoResponse) webServiceException.ResponseDto);
response.CorrelationId = m.Id;
}
// Log response message here
return response;
}, 1);
I've gone to great lengths to make sure that a correlationId based off the original message Id property is propagated through the life of this message and any child messages spawned from this action. How do I get a handle on the response message so that I may log it in the handler? I only have access to the ResponseDto and not the message.
One of the reasons for this request is that the message queue client does not have access to the database, only the process that has the handler registered does. Hope that explains the situation better.
Just to clarify, this question is about persisting a MQ Response Message in the handler, the correlation Id is something that all messages in 1 request/response workflow will share. I'm also using ServiceStack ORMlite to persist the Message object, so querying this table by ID for troubleshooting is paramount.
Thank you,
Stephen
You're calling a WebService from within your MQ Handler:
var client = new JsonServiceClient(...);
response = client.Post(m.GetBody());
So there is no MQ Response which is only available in MQ Services. Although the WebService will return the response for the request that's sent so you can either use the CorrelationId on the MQ Request, otherwise you can have your Response DTO implement an interface like IHasCorrelationId and get it that way, e.g:
var correlationResponse = response as IHasCorrelationId;
if (correlationResponse != null)
{
var correlationId = correlationResponse.CorrelationId;
}
Create your own Instance of Message
As the Message<T> class is just a POCO if you wanted to create your own you can intialize your own instance:
var mqResponse = new Message<Response>(response);
If you only had the runtime late-bound type info, you can create one with:
var mqResponse = MessageFactory.Create(response);
Use RabbitMQ Message Filters
If you just wanted to log incoming and outgoing messages you can use the RabbitMQ Message Filters, e.g:
var mqServer = new RabbitMqServer("localhost")
{
PublishMessageFilter = (queueName, properties, msg) => {
properties.AppId = "app:{0}".Fmt(queueName);
},
GetMessageFilter = (queueName, basicMsg) => {
var props = basicMsg.BasicProperties;
receivedMsgType = props.Type; //automatically added by RabbitMqProducer
receivedMsgApp = props.AppId;
}
};

Servicestack-RabbitMq: Return response type in message headers

Is there any way to add the type of the response dto to the rabbitmq response message's headers collection?
(My consumer is using spring's rabbitmq handler which seems to depend on explicit type information inside the mq header when deserializing.)
Currently servicestack's mq producer already returns serveral headers, such as "content_type='application/json".
I am in need of an additional header, e.g. "typeId"="HelloResponse", so that the consuming web app knows how to deserialize the message, even in RPC cases where the response queue name is some kind of GUID.
Is there some kind of configuration which would enable me to archieve such an behaviour? Or some hook before the message gets published so that I can add the header myself?
I've added support for automatically populating the Message Body Type in RabbitMQ's IBasicProperties.Type as well as adding support for both Publish and GetMessage Filters in this commit.
Here's an example of configuring a RabbitMqServer with custom handlers where you can modify the message and its metadata properties when its published and received:
string receivedMsgApp = null;
string receivedMsgType = null;
var mqServer = new RabbitMqServer("localhost")
{
PublishMessageFilter = (queueName, properties, msg) => {
properties.AppId = "app:{0}".Fmt(queueName);
},
GetMessageFilter = (queueName, basicMsg) => {
var props = basicMsg.BasicProperties;
receivedMsgType = props.Type; //automatically added by RabbitMqProducer
receivedMsgApp = props.AppId;
}
};
mqServer.RegisterHandler<Hello>(m =>
new HelloResponse { Result = "Hello, {0}!".Fmt(m.GetBody().Name) });
mqServer.Start();
Once Configured any message published or received will go through the above handlers, e.g:
using (var mqClient = mqServer.CreateMessageQueueClient())
{
mqClient.Publish(new Hello { Name = "Bugs Bunny" });
}
receivedMsgApp.Print(); // app:mq:Hello.In
receivedMsgType.Print(); // Hello
using (IConnection connection = mqServer.ConnectionFactory.CreateConnection())
using (IModel channel = connection.CreateModel())
{
var queueName = QueueNames<HelloResponse>.In;
channel.RegisterQueue(queueName);
var basicMsg = channel.BasicGet(queueName, noAck: true);
var props = basicMsg.BasicProperties;
props.Type.Print(); // HelloResponse
props.AppId.Print(); // app:mq:HelloResponse.Inq
var msg = basicMsg.ToMessage<HelloResponse>();
msg.GetBody().Result.Print(); // Hello, Bugs Bunny!
}
This change is available from ServiceStack v4.0.33+ that's now available on MyGet.

How to send/receive messages through a web socket on windows phone 8 using the class ClientWebSocket?

The web socket is written in javascript by my colleague. I managed to connect. First of all I have to log in on the application using a test account. I have to send the email and password through a json. I have installed the Json.Net packet using NuGet.
Some code that I found on my reaserch is this, but I do not understand how to send my data using that segment.
var buffer = new byte[1024];
var segment = new ArraySegment<byte>(buffer);
webSocket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
Of course, I can use an object
User user=new User();
user.Email="bla#bla.com";
user.Password="pass";
string json = JsonConvert.SerializeObject(user);
But it will not be of any use because the method SendAsync accepts only byte type on segment.
All I want is to send that data, and if log in succeeds, I should receive other data (in Json format) about the user.
As a side note, I am quite new to web sockets, I used http protocols from ASP.NET WEB API 2.
I have no idea about Windows Phone 8, but by the code you pasted it seems similar to the regular .NET ClientWebSocket, so here you have some examples:
public static Task SendString(ClientWebSocket ws, String data, CancellationToken cancellation)
{
var encoded = Encoding.UTF8.GetBytes(data);
var buffer = new ArraySegment<Byte>(encoded, 0, encoded.Length);
return ws.SendAsync(buffer, WebSocketMessageType.Text, true, cancellation);
}
public static async Task<String> ReadString(ClientWebSocket ws)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
do
{
result = await ws.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms, Encoding.UTF8))
return reader.ReadToEnd();
}
}
If something does not compile or exists in WP8, just find an equivalent.
#vtortola is a working example in case your data comes in multiple segmented messages, but if all data comes in a single message you don't need all those streams to read the message, you just need to do this:
public static async Task<String> ReadString(ClientWebSocket socket)
{
var reciveBuffer = new byte[32000];
var result = await socket.ReceiveAsync(new ArraySegment<byte>(reciveBuffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
}
return Encoding.ASCII.GetString(reciveBuffer , 0, result.Count);
}
If your message is splited in multiple segments or you don't know how your message is comming then you have to do like #vtortola
Also if you want to keep receiving messages you can do a while and call ReadString inside, like this:
while (socket.State == WebSocketState.Open)
{
var msg = ReadString(socket)
//do something with your message...
}

how to post plain json data to service stack rest service

Below is the code I am using to post json data to a rest ful service
var client = new JsonServiceClient(BaseUri);
Todo d = new Todo(){Content = "Google",Order =1, Done = false };
var s = JsonSerializer.SerializeToString < Todo>(d);
// client.Post<string>("/Todos/", "[{\"content\":\"YouTube\"}]");
// string payload= "[{\"id\":2,\"content\":\"abcdef\",\"order\":1,\"done\":false}]";
// string payload = #"{""todo"":{ {""content"":""abcdef"",""order"":1}} }";
client.Post<string>("/todos/", s);
I tried passing plain json data , it keep on fialing with message "Bad data". Then i tried serizliing the entity that also didn't work.
You can use PostJsonToUrl, which is included in ServiceStack.Text.

Resources