Я очень новичок в WCF и сейчас пытаюсь получить бизнес-требования. Чтобы дать вам некоторый фон, мне нужен сервис Windows, который может разговаривать с другим процессом (межпроцессное общение) над продуктами .NET. Идея состоит в том, что только один таймер может работать в любой момент во всех наших продуктах, а центральный брокер будет сообщать каждой программе о запуске/остановке, на основе которой пользователь хочет запустить.WCF TimeoutException с использованием каналов обратного вызова
На данный момент я просто хочу, чтобы один и тот же клиентский проект запускался дважды, чтобы запускать/останавливать таймеры друг друга, прежде чем расширять его до сотен других проектов.
Ошибка я получаю это, ниже которого происходит, когда второй клиент подключается и вызывает StartTimer:
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.
Первоначально я думал, что эта проблема будет связана с одновременных соединений/максимально разрешенных подключений. Однако после установки ниже в моем приложении 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)
Интерфейсы
Callback Интерфейс:
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
Реализация Callback:
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