2015-08-17 65 views
4

我有一个长期运行的WCF服务托管在Windows服务中。我有一个服务库,其目的是报告服务的状态。我怎样才能从服务库的实例中获取服务的实例?WCF:如何从服务库的实例内部到达服务的实例?

为了说明,我创建了一个服务,记录它开始的时间,并公开报告运行时间的方法。服务库需要能够调用服务的ElapsedSeconds()方法,因此库需要对正在运行的服务进行引用。

我想我可以使用OperationContext.Current。这里是我的服务库班:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.ServiceModel; 
using System.Text; 
using System.Threading.Tasks; 

namespace TimerService 
{ 
public class TimerServiceLib : ITimerServiceLib 
{ 
    TheTimerService m_timerService; 

    public TimerServiceLib() 
    { 
     var currentContext = OperationContext.Current; 
     var instanceContext = currentContext.InstanceContext; 
     m_timerService = (TheTimerService)instanceContext.GetServiceInstance(); 
    } 

    public double SecondsSinceStart() 
    { 
     return m_timerService.ElapsedSeconds(); 
    } 
} 
} 

但调用GetServiceInstance()创建TimerServiceLib()的一个新实例,当然这给了我一个无限循环。那么,做到这一点的正确方法是什么?

这里是我的服务类,实际上是在一个控制台应用程序被托管:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceModel; 
using System.ServiceModel.Description; 
using System.ServiceProcess; 
using System.Text; 
using System.Threading.Tasks; 

namespace TimerService 
{ 
public partial class TheTimerService : ServiceBase 
{ 
    private DateTime m_startTime; 
    ServiceHost m_svcHost; 

    public TheTimerService() 
    { 
     InitializeComponent(); 
     Init(); 
     m_startTime = DateTime.Now; 
    } 

    public double ElapsedSeconds() 
    { 
     return (DateTime.Now - m_startTime).TotalSeconds; 
    } 

    protected override void OnStart(string[] args) 
    { 
    } 

    protected override void OnStop() 
    { 
    } 

    public void Init() 
    { 
     if (m_svcHost != null) 
     { 
      m_svcHost.Close(); 
     } 

     string httpAddress = "http://localhost:1234/TimerService"; 
     string tcpAddress = "net.tcp://localhost:1235/TimerService"; 

     Uri[] adrbase = { new Uri(httpAddress), new Uri(tcpAddress) }; 
     m_svcHost = new ServiceHost(typeof(TimerServiceLib), adrbase); 

     ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior(); 
     m_svcHost.Description.Behaviors.Add(mBehave); 

     var debugBehavior = m_svcHost.Description.Behaviors.Find<ServiceDebugBehavior>(); 
     debugBehavior.IncludeExceptionDetailInFaults = true; 

     BasicHttpBinding httpBinding = new BasicHttpBinding(); 
     m_svcHost.AddServiceEndpoint(typeof(ITimerServiceLib), httpBinding, httpAddress); 
     m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), 
            MetadataExchangeBindings.CreateMexHttpBinding(), "mex"); 
     NetTcpBinding tcpBinding = new NetTcpBinding(); 
     m_svcHost.AddServiceEndpoint(typeof(ITimerServiceLib), tcpBinding, tcpAddress); 
     m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), 
            MetadataExchangeBindings.CreateMexTcpBinding(), "mex"); 

     m_svcHost.Open(); 

     // SimShopServiceLib.m_shop = new CSimShopManager(); 
    } 

} 

}

+1

可能重复[如何从运行Windows服务调用方法](http://stackoverflow.com/questions/1979016/how-to-call-method-from-running-windows-service) –

+0

可能您应该移动将时间码输入到Windows Service类中。 – usr

回答

1

你可以这样来做:

首先,修改TimerServiceLib做的构造TheTimerService

public class TimerServiceLib : ITimerServiceLib 
{ 
    private readonly TheTimerService m_timerService; 

    public TimerServiceLib(TheTimerService theTimerService) 
    { 
     m_timerService = theTimerService; 
    } 

    public double SecondsSinceStart() 
    { 
     return m_timerService.ElapsedSeconds(); 
    } 
} 

然后,在创建ServiceHost时,在您的Init()中,首先实例化您的服务并传递TheTimerService。由于您正在您的Windows服务内部创建ServiceHost,因此您可以通过TheTimerService

Uri[] adrbase = { new Uri(httpAddress), new Uri(tcpAddress) }; 
var timerServiceLib = new TimerServiceLib(this) 
m_svcHost = new ServiceHost(timerServiceLib , adrbase); 

有关在您的服务中传递对象的更多详细信息,请参阅此link

免责声明:上述代码未经测试。

+0

非常感谢您的回答。我不认为我确实遵循了这一点,但链接给了我答案。我将我的TimerServiceLib类标记为单例([ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)])。然后,在TheTimerService.Init()中,我做了这个改变: TimerServiceLib theServiceLib = new TimerServiceLib(); // m_svcHost = new ServiceHost(typeof(TimerServiceLib),adrbase); m_svcHost = new ServiceHost(theServiceLib,adrbase); –

+0

我对StackOverflow评论规则不满意,例如5分钟后无法编辑评论。下面是我想如何重写上述评论: 我把开始时间放在TimerServiceLib类中,并标记为单例。在TheTimerService.Init()中,我实例化了一个TimerServiceLib对象,以便设置开始时间。 我认为这与你的建议相反。你的建议可以让我保留它所属的TheTimeService中的重要逻辑。我会尝试这种方式。 –