我有一个应用程序使用MSMQ进行某些事情的异步处理。托管*稳定* WCF MSMQ窗口服务的正确方法
我使用WCF将消息放入队列,并让WCF MSMQ侦听器(Windows服务)接收消息并处理它们。
我的问题是保持这种稳定。处理(例如)队列服务器(这是一个单独的盒子)的正确方法是什么?有一天发生了这种情况,服务只是坐在那里 - 没有例外,它只是停止接收消息。 我希望它在队列服务器出现故障时抛出异常,然后重新尝试连接到它,直到它可以。
我也注意到,在服务上执行“停止”通常会导致它挂起很长一段时间,然后才终止。
任何代码建议或批评将受到欢迎。很明显,我首先做了谷歌,但大多数例子显示我已经有了很多东西,我想让我的系统比那更强大。
目前我有这样的:
(注:IMyExampleServiceContract是我的WCF服务合同和QueueHandler就是实现它)
namespace xyz.MyExample.MSMQListener
{
/// <summary>
/// The class that handles starting and stopping of the WCF MSMQ Listener windows service.
/// It will respond to start and stop commands from within the windows services administration snap-in
/// It creates a WCF NetMsmqBinding that watches a particular queue for messaages defined by a contract
/// in the ServiceContracts project.
/// </summary>
public partial class MsmqListenerService : ServiceBase
{
/// <summary>
/// The WCF service host
/// </summary>
private ServiceHost _serviceHost;
/// <summary>
/// Defines the maximum size for a WCF message
/// </summary>
private const long MaxMessageSize = 1024 * 1024 * 1024; // 1 gb
/// <summary>
/// Defines the maximum size for a WCF array
/// </summary>
private const int MaxArraySize = 1024 * 1024 * 1024; // 1 gb
/// <summary>
/// The queue name
/// </summary>
private readonly string _queueName;
/// <summary>
/// The queue server
/// </summary>
private readonly string _queueServer;
/// <summary>
/// Initializes a new instance of the <see cref="MsmqListenerService"/> class.
/// </summary>
public MsmqListenerService()
{
InitializeComponent();
using (ConfigManager config = new ConfigManager())
{
_queueName = config.GetAppSetting("QueueName");
_queueServer = config.GetAppSetting("QueueServer");
}
}
/// <summary>
/// When implemented in a derived class, executes when a Start command is sent to the service by the Service Control Manager (SCM) or when the operating system starts (for a service that starts automatically). Specifies actions to take when the service starts.
/// <para>
/// The logic in this method creates a WCF service host (i.e. something that listens for messages) using the <see cref="IMyExampleServiceContract"/> contract.
/// The WCF end point is a NetMSMQBinding to the MyExample MSMQ server/queue.
/// It sets up this end point and provides a class to handle the messages received on it.
/// The NetMSMQBinding is a Microsoft WCF binding that handles serialisation of data to MSMQ. It is a ms proprietary format and means that the message on the queue
/// can only be read by a WCF service with the correct contract information.
/// </para>
/// </summary>
/// <param name="args">Data passed by the start command.</param>
protected override void OnStart(string[] args)
{
try
{
Logger.Write("MyExample MSMQ listener service started.", StandardCategories.Information);
Uri serviceUri = new Uri("net.msmq://" + QueueServer + QueueName);
NetMsmqBinding serviceBinding = new NetMsmqBinding();
serviceBinding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None;
serviceBinding.Security.Transport.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None;
serviceBinding.MaxReceivedMessageSize = MaxMessageSize;
serviceBinding.ReaderQuotas.MaxArrayLength = MaxArraySize;
//QueueHandler implements IMyExampleServiceContract
_serviceHost = new ServiceHost(typeof(QueueHandler));
_serviceHost.AddServiceEndpoint(typeof(IMyExampleServiceContract), serviceBinding, serviceUri);
_serviceHost.Open();
Logger.Write("MyExample MSMQ listener service completed OnStart method.", StandardCategories.Information);
}
catch (Exception ex)
{
ExceptionReporting.ReportException(ex, "DefaultExceptionPolicy");
throw;
}
}
/// <summary>
/// Gets the name of the queue to send to.
/// This is retrieved from the application settings under QueueName
/// </summary>
private string QueueName
{
get { return _queueName; }
}
/// <summary>
/// Gets the name of the queue server to send to.
/// This is retrieved from the application settings under QueueServer
/// </summary>
private string QueueServer
{
get { return _queueServer; }
}
/// <summary>
/// When implemented in a derived class, executes when a Stop command is sent to the service by the Service Control Manager (SCM). Specifies actions to take when a service stops running.
/// </summary>
protected override void OnStop()
{
if (_serviceHost != null)
{
_serviceHost.Close();
_serviceHost = null;
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
public static void Main()
{
//Code will have to be compiled in release mode to be installed as a windows service
#if (!DEBUG)
try
{
Logger.Write("Attempting to start queue listener service.", StandardCategories.Information);
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MsmqListenerService()
};
ServiceBase.Run(ServicesToRun);
Logger.Write("Finished ServiceBase.Run of queue listener service.", StandardCategories.Information);
}
catch (Exception e)
{
ExceptionReporting.ReportException(e, "DefaultExceptionPolicy");
throw;
}
#else
//This allows us to run from within visual studio
MsmqListenerService service = new MsmqListenerService();
service.OnStart(null);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
}
}
}
故障事件看起来很方便。我假设你相信如果MSMQ服务器失败,它不会进入这个状态? (因为你在推荐“ping”服务) “ping”服务听起来像是测试服务器可用性的一个很好的解决方法,我只是认为WCF中会有内置的东西来处理这个问题。 无论如何,我会尝试Faulted事件,所以谢谢指出我的方向。 – David 2009-09-28 08:57:28
说实话,我只是不知道,所以我推荐这两个选项:) – tomasr 2009-09-28 12:23:16