Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF in IIS, using MSMQ in workgroup mode

Tags:

c#

iis

wcf

msmq

I've been trying out MSMQ with WCF, but I can't seem to get it to work properly. I've got the client (which sends messages to the queue) working, by using WCF and a service reference. The code that does this is more or less this:

static void Main(string[] args)
{
    var client = new MsmqServiceReference.MsmqContractClient();
    client.SendMessage("TEST");
    client.Close();
    Console.ReadKey();
}

Where MsmqContractClient is a proxy generated by visual studio when I add a service reference. The endpoint in the app.config is pointing to a msmqueue:

<client>
  <endpoint 
    address="net.msmq://localhost/private/MsmqService/MsmqService.svc"
    binding="netMsmqBinding"  
    bindingConfiguration="MsmqBindingNonTransactionalNoSecurity"
    contract="MsmqServiceReference.IMsmqContract" name="MsmqService" />
</client>

This works, messages are being posted to the queue.

Now I am trying to actually get the service to work, but I keep getting this error:

Binding validation failed because the binding's MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.

Things I've tried are:

  • give everyone full access (including anonymous logon) to the queue

  • configuring the app to use a specific binding from the config file using:

    <bindings>
      <netMsmqBinding>
         <binding name="MsmqBindingNonTransactionalNoSecurity" 
                  deadLetterQueue="Custom" 
                  exactlyOnce="false">
           <security mode="None" />
         </binding>
      </netMsmqBinding>
    </bindings>
    
  • I tried running the app pool in IIS (7) under my own account and administrator account

What stumps me is that it keeps trying to convince me that I am trying to run it with WindowsDomain authentication. I stated that I DIDN'T want to do that with the security mode set to none, right?

My app at the moment is simply a webforms asp.net site with a WCF service added to it.

If someone could at least point me into the right direction I'll be very grateful, as I've spent too much time on this already.


It seems as if the configuration is being ignored, or overridden. The full error message:

WebHost failed to process a request.
 Sender Information: System.ServiceModel.Activation.HostedHttpRequestAsyncResult/63721755
 Exception: System.ServiceModel.ServiceActivationException: The service '/MsmqService/MsmqService.svc' cannot be activated due to an exception during compilation.  The exception message is: Binding validation failed because the binding's MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.. ---> System.InvalidOperationException: Binding validation failed because the binding's MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.
   at System.ServiceModel.Channels.MsmqVerifier.VerifySecurity(MsmqTransportSecurity security, Nullable`1 useActiveDirectory)
   at System.ServiceModel.Channels.MsmqVerifier.VerifyReceiver(MsmqReceiveParameters receiveParameters, Uri listenUri)
   at System.ServiceModel.Channels.MsmqTransportBindingElement.BuildChannelListener[TChannel](BindingContext context)
   at System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener[TChannel]()
   at System.ServiceModel.Channels.MessageEncodingBindingElement.InternalBuildChannelListener[TChannel](BindingContext context)
   at System.ServiceModel.Channels.BinaryMessageEncodingBindingElement.BuildChannelListener[TChannel](BindingContext context)
   at System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener[TChannel]()
   at System.ServiceModel.Channels.Binding.BuildChannelListener[TChannel](Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters)
   at System.ServiceModel.Description.DispatcherBuilder.MaybeCreateListener(Boolean actuallyCreate, Type[] supportedChannels, Binding binding, BindingParameterCollection parameters, Uri listenUriBaseAddress, String listenUriRelativeAddress, ListenUriMode listenUriMode, ServiceThrottle throttle, IChannelListener& result, Boolean supportContextSession)
   at System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result)
   at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost)
   at System.ServiceModel.ServiceHostBase.InitializeRuntime()
   at System.ServiceModel.ServiceHostBase.OnBeginOpen()
   at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open()
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath)
   --- End of inner exception stack trace ---
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result)
 Process Name: w3wp
 Process ID: 5660

I tried figuring out what happens using Reflector, but it simply seems that somehow a MsmqTransportBindingElement is passed into the channel building process, which is convinced it has to use WindowsDomain as a security measure. However, I have security set to none in my config file. Any ideas on where this override behavior comes from?


Resolution:

I feel really stupid on one hand, but I feel there's room for improvement on the other hand. The short version is that I messed up the value in the 'name' attribute on the service element:

<services>
  <service name="WcfService.MsmqService">
    <!--        <endpoint binding="mexHttpBinding" contract="IMetadataExchange" />-->
    <endpoint name="msmq" 
            address="net.msmq://localhost/private/MsmqService/MsmqService.svc"
            binding="netMsmqBinding" 
            bindingConfiguration="NoSecurity"
            contract="WcfService.IMsmqContract" />
  </service>
</services>

The name was the same as on my client, however, the client had bindings generated by visual studio. I gave it a different name (MsmqService), so the name value was 'MsmqService.MsmqService'.

What kinda bothers me is that I didn't get any warning whatsoever that I was configuring a non-existing service, or any indication I am using the default configuration for the service. It would be really nice if the framework would at least generate a warning somewhere that I am using defaults, or an option to turn on some form of strict mode. Either way, thanks for all your input, and I am going to bang my head against the wall a few more times.

And yes, you may now point and laugh ;-)

like image 413
Erik van Brakel Avatar asked Dec 20 '10 19:12

Erik van Brakel


3 Answers

Try these settings... useActiveDirectory should be false by default, but try it. The authentication mode is set on the transport itself, so msmqAuthenticationMode should be set to 'none'. msmqProtectionLevel and clientCredentialType sound relevant, so I threw them in there, too
: )


<bindings>
  <netMsmqBinding>
     <binding name="MsmqBindingNonTransactionalNoSecurity" 
          deadLetterQueue="Custom"
          useActiveDirectory="false" 
          exactlyOnce="false">
       <security mode="None">
         <transport 
            msmqAuthenticationMode="None"
            msmqProtectionLevel="None"
            clientCredentialType="None"/>
       </security>
     </binding>
  </netMsmqBinding>
</bindings>

I'd be concerned about removing all the security, however... if you're on a domain, you should install MSMQ with Active Directory Integration, or use Workgroup methods of securing the messages.

Also, don't forget, the settings for the server and client have to match.

HTH,
James

Sorry for the continual updates, my attention to details seems to be a bit low today
: P

like image 153
James King Avatar answered Oct 24 '22 07:10

James King


Not sure if this is going to solve your concrete problem here, but there's a really good three-part blog post series by Tom Hollander:

  • MSMQ, WCF and IIS: Getting them to play nice (part 1 of 3)
  • MSMQ, WCF and IIS: Getting them to play nice (part 2 of 3)
  • MSMQ, WCF and IIS: Getting them to play nice (part 3 of 3)

Also, since the Active Directory stuff seems to be the problem, have you tried to tell your MSMQ binding to not use AD ??

<bindings>
  <netMsmqBinding>
     <binding name="MsmqBindingNonTransactionalNoSecurity" 
              deadLetterQueue="Custom" exactlyOnce="false"
              useActiveDirectory="false">   <== try this setting here!
        <security mode="None" />
     </binding>
  </netMsmqBinding>
</bindings>
like image 2
marc_s Avatar answered Oct 24 '22 06:10

marc_s


When we faced the issue <security mode="None"> worked in the test environment.

During final delivery , even that didn't work.. Finally this one worked

<security>
<transport
msmqAuthenticationMode="None"
msmqProtectionLevel="None"/>
</security>
like image 2
Ananth Avatar answered Oct 24 '22 07:10

Ananth