Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Unable to cast MSMQ body to an object

287 views
Skip to first unread message

Bill Wright

unread,
Oct 1, 2007, 4:53:03 PM10/1/07
to
Hi,

I built an assembly with a class, NodeBuildCommand, in the namespace
"Tendril". I use that assembly on one computer to send a
NodeBuildCommand object in the body of a System.Messaging.Message.
This works without error. On the receiving computer I use the same
assembly and then try to cast the body to that object. When this
happens I get a "Type not found error" from GetType(), which is called
from the get_Body() method on the System.Messaging.Message object.

In the development environment on the remote computer in the Immediate
window of the debugger I can do the following:

(new Tendril.NodeBuildCommand()).GetType().Name = "NodeBuildCommand"

(new Tendril.NodeBuildCommand()).GetType().Namespace = "Tendril"

so why doesn't this work:

System.Type.GetType("Tendril.NodeBuildCommand")

This last line returns null and this is the source of my problem with
the casting. Any ideas on how to proceed?

Thanks,
Bill

sloan

unread,
Oct 1, 2007, 5:05:53 PM10/1/07
to

You need to beomce famaliar with the formatter argument


System.Messaging.IMessageFormatter


Here is smoe sample code:

public class MyMSMQListener
{

MessageQueue _queue = null;


public MyMSMQListener(string queuePath ,
System.Messaging.IMessageFormatter formatter, int receiveOrPeekMilliSeconds)
{
this.ConstructorCommon(queuePath , receiveOrPeekMilliSeconds);
this._queue.Formatter = formatter; // Customize the formatter type
}

private void ConstructorCommon(string queuePath , int
receiveOrPeekMilliSeconds)
{

Console.WriteLine("MyMSMQListenerwas constructed");

this._queue = new MessageQueue(queuePath);

this.m_receiveOrPeekMilliSeconds = receiveOrPeekMilliSeconds;

}

}


"Bill Wright" <BillWr...@gmail.com> wrote in message
news:1191271983....@r29g2000hsg.googlegroups.com...

