2017-02-17 96 views
1

我对WCF非常陌生,现在正试图让业务需求正常运行。为了给你一些背景,我需要一个windows服务,它可以通过.NET产品与其他进程(进程间通信)进行通信。我们的想法是,在我们所有的产品中,只有一个定时器可以在任何时候运行,并且中央代理会根据用户想要运行哪一个来告诉每个程序启动/停止它。使用回调通道的WCF TimeoutException

目前我只想让相同的客户端项目运行两次,以便在将其扩展到数百个其他项目之前启动/停止对方的计时器。

An unhandled exception of type 'System.TimeoutException' occurred in mscorlib.dll 

Additional information: This request operation sent to net.tcp://localhost:9044/TimeRecordingService did not receive a reply within the configured timeout (00:01:00). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client. 

我最初以为这个问题会涉及到并发连接数/最大允许连接数:

我得到的误差低于当第二客户端连接起来,并调用startTimer所发生。然而,在我的App.Config中设置下面的内容后,我发现问题仍然存在。

<connectionManagement> 
    <add maxconnection="500" address="*"/> 
</connectionManagement> 
... 
<serviceBehaviors> 
    <behavior name="ThrottlingIssue"> 
    <serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500" /> 
    </behavior> 
</serviceBehaviors> 

希望下面的代码将使用

的我有以下项目结构:
接口 - 存储接口,WCF服务和客户端回调。 (C#)
服务 - 实现WCF服务并且还包含作为Windows服务部署的代码(C#)
客户端 - 使用WCF服务并处理回调,以便在打开新实例时暂停计时器(VB.NET )

接口
回调接口:

public interface ITimeRecordingClient 
{ 
    [OperationContract(IsOneWay = true)] 
    void ReceiveMessage(string userName, string message); 

    [OperationContract(IsOneWay = true)] 
    void StopTimer(string ID); 
} 

服务接口:

[ServiceContract(CallbackContract = typeof(ITimeRecordingClient))] 
public interface ITimeRecordingService 
{ 
[OperationContract] 
void Login(string Username, string Password); 

[OperationContract] 
void Listen(); 

[OperationContract] 
void StopListening(); 

[OperationContract] 
void StartTimer(string ID); 

[OperationContract] 
void AddTimer(string ID); 
} 

服务:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)] 
public class TimeRecordingServiceImpl : ITimeRecordingService 
{ 
    private ApplicationUser _user; 
    private List<ITimeRecordingClient> _lstCons = new List<ITimeRecordingClient>(); 
    private Dictionary<string, bool> _tmrs = new Dictionary<string, bool>(); 
    public TimeRecordingServiceImpl() 
    { 
    System.Net.ServicePointManager.DefaultConnectionLimit = 200; 
    } 
    public void Login(string Username, string Password) 
    { 
    var user = new ApplicationUser { Username = Username, Password = Password }; 
    _user = user; 

    foreach (ITimeRecordingClient con in _lstCons) 
     con.ReceiveMessage(Username, Password); 
    } 

    public void AddTimer(string ID) 
    { 
    _tmrs.Add(ID, false); 
    } 

    public void StartTimer(string ID) 
    { 
    List<string> lstIDs = new List<string>(); 
    foreach (KeyValuePair<string, bool> kvp in _tmrs) 
    { 
     if (kvp.Key != ID) 
     { 
     foreach (ITimeRecordingClient con in _lstCons) 
     { 
      try 
      { 
      con.StopTimer(kvp.Key); 
      } 
      catch { } 

     } 
       lstIDs.Add(kvp.Key); 
     } 
    } 

    _tmrs[ID] = true; 
    foreach (string strID in lstIDs) 
    _tmrs[strID] = false; 
    } 

    public void Listen() 
    { 
    var connection = OperationContext.Current.GetCallbackChannel<ITimeRecordingClient>(); 
    _lstCons.Add(connection); 
    } 

    public void StopListening() 
    { 
    var con = OperationContext.Current.GetCallbackChannel<ITimeRecordingClient>(); 
    _lstCons.Remove(con); 
    } 
} 

客户
主要形式:

Public Class Form1 
    Private _channelFactory As DuplexChannelFactory(Of ITimeRecordingService) 
    Private _server As ITimeRecordingService 
    Private _strID As String 
    Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing 
     _server.StopListening() 
     _channelFactory.Close() 
    End Sub 

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
     Dim contract = ContractDescription.GetContract(GetType(ITimeRecordingService)) 
     Dim Binding = New NetTcpBinding() With {.TransferMode = TransferMode.Buffered} 
     Dim EndpointAddress = New EndpointAddress("net.tcp://localhost:9044/TimeRecordingService") 
     Dim endPoint = New ServiceEndpoint(contract, Binding, EndpointAddress) 
     Dim clientImpl As New TimeRecordingClientImpl() 
     AddHandler clientImpl.MessageReceived, AddressOf ShowAlert 
     AddHandler clientImpl.RequestStopTimer, AddressOf StopTimer 

     System.Net.ServicePointManager.DefaultConnectionLimit = 200 
     _channelFactory = New DuplexChannelFactory(Of ITimeRecordingService)(clientImpl, endPoint) 
     _server = _channelFactory.CreateChannel() 
     _strID = Guid.NewGuid.ToString() 

     _server.Listen() 
     _server.AddTimer(_strID) 
     _server.StartTimer(_strID) 
     SlsTimer1.ResetClock() 
    End Sub 

    Private Sub StopTimer(ByVal ID As String) 
     If _strID = ID Then SlsTimer1.StopClock() 
    End Sub 
    Private Sub ShowAlert(Title As String, Body As String) 
     Dim info As New DevExpress.XtraBars.Alerter.AlertInfo(Title, Body) 
     AlertControl1.Show(Me, info) 
    End Sub 

    Private Sub SimpleButton1_Click(sender As Object, e As EventArgs) Handles SimpleButton1.Click 
     _server.StartTimer(_strID) 
     SlsTimer1.StartClock() 
    End Sub 
End Class 

回调实现:

Public Class TimeRecordingClientImpl 
    Implements ITimeRecordingClient 

    Public Event MessageReceived(Username As String, Password As String) 
    Public Event RequestStopTimer(ID As String) 
    Public Sub ReceiveMessage(Username As String, Password As String) Implements ITimeRecordingClient.ReceiveMessage 
     RaiseEvent MessageReceived(Username, Password) 
    End Sub 

    Public Sub StopTimer(ID As String) Implements ITimeRecordingClient.StopTimer 
     RaiseEvent RequestStopTimer(ID) 
    End Sub 
End Class 

回答

0

我已经做了相当多的调查到我问题,并有dis覆盖,这是由于我循环所有打开的连接,告诉他们停止计时器,包括当前正在调用我的事件,因此试图访问回调通道导致一个块的连接。

前:

try 
{ 
    con.StopTimer(kvp.Key); 
} 
catch { } 

后:

你不能要求

我实现下面的代码更改,从而解决这一问题的处理过程中访问回调通道

try 
{ 
    if (OperationContext.Current.GetCallbackChannel<ITimeRecordingClient>() != con) 
    { 
    con.StopTimer(kvp.Key); 
    } 
} 
catch { }