处理WCF超时的最佳方法

时间:2011-06-29 13:12:55

标签: c# .net wcf web-services

我有一个实时应用程序,可跟踪全国多个网站的资产。作为此解决方案的一部分,我有8个客户端应用程序来更新中央服务器。

我的问题是,有时应用程序会丢失与中央服务器的连接,我想知道处理这个问题的最佳方法是什么?我知道我可以增加最大发送/接收时间来处理超时但是我还想要一个优雅的解决方案来处理与服务器的连接是否已关闭:

例如,我正在调用我的服务:

using (var statusRepository = new StatusRepositoryClient.StatusRepositoryClient())
{
    statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
}

我正在考虑添加一个try / catch ......

using (var statusRepository = new StatusRepositoryClient.StatusRepositoryClient())
{
    try
    {
       statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    }
    catch (TimeoutException timeout)
    {
       LogMessage(timeout);
    }
    catch (CommunicationException comm)
    {
       LogMessage(comm);
    }
}

以这种方式处理它不允许我在没有大量代码重复的情况下重新运行代码。有人有任何建议吗?

编辑:调查Sixto Saez和user24601答案有一个整体解决方案比处理个别异常级别的超时更好但是...我想以下会解决我的问题(但它会添加一个TON额外代码错误处理):

void Method(int statusId)
{
     var statusRepository = new StatusRepositoryClient.StatusRepositoryClient()

      try
      {
         IsServerUp();
         statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
         statusRepository.Close(); 
      }            
      catch (Exception ex)
      {
            statusRepository.Abort();

            if (ex is TimeoutException || ex is CommunicationException)
            {
              LogMessage(timeout);
              Method(statusId);
            }
            else
            {
                throw new Exception(ex.Message + ex.InnerException);
            }
        }

  }
}

bool IsServerUp()
{
    var x = new Ping();
    var reply = x.Send(IPAddress.Parse("127.0.0.1"));

    if (reply == null)
    {
       IsServerUp();
    }
    else
    {
       if (reply.Status != IPStatus.Success)
       {
          IsServerUp();
       }
    }

    return true;
}

4 个答案:

答案 0 :(得分:3)

对于初学者,我认为您的Wcf错误处理是错误的。看起来应该是这样的

var statusRepository = new StatusRepositoryClient.StatusRepositoryClient();
try
{
    statusId = statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    statusRepository.Close()
}
catch(Exception e)
{
   statusRepository.Abort();
   LogMessage(e);
   throw; //I would do this to let user know.
}

我还会重新抛出错误,让用户知道问题。

答案 1 :(得分:2)

我有一个双管齐下的方法来验证服务器是否正常运行:

1)我每隔5秒就向服务器设置一个“PING”。服务器响应“PONG”和负载评级(低,中,高,因此客户端可以调整其在服务器上的负载)。如果客户端EVER没有收到pong,则假定服务器已关闭(因为服务器上的压力非常小 - 只需听取并做出响应)。

2)随机超时(如您正在捕获的超时)将记录在ConnectionMonitor类中以及所有成功连接中。这些调用超时中的一个不足以考虑服务器关闭,因为某些可能处理器很重,或者可能只需要很长时间。但是,这些中足够高的百分比将导致应用程序进入服务器超时。

我也不想为每一个连接超时发出一条消息,因为对于使用较差服务器的人来说,这种情况发生得太频繁(或者只是将一些计算机作为服务器放在他们的实验室中)。我的大部分电话都可能被错过一次或两次,但缺少5或6次电话显然会导致入侵。

当发生服务器超时状态时,我会抛出一个小对话框,说明用户正在发生的事情。

答案 2 :(得分:1)

在设计异常处理之前,要做出的一个重要决定是,您是否希望保证客户端发送的每条消息的传递,或者服务是否“丢失”某些消息是可以的。对于guaranteed delivery,,最好的内置解决方案是netMsmqBinding,假设客户端可以配置为支持它。否则,WCF中内置了一个轻量级reliable messaging capability。如果你试图纯粹通过异常处理来处理消息传递,你将会陷入一个兔子洞......:)

答案 3 :(得分:1)

您好请参阅下面的解决方案。另请注意,以下代码尚未完成,因此可能存在一些逻辑和输入错误。

bool IsServerUp()
{
    var x = new Ping();
    var reply = x.Send(IPAddress.Parse("127.0.0.1"));

if (reply == null) return false;

return reply.Status == IPStatus.Success ? true : false;
} 

int? GetStatusId()
{
try 
{
    using (var statusRepository = new  StatusRepositoryClient.StatusRepositoryClient())
    {
        return statusRepository.GetIdByName(licencePlateSeen.CameraId.ToString());
    }
}catch(TimeoutException te)
{
    //Log TimeOutException occured
    return null;
}
}

void GetStatus()
{
try
{
    TimeSpan sleepTime = new TimeSpan(0,0,5);
    int maxRetries = 10;

    while(!IsServerUp())
    {
        System.Threading.Thead.Sleep(sleepTime);
    }

    int? statusId = null;
    int retryCount = 0;

    while (!statusId.HasValue)
    {
        statusId = GetStatusId();
        retryCount++;

        if (retryCount > maxRetries)
            throw new ApplicationException(String.Format("{0} Maximum Retries reached in order to get StatusId", maxRetries));
        System.Threading.Thead.Sleep(sleepTime);
    }
}catch(Exception ex)
{
    //Log Exception Occured
}
}