1

I have a MVC-app that has a controller with an action that is supposed to expose data from the latest message in a queue (msmq). I have added a private queue on my local machine. I want the application to automatically receive a message from the queue when one is added. For this i am using msmqIntegrationBinding on a WCF-service that has been added to the application. The method that takes the message in the contract i then supposed to save the message in the application cache so that it can be accessed when a client asks for the latest data.

The challenge I now face is that when I add a message to the queue, it's not being picked up by the WCF-service. I need guidance at what I might be doing wrong or feedback on my approach. Please help.

The following is the endpoint-config for the WCF-service:

<bindings>
<msmqIntegrationBinding>
  <binding name="MsmqBinding">
    <security mode="None" />
  </binding>
</msmqIntegrationBinding>
</bindings>

<services>
  <service name="TestApp.Web.Service.QueueMessageReceiver">
    <endpoint address="msmq.formatname:DIRECT=OS:.\private$\testsmessagequeue"
                      binding="msmqIntegrationBinding"
                      bindingConfiguration="MsmqBinding"
                      contract="TestApp.Web.Service.IQueueMessageReceiver" />
  </service>
</services>

And the following code is from the QueueMessageReceiver.cs WCF-service:

public class QueueMessageReceiver : IQueueMessageReceiver
{
    private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(ScrewInfoModel));

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void PutScrewInfoMessage(System.ServiceModel.MsmqIntegration.MsmqMessage<System.Xml.XmlDocument> msg)
    {
        CacheScrewInfoModelFromScrewInfoXmlDoc(msg.Body);
    }

    private static void CacheScrewInfoModelFromScrewInfoXmlDoc(XmlNode screwInfoXmlDoc)
    {
        var reader = new StringReader(screwInfoXmlDoc.InnerXml);
        var screwInfoModel = (ScrewInfoModel)Serializer.Deserialize(reader);
        Common.Utils.CacheScrewInfo(screwInfoModel);
    }
}

And here is the Interface for the WCF:

[ServiceContract]
public interface IQueueMessageReceiver
{
    [OperationContract(IsOneWay = true, Action = "*")]
    void PutScrewInfoMessage(MsmqMessage<XmlDocument> msg);
}
tom redfern
  • 30,562
  • 14
  • 91
  • 126
Spetastium
  • 205
  • 3
  • 12

1 Answers1

0

Try changing your operation contract to

void PutScrewInfoMessage(MsmqMessage<string> msg);

It's possible that the WCF stack is having difficulty with the deserialization to XmlDocument.

UPDATE

