【问题标题】:MSMQ Application does not process queued messages when running as Windows ServiceMSMQ 应用程序在作为 Windows 服务运行时不处理排队的消息
【发布时间】:2014-10-22 15:40:09
【问题描述】:

这是一个直截了当的问题:

当作为标准程序运行时,我的应用程序行为正确。现在,当我将它作为 Windows 服务运行时,它不会处理其私有队列中的消息(使用 MSMQ)。

我尝试将服务作为我的用户帐户和本地服务运行。在这两种情况下,队列都只是填满了消息,没有一个消息被处理。

请注意,Windows 服务似乎运行正常:它关联的 Wcf 服务已打开并正在侦听。

为了确保这不是权限问题,我授予了我能想到的每个组/用户的完全访问权限。这是处理队列创建和主机初始化的代码。请注意,在这次尝试中,我将用户的本地化命名更改为他们的英文对应名称。另请注意,我尝试在所有可能的帐户下安装该服务:我自己以管理员身份运行、LocalSystem、LocalService 和 NetworkService。

namespace MachineCommunication.ZeissCMMAdapter
{
    partial class ZeissService : ServiceBase
    {
        public ZeissService()
        {
            InitializeComponent();
        }
        ServiceHost _host = null;

        protected override void OnStart(string[] args)
        {
            Trace.WriteLine("Starting ZeissAdapter Service...");
            string adapterQueueName = ConfigurationManager.AppSettings["adapterQueueName"];

            // Create the transacted MSMQ queue if necessary.

            MessageQueue adapterQueue;
            if (!MessageQueue.Exists(adapterQueueName))
            {
                Trace.WriteLine("Creating Queue: " + adapterQueueName);
                adapterQueue = MessageQueue.Create(adapterQueueName, true);
                adapterQueue.SetPermissions(@"NT AUTHORITY\System", MessageQueueAccessRights.FullControl);
                adapterQueue.SetPermissions(@"ANONYMOUS LOGON", MessageQueueAccessRights.FullControl);
                adapterQueue.SetPermissions(@"Everyone", MessageQueueAccessRights.FullControl);
                adapterQueue.SetPermissions(@"my_user", MessageQueueAccessRights.FullControl);
            }
            else
            {
                Trace.WriteLine("Queue already exists: " + adapterQueueName);
            }


            string machineQueueName = ConfigurationManager.AppSettings["machineQueueName"];
            MessageQueue machineQueue;
            // Create the transacted MSMQ queue if necessary.
            if (!MessageQueue.Exists(machineQueueName))
            {
                Trace.WriteLine("Creating Queue: " + machineQueueName);
                machineQueue = MessageQueue.Create(machineQueueName, true);
                machineQueue.SetPermissions(@"NT AUTHORITY\System", MessageQueueAccessRights.FullControl);
                machineQueue.SetPermissions(@"ANONYMOUS LOGON", MessageQueueAccessRights.FullControl);
                machineQueue.SetPermissions(@"Everyone", MessageQueueAccessRights.FullControl);
                machineQueue.SetPermissions(@"my_user", MessageQueueAccessRights.FullControl);
            }
            using (_host = new ServiceHost(typeof(ZeissAdapterService)))
            {
                _host.Open();
                Console.WriteLine("The service is ready");
                Console.WriteLine("Press <Enter> to stop the service.");
                Console.ReadLine();
            }
        }

