The little series I am currently writing here on my blog has inspired me to write way too more code than actually necessary to get my point across ;-) So by now I've got my own MSMQ transport for WSE 2.0 (yes, I know that others have written that already, but I am shooting for a "enterprise strength" implementation), a WebRequest/WebResponse pair to smuggle under arbitrary ASMX proxies and I am more than halfway done with a server-side host for MSMQ-to-ASMX (spelled out: ASP.NET Web Services).

What bugs me is that WSE 2.0's messaging model is "asynchronous only" and that it always performs a push/pull translation and that there is no way to push a message through to a service on the receiving thread. Whenever I grab a message from the queue and put it into my SoapTransport's "Dispatch()" method, the message gets queued up in an in-memory queue and that is then, on a concurrent thread, pulled (OnReceiveComplete) by the SoapReceivers collection and submitted into ProcessMessage() of the SoapReceiver (like any SoapService derived implementation) matching the target endpoint. So while I can dequeue from MSMQ within a transaction scope (ServiceDomain), that transaction scope doesn't make it across onto the thread that will actually execute the action inside the SoapReceiver/SoapService.

So now I am sitting here, contemplating and trying to figure out a workaround that doesn't require me to rewrite a big chunk of WSE 2.0 (which I am totally not shy of if that is what it takes). Transaction marshaling, thread synchronization, ah, I love puzzles. Once I am know how to solve this and have made the adjustments, I'll post the queue listener I promised to wrap up the series. The other code I've written in the process will likely surface in some other way.

Monday, December 06, 2004 7:47:08 AM UTC
I had exactly the same frustration, and I ended up ignoring the DispatchMessage call. I recall Roman Kiss blogging about it as well. I'm sure you'll come up with a great solution, but ping me if you'd like to commiserate.
Monday, December 06, 2004 2:57:43 PM UTC
have a look at my solution in my soap.msmq transport [1].

overriding the Enqueue method you have a full control over reciver. The following code snippet is from my transport.

public override void Enqueue(SoapEnvelope message)
{
// get the receiver for this endpoint
SoapReceiver receiver = SoapReceivers.Receiver(_endpoint) as SoapReceiver;
if(receiver != null)
{
// process a message workflow through the pipeline to the endpoint handler
receiver.ProcessMessage(message);
}
else
throw new Exception(string.Format("Missing a receiver for endpoint={0}", _endpoint.Address.Value));
}

Note, that my transport supports a DTC transaction on the sender side and with small modification can be done also on the receiver side (using the SWC + Win2k3/XPSP2).

hth

Roman



[1] http://www.codeproject.com/useritems/SoapMSMQ.asp
Roman Kiss
Monday, December 06, 2004 3:04:43 PM UTC
sorry, I pick-up the old version. here is a correct one:

public override void Enqueue(SoapEnvelope message)
{
SoapReceiver receiver = null;


// get/create the receiver for this endpoint
if(SoapReceivers.Count > 0)
{
object val = SoapReceivers.Receiver(_endpoint);

if(val is SoapReceiver)
receiver = val as SoapReceiver;
else if(val is Type)
receiver = Activator.CreateInstance((Type)val) as SoapReceiver;
}

if(receiver != null)
{
// synchronous process message workflow through the pipeline to the endpoint handler
receiver.ProcessMessage(message);
}
else
throw new Exception(string.Format("Missing a receiver for endpoint={0}", _endpoint.Address.Value));
}
Roman Kiss
Comments are closed.