Workflow with MSMQ Bindings on WAS

Was helping out a developer to troubleshoot why his Workflow service is not picking-up messages from a Message Queue when hosted in WAS (Windows Process Activation Service) and I found out something interesting. All the configurations on IIS/WAS and MSMQ were verified to be correct but things just don't work.

I created a Workflow service with the following service endpoint configuration to reproduce the problem:

<endpoint name="basicHttpWorkflowService" 
          address="msmq.formatname:DIRECT=OS:.\private$\wfmsmq"
          binding="msmqIntegrationBinding" 
          bindingConfiguration="msmqIntegrationBinding"
          contract="IWFMsmqWorkflowService" />

[Note: I am using msmqIntegrationBinding because the system needs to interop with older non-WCF queue base applications.]

Turns out that it works without any issues on a console host but does not work when hosted in WAS. After some digging, I finally understood why and here is the MSDN article about it.

I have to admit that it took me a while to understand that article. Basically, it is trying to say that when hosting in WAS, we can't actually use the above address naming convention because WAS intelligently prefixes base URI to our addresses. If you look at the configuration for WAS hosting, it looks something like this:

<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
  <serviceActivations>
    <add factory="System.ServiceModel.Activities.Activation.WorkflowServiceHostFactory" 
         relativeAddress="./WFMsmqWorkflowService.svc" 
         service="WFMsmq.Workflows.WFMsmqWorkflowService" />
  </serviceActivations>
</serviceHostingEnvironment>
<services>
  <service name="WFMsmqWorkflowService" behaviorConfiguration="WorkflowServiceBehavior">
    <endpoint name="basicHttpWorkflowService" 
              address="" 
              binding="msmqIntegrationBinding" 
              bindingConfiguration="msmqIntegrationBinding" 
              contract="IWFMsmqWorkflowService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<bindings>
  <msmqIntegrationBinding>
    <binding name="msmqIntegrationBinding" exactlyOnce="false" >
      <security mode="None">
        <transport msmqAuthenticationMode="None" msmqProtectionLevel="None"/>
      </security>
    </binding>
  </msmqIntegrationBinding>
</bindings>

The address is usually empty when hosting in WAS. If we are using http bindings, the URL address will be: 
http://[servername]/[Web Application or virtual directory]/[Service Name].svc 

in my case it will be:  
http://localhost/wfmsmqTest/WFMsmqWorkflowService.svc

Therefore, when hosted under msmq bindings, the URL will be either
net.msmq://[servername]/[Web Application or virtual directory]/[Service Name].svc 

or
msmq.formatname://[servername]/[Web Application or virtual directory]/[Service Name].svc 

in this case, it will be:
msmq.formatname://localhost/wfmsmqTest/WFMsmqWorkflowService.svc

According to the documentation, the MSMQ Activation Service does not differentiate between public or private queues so, it should not matter where our queue is.

To allow the Workflow Service to work, we need to create a queue with the name 
wfmsmqTest/WFMsmqWorkflowService.svc

Which means, if you are testing it using a console host, the address value will be
address="msmq.formatname:DIRECT=OS:.\private$\wfmsmqTest/WFMsmqWorkflowService.svc"

Warning: Beware of the / and \

To see the Workflow service work, send a message to the queue and you should be able to see that the message will be processed.

No comments:

Post a Comment

Popular Post