        protected override void OnStop()
        {
            try
            {
                Trace.WriteLine("Shutting down Class-A E-mail Service...");
                if (_host != null && _host.State == CommunicationState.Opened)
                {
                    _host.Close();
                    _host = null;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Something went wrong closing the ServiceHost : " + ex.Message);
                throw;
            }
        }
    }
}

这是我的服务的完整 app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <!-- use appSetting to configure MSMQ queue name -->
    <add key="adapterQueueName" value=".\private$\Zeiss/ZeissAdapterService"/>
    <add key="machineQueueName" value=".\private$\Zeiss/ZeissMachineService"/>
  </appSettings>
  <system.serviceModel>
    <services>
      <service name="MachineCommunication.ZeissCMMAdapter.ZeissAdapterService" behaviorConfiguration="DefaultBehavior">
        <!-- Define NetMsmqEndpoint -->
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:12000/" />
          </baseAddresses>
        </host>
        <endpoint address="net.msmq://localhost/private/Zeiss/ZeissAdapterService" binding="netMsmqBinding" bindingConfiguration="TransactedBinding" contract="MachineCommunication.Contracts.AdapterContracts.IAdapterService"/>
        <endpoint address="net.msmq://localhost/private/Zeiss/ZeissMachineService" binding="netMsmqBinding" bindingConfiguration="TransactedBinding" contract="MachineCommunication.MachineTypeSpecificInfrastructure.ZeissInfrastructure.IZeissListener"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netMsmqBinding>
        <binding name="TransactedBinding" deadLetterQueue="System" useActiveDirectory ="False" useMsmqTracing="True">
          <security mode="None">
            <message clientCredentialType="None"/>
            <transport msmqAuthenticationMode="None" msmqProtectionLevel="None"  />
          </security>
        </binding>
      </netMsmqBinding>
    </bindings>
  </system.serviceModel>
  <system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="sdt"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "SdrConfigExample.e2e" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

这里有一个快速重现问题的方法:在 MSDN 上分发的 WCF 代码示例中,有一个涉及客户端/服务器设置的双向 MSMQ 示例;我修改了这个示例以将服务器安装为 Windows 服务。如果您运行服务器并启动客户端,则所有消息都应该最终停留在服务器的队列中,而无需进一步处理。这是该示例的链接:

https://drive.google.com/file/d/0B5-APK5bfBpMUGU2cW5iaV9ybnM/edit?usp=sharing

【问题讨论】:

    标签: c# wcf windows-services msmq


    【解决方案1】:

    几个想法。

    1. 尝试让服务以您的身份运行,但以交互式用户身份运行。

    2. 配置文件是否在正确的文件夹中?当您运行 Windows 服务时,它会将 appdomain 的基本目录默认为 %SYSDIR%(您可以在 OnStart 中覆盖)

    除此之外,我建议添加跟踪器并记录实际发生的活动或使用调试器附加到进程。

    如果您需要覆盖 BaseDir。

    System.IO.Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory)
    

    【讨论】:

      【解决方案2】:

      很可能是由于权利。在网络服务下运行的 Windows 服务无权访问 MSMQ 队列。您必须提供访问权限。

      在开发计算机或测试服务器上尝试这个,而不是在生产环境中。尝试为您正在与之交谈的队列授予“所有人”权限,并在具有管理权限的用户下运行该服务。如果它开始处理消息,你就会知道这是一个版权问题。

      然后缩小范围。删除越来越多的权限,看看它是否仍然有效。

      还可以尝试一些日志记录以查看服务是否正确启动。尝试加载配置设置并记录它们。尝试使用 Sysinternals DebugView 查看它们或将它们记录到文件中。如果服务正在记录到文件并且您看到记录了正确的配置项值,您就会知道那里没有问题。

      我还看到人们认为他们应该访问 queuename/service.svc 队列。但这仅适用于 IIS 托管的 WCF 服务。

      如果我是你,请发布整个配置。你没有提供很多信息,我也看不出配置有什么问题。

      【讨论】:

      • 对上面代码中的本地化用户/组感到抱歉。实际上,我确实授予了对“所有人”(Tout le monde)、网络服务(SERVICE RÉSEAU)、本地服务等的完全访问权限。我还尝试以我自己的用户(具有管理员权限)的身份运行该服务,作为本地服务,作为网络服务的本地系统。队列始终保持静止(我确实删除了它,并在每次尝试之前为我能想到的每个帐户分配了完全权限)。我将编辑我的帖子以包含更多可能导致该问题的代码。感谢您的回复!
      • 如果您以编程方式将绑定设置为 MSMQ 会怎样?我感觉它不是使用 App.config 来通过 MSMQ 监听,而是使用默认值来监听 Http 我忘记了确切的语法是什么,但它类似于:_host.AddServiceEndpoint(typeof(MachineCommunication.MachineTypeSpecificInfrastructure. ZeissInfrastructure.IZeissListener), new NetTcpBinding(), "SomeName");而且在同一个 MSMQ 队列上不可能有两个侦听器。你们都应该为他们提供自己的队列。从配置中删除一个以进行测试。
      【解决方案3】:

      真正的问题只是我试图通过 console.readline 阻止服务线程退出——这(显然可能)在将应用程序作为服务运行时不适用。我的错,我真的很抱歉首先问了这个问题。无论如何感谢所有的答案尝试。

      【讨论】:

        猜你喜欢
        • 2012-04-12
        • 2010-09-27
        • 1970-01-01
        • 1970-01-01
        • 2013-10-05
        • 1970-01-01
        • 2012-12-24
        • 2012-04-12
        • 1970-01-01
        相关资源
        最近更新 更多