2015-08-17 109 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中的重要邏輯。我會嘗試這種方式。 –