Things to try:

  1. Make suer your queue "testsmessagequeue" have the correct permissions set. In this case the service account running the app pool hosting your controller needs to have the "Receive Message" permissions set.

  2. Enable MSMQ logging (if you're on windows 2008 server or windows 7 and above) which can be found in Event Viewer under: Applications and Services Logs -> Microsoft -> Windows -> MSMQ -> End2End. This will capture everything that happens in MSMQ including any errors.

  3. Try making the queue transactional (if it not already). This will ensure that an error condition will exist on message non-delivery.

  4. Enable WCF tracing on your service endpoint to see any specific WCF errors happening with the dequeuing of the message.

UPDATE 2

I think the problem is queue permissions. Your app pool is running under the user ApplicationPoolIdentity (if it's running under the .net 4.0 app pool). The user which corresponds to this identity is called DefaultAppPool. You need to give this user receive message permissions on the queue. To select this user search for a local account called IIS AppPool\DefaultAppPool in the Select Users dialogue.

enter image description here

UPDATE 3

It just struck me that IIS is not an appropriate hosting container for a queue listener. The reason for this is that the app pool unloads after a period of inactivity. This is controlled by IIS and is not configurable. (see here)

I think you should create a new hosting container in a windows service (you can use a console host to spike this) to host the queue endpoint. The windows service will run under an actual service account so granting permissions will be less complicated.

This service can write either write directly into the cache, or if this is not possible, should write to a DB where the website controller can refresh the cache from.

Does this make sense?

UPDATE 4

Poison message means that the message cannot be dequeued because of some problem with it. Check the system queue called Transactional Dead Letter Queue and see if your message is in there.

Community
  • 1
  • 1
tom redfern
  • 30,562
  • 14
  • 91
  • 126
  • I changed the contract to what you suggested and redeployed to my local IIS and added a message to the queue. I remained on the queue. Am i suppose to do some specific configuration in the IIS or app-pool? – Spetastium Jul 24 '12 at 09:13
  • Thank you for this answer. I have tried to set the permissions on the QUEUE to Receive Messages but i still doesn't work. Do i need to set the same permissions on the identity that the app-pool is using? The app-pool is using "ApplicationPoolIdentity", how do i set the permissions for that? – Spetastium Jul 24 '12 at 11:32
  • I changed the queue-adress from "msmq.formatname:DIRECT=OS:.\private$\testsmessagequeue" to "msmq.formatname:DIRECT=OS:LEIA\private$\testsmessagequeue" (Where Leia is my machine-name) and it worked. The message doesn't remain on the queue. The problem I am having now is that the message-object is not stored in the application cache. I have tried using both XmlDocument and string now. Any suggestions? – Spetastium Jul 24 '12 at 11:42
  • Yes I did and according to the log the messages are both placed in the queue and read. I implemented log4net and the WCF should log an entry everytime it receives a message, but i doesnt. The strange thing is that when i add a message to the queue it disapears moment after and i can read about it being placed in the queue and read in the MSMQ\End2End-log. – Spetastium Jul 24 '12 at 13:36
  • In answer to your previous question the account called "ApplicationPoolIdentity" which is running your IIS app pool needs to be given permission on the queue. Are you using transactional queue? – tom redfern Jul 24 '12 at 13:39
  • The user "ASP .NET v4.0" has been added with permissions on the queue. I am using a transactional queue, yes. I think i am, how do i know? – Spetastium Jul 24 '12 at 13:43
  • If you look at the queue properties it will tell you if it is transactional – tom redfern Jul 24 '12 at 13:44
  • The queue is transactional. Does that mean I have to configure the enpoint differently or what does it mean? – Spetastium Jul 24 '12 at 13:49
  • Thank you for the latest update! I seem to be one step closer. Now I have the following scenario: Message is added to the queue as usual but never picked up by the wcf. Though when I open the wcf in the browser the wcf seems to be "activated" and all the messages added after that is somehow read and does not remains in the queue and the log-entries by log4net is never written as well. Any thoughts? – Spetastium Jul 24 '12 at 14:06
  • Scratch that last one. The message disapears from the queue and i get event-id 1 followed by 5 followed by 2 in the End2End-log. – Spetastium Jul 24 '12 at 14:18
  • But the contract is never invoked. The queue is only read after I visited the wcf in the browser once first. – Spetastium Jul 24 '12 at 14:25
  • I have now successfully implemented WCF tracing (Which i hadn't before) and the tracelog says that a poisonous message resultet in an exception. What does "poison message" means and how do i handle it? Does this mean that the contract successfully receives the message but an error occurs on the wcf-side? – Spetastium Jul 24 '12 at 14:38
  • I cannot access the dead letter queues. They seem to be empty. There are a red dot with a white cross over the icon though. – Spetastium Jul 24 '12 at 14:51
  • I looked in the poison sub queue and thats where they went. I solved i by checking the "Authenticated"-box in the prefs for the queue. The queue is read by the service but the contract is never invoked. This question is answered and my new problem doesn't belong here so i wrote another one more specific for this. http://stackoverflow.com/questions/11645131/msmq-message-is-put-on-queue-and-disapears-but-is-never-picked-up-by-service-co – Spetastium Jul 25 '12 at 08:30