[英]WCF - Login/Logout of chat service causing issues
我在Windows服務中托管了WCF服務,但是客戶端登錄和注銷時出現問題。
在客戶端代碼Login中,有時會出現以下異常。
Exception thrown: System.ServiceModel.FaultException 1 in System.ServiceModel.dll
Additional information: The operation 'RefreshClients' could not be completed because the sessionful channel timed out waiting to receive a message. To increase the timeout, either set the receiveTimeout property on the binding in your configuration file, or set the ReceiveTimeout property on the Binding directly.
我在綁定中已經收到了receiveTimeout="00:00:30"
就像receiveTimeout="00:00:30"
。 但是上述例外幾乎是即時的。 現在我不是專家,但這對我說超時之前還有30秒,但我的異常幾乎立即發生。
客戶端代碼-登錄
private DuplexChannelFactory<IMessageComs> remoteFactory;
private IMessageComs remoteProxy;
private Client clientUser;
public bool Login()
{
ConnectionStatus = "Logging in";
IsConnecting = true;
try
{
var ctx = new InstanceContext(CallBacks);
remoteFactory = new DuplexChannelFactory<IMessageComs>(ctx, "NetTcpBinding_IMessageComs");
}
catch (Exception ex)
{
ConnectionStatus = "Remote Factory Error";
IsConnecting = false;
return false;
}
remoteFactory.Closed += remoteFactory_Closed;
remoteFactory.Opening += remoteFactory_Opening;
CallBacks.ClientsChanged += CallBacks_ClientsChanged;
try
{
remoteProxy = remoteFactory.CreateChannel();
}
catch (Exception ex)
{
ConnectionStatus = "Remote Proxy Error";
IsConnecting = false;
Console.WriteLine(ex.Message);
return false;
}
try
{
clientUser = remoteProxy.ClientConnect(Environment.UserName.ToUpper()); << Exception Happens Here
}
catch (Exception ex)
{
IsConnecting = false;
Console.WriteLine(ex.Message);
return false;
}
if (clientUser != null)
{
ConnectionStatus = "Online";
IsConnecting = false;
LoggedIn = true;
remoteFactory.Faulted += remoteFactory_Faulted;
// Now get the online user list
var users = remoteProxy.GetClientsAsync();
var connectedUser = users.Result;
if (connectedUser != null)
{
foreach (Client c in connectedUser)
OnlineUsers.Add(c);
}
}
else
{
IsConnecting = false;
ConnectionStatus = "Offline";
return false;
}
return true;
}
服務器端代碼
public Client ClientConnect(string userName)
{
AddEvent(userName + " is attempting to connect");
var exists = Clients.Where(x => x.Client.UserName == userName);
if (exists.Count() == 0)
{
Client c = new Client();
c.UserName = userName;
var tmpNo = c.ID; // Force ID generation?
c.SessionID = OperationContext.Current.Channel.SessionId;
ServerClient sc = new ServerClient(c, CurrentCallback);
OperationContext.Current.Channel.Faulted += Channel_Faulted;
Clients.Add(sc);
AddEvent(userName + " now connected and clients being notified");
if (Clients.Count > 0)
{
// Get clients list
var Clientlist = new List<Client>();
foreach (ServerClient s in Clients)
{
Clientlist.Add(s.Client);
}
foreach (ServerClient s in Clients)
{
s.CallBack.RefreshClients(Clientlist);
}
}
return c;
}
else
{
AddEvent(userName + " is already connected");
return exists.First().Client;
}
}
編輯1:堆棧跟蹤
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
異常詳細信息堆棧跟蹤-服務器堆棧跟蹤:
at System.ServiceModel.Channels.ServiceChannel.ThrowIfIdleAborted(ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at EMS.Messaging.Service.IMessageComsCallBack.RefreshClients(List`1 clients)
at EMS.Messaging.Service.ComsService.ClientConnect(String userName)
at SyncInvokeClientConnect(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
編輯2:服務器配置
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="EMS.Messaging.Service.ComsService" behaviorConfiguration="MessagingServiceBehaviour">
<endpoint address="" binding="netTcpBinding" contract="EMS.Messaging.Service.IMessageComs" bindingConfiguration="tcpBinding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://SERVERNAME:8000/MessagingService/service" />
<add baseAddress="net.tcp://SERVERNAME:8001/MessagingService/service" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MessagingServiceBehaviour">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentSessions="100"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="tcpBinding" maxBufferSize="67108864" maxReceivedMessageSize="67108864" maxBufferPoolSize="67108864" transferMode="Buffered" closeTimeout="00:00:10"
openTimeout="00:00:10" receiveTimeout="00:20:00" sendTimeout="00:01:00" maxConnections="100" portSharingEnabled="true">
<security mode="None"/>
<readerQuotas maxArrayLength="67108864" maxBytesPerRead="67108864" maxStringContentLength="67108864" />
<reliableSession enabled="true" inactivityTimeout="00:20:00" />
</binding>
</netTcpBinding>
<customBinding>
<binding name="mexBinding">
<tcpTransport maxPendingConnections="100">
<connectionPoolSettings groupName="default" maxOutboundConnectionsPerEndpoint="100"/>
</tcpTransport>
</binding>
</customBinding>
</bindings>
</system.serviceModel>
</configuration>
問題出在服務器上您的客戶端集合中的客戶端之一。 在先前連接的客戶端之一上,當他們調用其回調方法RefreshClients時,會引發異常。 由於未捕獲並處理此錯誤,因此將其返回給名為ClientConnect的客戶端。 注冊有故障的回調以將其從Clients集合中刪除是不夠的,有兩個原因。 首先,當您遍歷Clients集合時,您可能會遇到競爭狀態,在這種情況下會進入故障狀態。 此外,直到您嘗試撥打電話時,才會發現某些故障模式。 您需要將回調包裝在try / catch塊中。 您也有其他潛在問題。 如果客戶端也幾乎同時調用ClienConnect,則當clientB調用Clients.Add時,可以在foreach塊中讓clientA的調用在Client上迭代。 這將導致迭代在基礎集合被修改時引發異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.