在IIS中使用WCF,在工作组模式下使用MSMQ

12

我一直在尝试使用WCF和MSMQ,但似乎无法使其正常工作。我已经通过使用WCF和服务引用来使客户端(向队列发送消息)正常工作。完成此操作的代码大致如下:

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

MsmqContractClient是在我添加服务引用时Visual Studio生成的代理。app.config中的端点指向一个msmqueue:

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

这个代码可以运行,消息已被发送到队列。

现在我正在尝试让服务实际工作起来,但是我一直收到以下错误:

 

绑定验证失败,因为绑定的MsmqAuthenticationMode属性设置为WindowsDomain,但MSMQ已安装并禁用了Active Directory集成。 通道工厂或服务主机无法打开。

我尝试过的方法有:

  • 赋予每个人(包括匿名登录)对队列的完全访问权限

  • 使用以下内容从配置文件中配置应用程序以使用特定绑定:

    <bindings>
      <netMsmqBinding>
         <binding name="MsmqBindingNonTransactionalNoSecurity" 
                  deadLetterQueue="Custom" 
                  exactlyOnce="false">
           <security mode="None" />
         </binding>
      </netMsmqBinding>
    </bindings>
    
    我尝试在IIS(7)中使用我的账户和管理员账户运行应用程序池,但是它一直试图让我相信我正在尝试使用WindowsDomain身份验证来运行它。 我已经将安全模式设置为none,并声明了我不想这样做,这让我困扰不已。
    目前,我的应用程序只是一个添加了WCF服务的WebForms ASP.NET站点。
    如果有人能指引我正确的方向,我将非常感激,因为我已经在解决这个问题上花费了太多时间。
    看起来配置被忽略或覆盖了。完整的错误信息:
    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
    

    我尝试使用 Reflector 弄清楚发生了什么,但似乎某种方式将 MsmqTransportBindingElement 传递到通道构建过程中,它确信必须使用 WindowsDomain 作为安全措施。但是,在我的配置文件中,我将安全性设置为 none。有任何想法,这种覆盖行为来自哪里吗?


    解决方案:

    一方面,我感到非常愚蠢,但另一方面,我认为有改进的空间。简而言之,我在服务元素的“name”属性中搞砸了值:

    <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>
    

    名称与我的客户端上相同,但是客户端生成了Visual Studio的绑定。我给它起了一个不同的名字(MsmqService),因此名称值为“MsmqService.MsmqService”。

    令我有些困扰的是,我没有收到任何关于我正在配置不存在的服务或者我正在使用服务默认配置的表示。如果框架至少能够在某处生成警告表明我正在使用默认设置,或提供打开某种形式的严格模式的选项,那将会非常好。无论如何,感谢您提供的所有信息,我还要再撞墙几次。

    是的,你现在可以指着我笑了;-)


1
你真是个传奇!我已经花了几个小时研究我的配置,才意识到我和你犯了完全一样的错误! - Darren Lewis
1
哈哈,谢谢我的失误和找出错误的过程能帮助到另一个开发者 :) - Erik van Brakel
我一直在努力解决问题,直到找到了答案。实际问题和错误信息之间是否有任何联系呢? - ravi
我也遇到了完全相同的问题。没有意识到我的服务名称是不正确的,导致了这个误导性的错误!+1 - ajawad987
4个回答

9
尝试以下设置... useActiveDirectory 默认应该为 false,但可以尝试。身份验证模式设置在传输本身上,因此msmqAuthenticationMode 应设置为“none”。msmqProtectionLevelclientCredentialType 听起来与此相关,因此我也加入了它们。
: )
<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>

我很担心去除所有安全措施... 如果您在域上,应安装带有Active Directory集成的MSMQ,或使用工作组方法来保护消息。

另外,请不要忘记,服务器和客户端的设置必须匹配。

希望对你有所帮助,
詹姆斯

对于持续更新感到抱歉,我的注意力似乎今天有点低
:P


当然,我同意在生产环境中移除所有安全性是不好的。但是为了简单演示这个功能的工作原理,我需要尽可能简化它的运行方式。现在我将尝试使用您的设置。 - Erik van Brakel
哎呀,还是不行。我要在另一台机器上试试,也许是我的环境的问题。提到安全应该关闭加1分哈;-) - Erik van Brakel
不得不花费很长时间才找到了这个,但是 netMsmqBinding 的模式可以在这里找到:http://msdn.microsoft.com/en-us/library/ms731380.aspx - James King
嗯,你能发布一下完整的客户端和服务器配置吗? - James King
1
在.NET 4.5.1中现在无法设置clientCredentialType="None"。 - huoxudong125
显示剩余4条评论

2

不确定这是否能解决您具体的问题,但Tom Hollander写了一篇非常好的三部分博客系列:

此外,由于Active Directory似乎是问题所在,您是否尝试告诉您的MSMQ绑定不使用AD?

<bindings>
  <netMsmqBinding>
     <binding name="MsmqBindingNonTransactionalNoSecurity" 
              deadLetterQueue="Custom" exactlyOnce="false"
              useActiveDirectory="false">   <== try this setting here!
        <security mode="None" />
     </binding>
  </netMsmqBinding>
</bindings>

更新的链接: 第一部分,https://dzone.com/articles/msmq-wcf-and-iis-getting-them- 第二部分,https://dzone.com/articles/msmq-wcf-and-iis-getting-them--0 第三部分,https://dzone.com/articles/msmq-wcf-and-iis-getting-them--1 - user2986756

2

当我们遇到这个问题时,在测试环境下<security mode="None">是有效的。

然而,在最终交付时,即使使用了这个方法也无法解决问题。最终,我们采用了另一种方法。

<security>
<transport
msmqAuthenticationMode="None"
msmqProtectionLevel="None"/>
</security>

1

Dennis van der Stelt提供了一个关于WCF + MSMQ的好样例。

您可能也会对MSDN上的这个问答感兴趣:

问:当我在工作组模式下运行使用默认绑定的示例时,似乎消息已发送但接收者从未收到。

答:默认情况下,消息使用需要Active Directory目录服务的MSMQ内部证书进行签名。在工作组模式下,因为没有可用的Active Directory,签名消息失败。所以消息会落入死信队列,并指示故障原因,例如“坏签名”。

解决方法是关闭安全性。这可以通过将Mode = None设置为在工作组模式下运行来实现。

另一种解决方法是从Transport属性获取MsmqTransportSecurity,并将其设置为Certificate,并设置客户端证书。

另一种解决方法是安装带有Active Directory集成的MSMQ。


我现在使用的方式基本上是将某些内容发送到服务器。这部分工作正常,消息最终进入队列(而不是死信队列)。 - Erik van Brakel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接