簡體   English   中英

WCF-導致問題的聊天服務登錄/注銷

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM