WCF in IIS, using MSMQ in workgroup mode
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 ;-)
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
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>
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>
Dennis van der Stelt provide a good sample on WCF + MSMQ.
You may also be interested in this Q/A on MSDN:
Q: When I run the sample that uses a default binding in workgroup mode, messages seem to get sent but are never received by the receiver.
A: By default, messages are signed using an MSMQ internal certificate that requires the Active Directory directory service. In workgroup mode, because Active Directory is not available, signing the message fails. So the message lands in the dead-letter queue and failure cause, such as “Bad signature”, is indicated.
The workaround is to turn off security. This is done by setting Mode = None to make it work in workgroup mode.
Another workaround is to get the MsmqTransportSecurity from the Transport property and set it to Certificate, and set the client certificate.
Yet another workaround is to install MSMQ with Active Directory integration.
精彩评论