我有一个必须始终启动的WCF服务,因此由Windows服务托管。我的Windows服务模型具有简单的启动代码:
HostService:
public void StartService()
{
if (_hostController.Status != ServiceControllerStatus.Stopped && _hostController.Status != ServiceControllerStatus.StopPending)
{
var msg = string.Format("Service '{0}' must be in status '{1}' or '{2}' to accept a 'Start' command.",
HostResources.ServiceName, ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceStatusControl);
}
try
{
_hostController.Start();
}
catch (Exception ex)
{
if (ex is Win32Exception || ex is InvalidOperationException)
{
throw new HostServiceException(string.Format("'{0}' failed to respond properly to a 'StartService` command: '{1}'", _hostController.ServiceName, ex.Message), ex);
}
throw;
}
try
{
_hostController.WaitForStatus(ServiceControllerStatus.Running, _waitForStatusTimeout);
}
catch (TimeoutException tx)
{
throw new HostServiceException(string.Format("{0} did not start respond after {1} seconds and the 'Start' command timed out.", _hostController.ServiceName, _waitForStatusTimeout.TotalSeconds), tx);
}
if (ServiceControllerStatus.Running != _hostController.Status)
{
throw new HostServiceException(string.Format("The 'StartService' command for '{0}' failed. The Service has a status of '{1}'.", _hostController.ServiceName, _hostController.Status));
}
}
我的WCF服务甚至更简单的启动代码:
SchedulerService:
public void Start()
{
_isBusy = false;
var interval = _config.Settings.ServicePollingInterval * 1000;
_pollTimer = new Timer(interval);
_pollTimer.Enabled = true;
_pollTimer.Elapsed += PollTimerElapsed;
_pollTimer.Start();
Status = SchedulerServiceStatus.Running;
var msg = string.Format("'{0}' started with the timer set for {1} second{2} intervals.", SchedulerResources.ServiceName, _pollTimer.Interval / 1000, _pollTimer.Interval / 1000 > 1 ? "s" : "");
_logger.Info(msg);
StatusChanged(this, new SchedulerStatusChangeEventArgs(Status, msg));
}
这是我的视图模型中的代码,因为只有它可以启动Windows服务,它才会启动WCF服务:
SchedulerViewModel:
private void ExecuteStart()
{
if (_hostModel.ServiceStatus != ServiceControllerStatus.Running)
{
_logger.Warn("The '" + _hostModel.ServiceName + "' host service is not running. The '" + GetType().Name + "' will attempt to start it.");
try
{
_hostModel.StartService();
}
catch (Exception ex)
{
var msg = string.Format("The '{0}' could not start the '{1}' host service: {2}", GetType().Name, _hostModel.ServiceName, ex.Message);
_logger.Error(msg, ex);
throw new HostServiceException(msg, HostServiceException.HostServiceExceptionCategory.ServiceController, ex);
}
}
try
{
_scheduler.Start();
}
catch (Exception ex)
{
throw new SchedulerServiceException(ex.Message, SchedulerServiceException.SchedulerServiceExceptionCategory.SchedulerControl, ex);
}
SchedulerStatus = _scheduler.Status;
CommandsCanExecuteChanged();
}
现在这确实不是视图逻辑,但它也不是业务逻辑;更像是家务:如果开启供水,我只能使用洗衣机。现在我并没有真正看到需要一个只有HostModel
和SchedulerService
实例的全新模型,只是为了这个决定。陪审团对我目前的安排有什么看法?
答案 0 :(得分:0)
我会将所有代码推送到另一个服务后面并通过接口将其注入到VM中,我这样做是因为我假设WCF通过事件公开状态并且你想在UI中显示它。如果你把它推到另一个服务之后,允许将暴露状态“塑造”成一个更适合在VM中使用的以UI为中心的模型。
如果你这样做了,从虚拟机的角度来看,所有它都会知道'start \ stop'方法和一个事件处理程序 - 然后将实现抽象掉,并通过模拟很容易地测试VM。 / p>
为了更进一步,我会考虑使用Reactive扩展而不是CLR事件来传达服务中的状态更改。