In my job, I work with an application developped partly in c++ and C#. The C++ code is responsible to manage activeMQ (send, receive message).
I've developped an application to monitor the messages sent in the topic by subscribing myself with my C# application.
So when a message is sent to a topic, my application manage to handle the message, but the message is serialized in ActiveMQBytesMessage.
How can I deserialize this object ?
public void OnMessage(IMessage message)
{
if (message != null)
{
var content = (message as ActiveMQBytesMessage).Content; // This is a byte[], I tried to deserialize using BinaryFormatter but it throws an exception, I can't write it here because I'm at home.
}
}
I just noticed that ActiveMQBytesMessage inherits IBytesMessage from namespace Apache.NMS, but I see nothing which helps me to deserialize the message.
I use the last version of ActiveMQ with NMS
[NB] The goal of my C# application is to simply monitor what's happening inside an ActiveMQ channel. That's why I need to deserialize the ActiveMQBytesMessage so I can display the name of the object and its content in a gridview.
[Added more information]
Here's what i tried to deserialize.
var memoryStream = new MemoryStream((message as ActiveMQBytesMessage).Content);
var binaryFormatter = new BinaryFormatter();
memoryStream.Position = 0;
var deserializedMessage = binaryFormatter.Deserialize(memoryStream);
And I get this error when it deserializes:
The input stream is not a valid binary format. The starting contents (in bytes) are: 00-00-00-00-00-00-4F-8C-00-00-00-09-00-00-00-00-54 ...
(I am making a few assumptions here, since you didn't specify certain details.) The BinaryFormatter you are attempting to use will only work for .NET objects, not for C++ objects. Most likely, these objects have not been encoded in a platform neutral way, and are in a C++ format specific to that particular compiler and platform. Therefore, it is up to you to parse the binary code directly to determine what object is encoded, and then to manually decode the data. If these are non-trivial objects, this will be a difficult task. If at all possible, try to get the original application to encode the objects into a platform neutral format that can be easily parsed and instantiated in C#. (I prefer using a TextMessage and XML encoding.) It won't be as efficient as the direct C++ to C++ encoding/decoding that is apparently going on right now, but it will allow external monitoring of the message stream. When I do this, I put the full typename (including namespace) of the object in the NMSType header property. This then tells me the internal structure of message content, and I can instantiate the correct object for parsing the data out of the message.
If all of that doesn't help, or the assumption is wrong and you are using Managed C++, perhaps this question/answer will help you: What serialization method is used for an ActiveMQ NMS C# object message?
Related
I'm working on a system built on Azure Service Bus and Azure Functions.
Our service bus messages are text based, usually json and we have started seeing errors in some of our messages about invalid characters in the text.
This doesn't affect all messages on the queue and I've been able to trace it back to using Service Bus Explorer to resubmit Dead Letter Queue messages with a Body type of "String"
In service bus explorer the message appears perfectly normal:
however when reading the message from code the body text is:
#06string083http://schemas.microsoft.com/2003/10/Serialization/�15Hi mate, how are you?
I would like to be able to handle messages which have been submitted this way, but none of the messages on the ReceivedMessage Class work. I've tried a number of approaches using C# in Linqpad
var client = new ServiceBusClient(connectionString);
var receiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions { ReceiveMode = ServiceBusReceiveMode.PeekLock});
string txtBody;
"Peek Messages".Dump();
var message = await receiver.PeekMessageAsync();
while (message != null)
{
Stream stream = message.Body.ToStream();
StreamReader reader = new StreamReader(stream,Encoding.UTF8);
txtBody = reader.ReadToEnd();
txtBody.Dump("Read with stream");
txtBody = Encoding.UTF8.GetString(message.Body.ToArray());
txtBody.Dump("Read with Byte[]");
message.Body.ToString().Dump("Read with toString");
message = await receiver.PeekMessageAsync();
}
This only happens if the message was resubmitted as a string - resubmitting as stream works as expected.
It seems to me like there should be a way of detecting this type of message and an alternate way of reading it. Service bus Explorer is clearly handling it somehow.
Service Bus Explorer is based on a legacy SDK which uses a DataContractSerializer to encode the message payload. This approach was deprecated and not carried forward into the newer SDKs.
Azure.Messaging.ServiceBus makes no assumptions about how your message payload was serialized or encoded, returning only the raw bytes. To interact with a payload from Service Bus Explorer, you'll need to use an equivalent serializer to transform the payload.
An example of doing so can be found in the Service Bus Interop sample.
I'm adding my own answer to help others.
Jesse Squire pointed my in the right direction to the service bus interop samples however that approach only works where the message has been serialized and contains the "serialization junk".
The vast majority of messages coming through my queues are generated with new libraries and are "clean". It's only a small portion of messages which have been "repaired and resubmitted" from the DQL using Service Bus Explorer or other tools based on older libraries that cause a problem.
I solved this by checking for serialization markers in the text as shown below.
string ReadMessageText(ServiceBusReceivedMessage message)
{
string msgText = message.Body.ToString();
if (msgText.StartsWith("#") && msgText.Contains(#"http://schemas.microsoft.com/2003/10/Serialization"))
{
var deserializer = new DataContractSerializer(typeof(string));
XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(message.Body.ToStream(), XmlDictionaryReaderQuotas.Max);
// deserialize the XML envelope into a string
msgText = (string)deserializer.ReadObject(reader);
}
return msgText.Trim();
}
This requires System.Runtime.Serialization for the DataContractSerializer and System.Xml for the reader.
I got a task that I got something likeIEnumerable<State> StateList; sending from a C# based sever and I need to deserialize it in C++ based client. (State here is a proto class). I have no control on the proto. file so I can't just add any repeated message in the proto and make it work like a STL in C++. I don't know how I can deserialize this thing.
In C#,
System.IO.MemoryStream ms = new System.IO.MemoryStream (56 * stateList.Count());
ProtoBuf.Serializer.Serialize(ms, StateList);
So I think it use protobuf-net and use this function
public static void Serialize<T>(Stream destination, T instance);
BTW, we use MQTT as our transmit protocol.
I have simple c# client app which sends object to java based server app.
Note:I am using protobuf-net on clinet side. For this application I have simple .proto file with only one field and .java class is generated by protoc compiler.
.Proto file:
message Person {
required string id = 1;
}
C# client to send object
MemoryStream ms = new MemoryStream();
Person per = new Person();
per.id = "TestId001";
Serializer.Serialize<Person>(ms, per);
byte[] buffer = ms.ToArray();
clientSocket.SendTo(buffer, hostEP);
Java based server to receive object
DataInputStream inputStream=new DataInputStream(socket.getInputStream());
Person person = Person.parseFrom(socket.getInputStream());
System.out.println("Id: " + person.getId());
Problem: I not getting the serialized message as sent by the c# app.Even I am not getting
any errors. That's why I was unable to figureout the problem.
"Problem: I not getting the serialized message"
This sounds simply like the classic "sockets are streams" issue (second example here: http://marcgravell.blogspot.com/2013/02/how-many-ways-can-you-mess-up-io.html). If you have written data to a stream but haven't closed that stream, the receiving stream does not terminate. It also does not automatically know that the client sent (say) 117 bytes that should be considered a single message. You have two options:
close the outbound stream after writing (only suitable for sending single messages, not for continued discussions between two nodes)
introduce some form of framing - for example a length-prefix - so that the receiver knows to only try to read a certain amount of data, rather than trying to read to the EOF (which will never come if you haven't closed the outbound stream)
Note: in addition to the "sockets are streams" issue, also keep in mind that protobuf messages are appendable. A protobuf message, by itself, has no notion of where it ends. Fortunately, both the existing bullet points above will address this. But importantly, you can't just write 3 Person object to the stream in a frame (or close the stream), and then expect to be able to get back 3 Person objects at the other end: you will get one Person object. In this scenario, the simplest option is to add a wrapper object, i.e.
message SomeMessage {
repeated Person people = 1;
}
Try adding these attributes to your class in C# and check if the input is ok in Java.
[ProtoContract]
class Person
{
[ProtoMember(1)]
public string id = "1";
}
I have a .net Web service Method 'CheckCustomerLicense', and this method returns a C sharp serialized object, I am calling this method via Soap from PHP.
I am getting the serialized object which is binary formatted and not in XML.
I want to access that data as object in PHP, but to do this I must desirealize it, and since its a .NET object I want to use .NET built in class 'System.Runtime.Serialization.Formatters.Binary.BinaryFormatter' via COM.
The Code I am Using For This Is Shown Below:
<?php
class eToolsLicenseNew
{
}
$url='http://mail.ucm.com.au/eToolsLicenseWebService/eToolsLicenseWebUpdateService.asmx?WSDL';
$soap = new SoapClient($url, array(
"trace" => 1, // enable trace to view what is happening
"exceptions" => 1, // disable exceptions "cache_wsdl" => 1)
);
try {
$customer=array('customerId'=>'12345');
$result=$soap->CheckCustomerLicense($customer);
//print_r($result);
$obj = new COM("System.Runtime.Serialization.Formatters.Binary.BinaryFormatter");
$object=new eToolsLicenseNew();
$object=$obj->Deserialize($result); // call to deserilize method
}
catch (SoapFault $e)
{
echo "Error: {$e->faultstring}";
}
?>
But When I call 'Deserializing Method' Giving Internal Server Error....
Other than that every thing is fine, Can Any one is there to help me... Please...
The data your receive is a byte array. If it contains a .NET binary formatted object, you will need to have a BinaryFormatter to deserialize it. A binary formatters Deserialize method however, does not take a byte array. It takes a stream of any kind. The simplest conversion method from byte array to a stream is using a MemoryStream. This takes a byte array as constructor parameter.
var bytes = new byte[50]; // example byte array
using(var stream = new MemoryStream(bytes))
{
BinaryFormatter formatter = new BinaryFormatter();
var obj = (YourExpectedType)formatter.Deserialize(stream);
}
This is what the C# code would look like, you will need to adapt it to the COM/PHP variant.
Again, if this is really the case, someone is sending a binary serialized object via XML serialized SOAP to someone, then the first someone needs to learn how to code webservices. Because this is not an interoperable webservice, this is C#-to-C# communication wasting time using SOAP.
I'm wondering is there a way to send some kind of generics for example List <float> floatValues = new List<float>() need to be sent to udp client. I don't know how to do that, any help will be appreciated!
You can serialize floatValues using some serialization facility (like XmlSerializer, BinaryFormatter or DataContractSerializer) and than deserialize it back.
Or you can create your own "application level protocol" and put to the stream type name and serializer type and use this information during deserialization process.
What you want to do is known as serialization/deserialization
In computer science, in the context of data storage and transmission, serialization, is the process of converting a data structure or object state into a format that can be stored (for example, in a file or memory buffer, or transmitted across a network connection link) and "resurrected" later in the same or another computer environment
Instead of building your own serializer, I would recommend to use one of the existing libraries like
XmlSerializer,
SoapFormatter,
BinaryFormatter,
DataContractSerializer ,
DataContractJsonSerializer,
JavaScriptSerializer,
Json.Net,
ServiceStack,
Protobuf.Net ........
Here is an example using Json serialization
//Sender
string jsonString = new JavaScriptSerializer().Serialize(floatValues);
byte[] bytesToSend = Encoding.UTF8.GetBytes(jsonString);
//Receiver
string receivedJson = Encoding.UTF8.GetString(bytesToSend);
List<float> floatValues2 = new JavaScriptSerializer()
.Deserialize<List<float>>(receivedJson);