Nicholas Paldino [.NET/C# MVP]

unread,
Oct 1, 2007, 6:03:27 PM10/1/07
to
That shouldn't be ASP code as much as it is COM/ActiveX
component/unmanaged code.

--
- Nicholas Paldino [.NET/C# MVP]
- m...@spam.guard.caspershouse.com

"sloan" <sl...@ipass.net> wrote in message
news:unMwmRHB...@TK2MSFTNGP03.phx.gbl...
>
>
>
>
> New ActiveXMessageFormatter ' good for using Asp code (That's ASP, not
> Asp.Net)
>
>
>
> new BinaryMessageFormatter() ' good for using DotNet objects
>
>
>
> Which formatter are you using?
>
>
>
> ...
>
>
>
> And when you handle/receive the message, are you casting it?
>
>
>
>
>
> Dim e As Employee = CType(msg.Body, Employee)
>
>
>
> Or
>
>
>
> Employee e = msg.Body as Employee; //<< Can you do this, aka, is your
> assembly referenced in the project.
>
> If(null!=e)
>
> {
>
> Console.WriteLine ("We got the employee from the message
> body");
>
> }
>
>
>
>
>
> Something like that.
>
>
>
>
>
>
>
> If a DotNet to DotNet world, you want to usually use the
> BinaryMessageFormatter
>
> Then you have to cast the msg.Body
>
>
>
> Make sense?
>
>
>
>
>
> PS
>
> I really like Manoj's helper
>
> http://msmvps.com/blogs/manoj/archive/2005/10/16/70979.aspx
>
>
>
> I added some code (to enhance his) in the comments section, basically to
> overload the formatter.
>
>
>
>
>
> Question #2.
>
>
>
>
>
>
> --------------------------------------------------------------------------------
>
> From: Bill Wright [mailto:billwr...@gmail.com]
> Sent: Monday, October 01, 2007 5:28 PM
> To: Sloan Holliday
> Subject: Re: Unable to cast MSMQ body to an object
>
>
>
> Sloan,
>
>
>
> Thanks for the email response. I appreciate it.
>
>
>
> I'm using the Formatter. I think that is essential to send a message
> without an error, though I'm not sure.
>
>
>
> Anyway, when I initialize the Formatter I give it an array of two strings:
>
>
>
> { "System.string", "Tendril. NodeBuildCommand" }
>
>
>
> So, I don't think that is the problem. Isn't it curious that can create an
> object like this:
>
>
>
> New Tendril. NodeBuildCommand()
>
>
>
> but that I cannot get the type using System.GetType("Tendril.
> NodeBuildCommand")
>
>
>
> ?
>
>
>
> I've seen stuff about explicitly loading the assembly, but it seems like
> the program knows about the assembly - it can create objects from it
> explicitly, but it can't seem to discover the type via the
> System.GetType() method...?
>
>
>
> Any other ideas?
>
>
>
> Bill
>
>
>
>
>
>
>
>
>
> "sloan" <sl...@ipass.net> wrote in message
> news:Ow0oT7GB...@TK2MSFTNGP06.phx.gbl...

sloan

unread,
Oct 1, 2007, 5:45:54 PM10/1/07
to

...

Or

If(null!=e)

{

}

Something like that.

Make sense?

PS

http://msmvps.com/blogs/manoj/archive/2005/10/16/70979.aspx

Question #2.


--------------------------------------------------------------------------------

Sloan,

{ "System.string", "Tendril. NodeBuildCommand" }

New Tendril. NodeBuildCommand()

?

Any other ideas?

Bill

sloan

unread,
Oct 1, 2007, 6:08:43 PM10/1/07
to
Good catch Nicholas.


ActiveXMessageFormatter = COM/ActiveX

"Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote in
message news:O9PiXZHB...@TK2MSFTNGP04.phx.gbl...

Bill Wright

unread,
Oct 1, 2007, 8:02:16 PM10/1/07
to
Initially, I was using an XmlFormatter to initialize the queue (from
both the sender's init code and the receiver's init code, like this:

string[] types = { "System.String",
"Tendril.NodeBuildCommand" };
BUILD_QUEUE.Formatter = new XmlMessageFormatter(types);

And that's when I got the original error message. I'm still baffled
why System.GetType() doesn't work and I think this problem needs to be
fundamentally understood to solve this problem. That said, I want to
get this to work and am willing to try a different formatter if it
will help matters. So, in the second go I did the following for queue
initialization:

BUILD_QUEUE.Formatter = new BinaryMessageFormatter();

This formatter doesn't appear to take any arguments?

Then each time I construct the message like this:

NodeBuildCommand buildCmd = new NodeBuildCommand(11,
0x1111);
System.Messaging.Message buildMsg = new
System.Messaging.Message(buildCmd);

Then in the receiving application, which uses the same DLL Assembly
that contains the code for the NodeBuildCommand class, I do the
following, in the callback method that I have setup for the queue:

private void buildQueue_ReceiveCompleted(object sender,
ReceiveCompletedEventArgs e)
{
System.Messaging.Message newMsg = e.Message);
(NodeBuildCommand)(newMsg.Body)

The error I get the with the BinaryMessageFormatter method is "Cannot
deserialize the message passed as an argument". I would think this is
message I'd get when using the XmlFormatter, but I guess some form of
serialization is done either way. Each time the exception is thrown
from the System.Messaging.Message.get_Body() method.

Both of these problems are confounding to me.

Thanks for any advice,
Bill

On Oct 1, 4:08 pm, "sloan" <sl...@ipass.net> wrote:
> Good catch Nicholas.
>
> ActiveXMessageFormatter = COM/ActiveX
>
> "Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote in

> messagenews:O9PiXZHB...@TK2MSFTNGP04.phx.gbl...> That shouldn't be ASP code as much as it is COM/ActiveX

> >>> "Bill Wright" <BillWright...@gmail.com> wrote in message

sloan

unread,
Oct 1, 2007, 9:03:56 PM10/1/07
to

You're saying the target code (the code receiving/peeking the msmq message)
has access to the concrete type.
Aka, the NodeBuildCommand.

Here is one method to debug. Make absolute sure you have the same
assembly/class.

Put this (kind of code) in both the sender and the receiving code.

Assembly SampleAssembly;
// Instantiate a target object.
Int32 Integer1 = new Int32();
Type Type1;
// Set the Type instance to the target class type.
Type1 = Integer1.GetType();
// Instantiate an Assembly class to the assembly housing the Integer type.
SampleAssembly = Assembly.GetAssembly(Integer1.GetType());
// Write the display name of assembly including base name and version.
Console.WriteLine("FullName=" + SampleAssembly.FullName);

Basically, you want to look at the FULLNAME to make sure you got apples to
apples. Just because the name is the same doesn't guarantee it.

...............

Also , look at the documentation from MSDN.

Message () Initializes a new instance of the Message class with an
empty body.
Supported by the .NET Compact Framework.

Message (Object) Initializes a new instance of the Message class,
using the XmlMessageFormatter to serialize the specified object into the
body of the message.
Supported by the .NET Compact Framework.

Message (Object, IMessageFormatter) Initializes a new instance of the
Message class using the specified formatter to serialize the specified
object into the body of the message.
Supported by the .NET Compact Framework.


Notice the second constructor will by default use the XmlMessageFormatter.

You probably want to use the third constructor.

> NodeBuildCommand buildCmd = new NodeBuildCommand(11,
> 0x1111);

Does this class have a default constructor? XmlSerialization likes default
constructors.
I'm not sure about BinaryFormatter, as in, it must have a default
constructor or not.

What is the definition of NodeBuildCommand?

Did you mark it as
[Serializable]

See
http://sholliday.spaces.live.com/Blog/cns!A68482B9628A842A!114.entry
for a decent XmlSerialization example.


Then the slight modification of the code:

> private void buildQueue_ReceiveCompleted(object sender,
> ReceiveCompletedEventArgs e)
> {
> System.Messaging.Message newMsg = e.Message);
> (NodeBuildCommand)(newMsg.Body)

private void buildQueue_ReceiveCompleted(object sender,
ReceiveCompletedEventArgs e)
{

System.Messaging.Message newMsg = e.Message;

if(null!=newMsg)
{
NodeBuildCommand nbc = newMsg.Body as NodeBuildCommand;

if(null!=nbc)
{
Console.WriteLine( nbc.ToString());
}
}

}


----------------------

While I would pick the BinaryFormatter over the XmlMessageFormatter, you
should look at the this constructor of the XmlMessageFormatter
XmlMessageFormatter.XmlMessageFormatter(Type[]) Constructor
http://msdn2.microsoft.com/en-us/library/6tb06chb.aspx

as you'll get strong typing vs depending on strings.

..............

From the ground up, here would be my instructions:

::Send
Create a Queue object. Set the formatter.
Create a Message. Get the body to be the object of your choice. Use the
third overload constructor to set the formatter of the Message.
Send the message.

::Receive
Peek/Receive the Queue
With the message, cast the msg.Body as your object.
Make super/double sure you have the same object (Assembly.FullName) as the
sender logic.

My explanation about formatters is this:

ActiveXFormatter. I'm using old COM/ActiveX code to create the message.
But DotNet needs to get at it.
(this is rare)

BinaryFormatter....going from a DotNet to DotNet world. No overloads,
because Microsoft is able to figure out which object it is.

XmlMessageFormatter.. with types. The reason you provide types is because
there are so very very many things which can be serialzied thru Xml. So
basically, you're providing the hint which says "I've got an object of X
type, via my Xml". So its a hint thing. And helps with performance. And
helps because ... .the Xml used to serialize an object can be created from a
variety of sources.


Ok...I hope that helps.

I think you're close, but go from the ground up again.

"Bill Wright" <BillWr...@gmail.com> wrote in message

news:1191283336.3...@g4g2000hsf.googlegroups.com...

sloan

unread,
Oct 1, 2007, 9:10:06 PM10/1/07
to

My hankering is that the issue is ... the third constructor of the Message
object.
http://msdn2.microsoft.com/en-us/library/system.messaging.message.message.aspx


And the fact you don't have a default constructor on your NodeBuildCommand
class.


But my previous post should give you the tools to figure it out.

If you're still stuck, post more code !


"Bill Wright" <BillWr...@gmail.com> wrote in message

news:1191283336.3...@g4g2000hsf.googlegroups.com...

Bill Wright

unread,
Oct 4, 2007, 6:40:05 PM10/4/07
to
Sloan,

Great suggestions and I have met with success! Thanks so much. There
are still things I do not understand, though.

First, what worked. Using the third constructor of the Message,
passing in a Binary formatter:

System.Messaging.Message buildMsg = new
System.Messaging.Message(buildCmd, new BinaryMessageFormatter());

I do wonder why I need to do this if I set the formatter on the queue:

BUILD_QUEUE.Formatter = new BinaryMessageFormatter();

Why do I need to do this as well? Maybe I don't. Something is
redundant here. Anywhere when I made this change I got a clear
serialization error. Then I added

[Serializable]

to the class definition and it worked!

I had already had a default constructor for the class, as that
requirement came up earlier. I'm happy that this works and I'm moving
on, but here are some things I'm still confused about:

1. Why does the queue and the message have formatters associated with
them. One would be sufficient. If it wasn't specified in the message
constructor, why wouldn't it use the one on the queue? Yes, this would
have to be delayed until the message is sent, but so what? It doesn't
need to be formatted until then. Why assign formatters to the queue at
all? Maybe this is strictly for receiving messages. Probably, now that
I think of it.

2. I still don't understand why System.GetType() doesn't work here.
Yes, I have confirmed the assemblies are the same. In fact, I build
the receiving program by pointing it at the build directory on the
transmitting machine. I do not copy the assembly over there
explicitly.

3. What is the point of a BinaryFormatter? It seems like it is just
converting it to XML anyway. Maybe not. I guess serialization doesn't
imply XML necessarily. I think this should work for an XML formatter
as well, but I haven't gone back to try it with the [Serializable]
attribute.

Thanks again for all the great help,
Bill

On Oct 1, 7:10 pm, "sloan" <sl...@ipass.net> wrote:
> My hankering is that the issue is ... the third constructor of the Message

> object.http://msdn2.microsoft.com/en-us/library/system.messaging.message.mes...


>
> And the fact you don't have a default constructor on your NodeBuildCommand
> class.
>
> But my previous post should give you the tools to figure it out.
>
> If you're still stuck, post more code !
>

sloan

unread,
Oct 5, 2007, 10:16:16 AM10/5/07
to

//Quote

1. Why does the queue and the message have formatters associated with
them. One would be sufficient. If it wasn't specified in the message
constructor, why wouldn't it use the one on the queue? Yes, this would
have to be delayed until the message is sent, but so what? It doesn't
need to be formatted until then. Why assign formatters to the queue at
all? Maybe this is strictly for receiving messages. Probably, now that
I think of it.
//End Quote

#1 No idea. Its just the way it is. I would think that the message would
be more important to set as the BinaryFormatter, not the Queue.
But I don't know.

//Quote


2. I still don't understand why System.GetType() doesn't work here.
Yes, I have confirmed the assemblies are the same. In fact, I build
the receiving program by pointing it at the build directory on the
transmitting machine. I do not copy the assembly over there
explicitly.

//End Quote


I'm not "in your code" enough to see this.


//Quote


3. What is the point of a BinaryFormatter? It seems like it is just
converting it to XML anyway. Maybe not. I guess serialization doesn't
imply XML necessarily. I think this should work for an XML formatter
as well, but I haven't gone back to try it with the [Serializable]
attribute.

//End Quote

You have to remember that Xml is just a big fancy (and usually long) string
at the end of the day.
Xml is great for non propietary stuff. But it is in fact not the great
performer.
BinaryFormatter is more efficient, and if you're workign in a DotNot to
DotNet world, use it.

You can find a decent xml serialization demo here:
http://sholliday.spaces.live.com/Blog/cns!A68482B9628A842A!114.entry

//I guess serialization doesn't imply XML necessarily.//
Yes, exactly.

Your code should work if you have xml to xml (serialization), but again, you
shouldn't pick that one necessarily.

......

If you had a situation where you needed to put messages in a queue.... and
you didn't have DotNet doing it, (ex: asp application), you can put xml in
the queue.
Remember, anybody can generation xml. And almost anybody can put a message
INTO the queue. As long as the xml is the right kind of xml, it'll work.

Anything to do with Remoting, MSMQ, WCF, or (in asp.net) Session variables
(stored in Sql Server) needs to be serializable.


"Bill Wright" <BillWr...@gmail.com> wrote in message

news:1191537605.9...@o80g2000hse.googlegroups.com...

0 new messages