处理WCF超时的最佳方法

时间:2022-08-12 20:10:25

I have a real time app that tracks assets around a number of sites across the country. As part of this solution I have 8 client apps that update a central server.

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

My question is that sometimes the apps lose connection to the central server and I am wondering what is the best way to deal with this ? I know I could just increase the max send/receive times to deal with the timeout BUT I also want a graceful solution to deal with if the connection to the server is down:

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

For example I'm calling my services like this :

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

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

I was thinking of adding a try/catch so...

我想添加一个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);
    }
}

Dealing it this way doesn't allow me to rerun the code without having a ton of code repeat. Any one got any suggestions ?

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

EDIT: Looking into Sixto Saez and user24601 answers having an overall solution is better than dealing with timeouts on an individual exception level BUT... I'm was thinking that the below would solve my problem (but it would add a TON of extra code error handling):

编辑:调查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 个解决方案

#1


3  

For starters I think your Wcf error handling is wrong. It should look like this

对于初学者,我认为你的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.
}

I would also re-throw the error to let the user know about the problem.

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

#2


2  

I have a two-pronged approach to verifying the server is up:

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

1) I have set up a 'PING' to the server every 5 seconds. The server responds with a 'PONG' and a load rating (low, medium, high, so the client can adjust its load on the server). If the client EVER doesn't receive a pong it assumes the server is down (since this is very low stress on the server - just listen and respond).

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

2) Random timeouts like the one you are catching are logged in a ConnectionMonitor class along with all successful connections. A single one of these calls timing out is not enough to consider the server down since some may be very processor heavy, or may just take a very long time. However, a high enough percentage of these will cause the application to go into server timeout.

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

I also didn't want to throw up a message for every single connection timeout, because it was happening too frequently to people who use poorer servers (or just some computer lying in their lab as a server). Most of my calls can be missed once or twice, but missing 5 or 6 calls are clearly going to cause instrusion.

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

When a server-timeout state happens, I throw up a little dialog box explaining what's happening to the user.

当发生服务器超时状态时,我会抛出一个小对话框,说明用户发生了什么。

#3


1  

Prior to designing your exception handling, one important decision to make is whether you want guaranteed delivery of each message the client sends or is it OK for the service to "lose" some. For guaranteed delivery, the best built-in solution is the netMsmqBinding assuming the client can be configured to support it. Otherwise, there is a lightweight reliable messaging capability built into WCF. You'll be going down a rabbit hole if you try to handle message delivery purely through exception handling... :)

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

#4


1  

Hi Please see my solution below. Also please note that the below code has not been compliled so may have some logic and typing errors.

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

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
}
} 

#1


3  

For starters I think your Wcf error handling is wrong. It should look like this

对于初学者,我认为你的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.
}

I would also re-throw the error to let the user know about the problem.

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

#2


2  

I have a two-pronged approach to verifying the server is up:

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

1) I have set up a 'PING' to the server every 5 seconds. The server responds with a 'PONG' and a load rating (low, medium, high, so the client can adjust its load on the server). If the client EVER doesn't receive a pong it assumes the server is down (since this is very low stress on the server - just listen and respond).

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

2) Random timeouts like the one you are catching are logged in a ConnectionMonitor class along with all successful connections. A single one of these calls timing out is not enough to consider the server down since some may be very processor heavy, or may just take a very long time. However, a high enough percentage of these will cause the application to go into server timeout.

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

I also didn't want to throw up a message for every single connection timeout, because it was happening too frequently to people who use poorer servers (or just some computer lying in their lab as a server). Most of my calls can be missed once or twice, but missing 5 or 6 calls are clearly going to cause instrusion.

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

When a server-timeout state happens, I throw up a little dialog box explaining what's happening to the user.

当发生服务器超时状态时,我会抛出一个小对话框,说明用户发生了什么。

#3


1  

Prior to designing your exception handling, one important decision to make is whether you want guaranteed delivery of each message the client sends or is it OK for the service to "lose" some. For guaranteed delivery, the best built-in solution is the netMsmqBinding assuming the client can be configured to support it. Otherwise, there is a lightweight reliable messaging capability built into WCF. You'll be going down a rabbit hole if you try to handle message delivery purely through exception handling... :)

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

#4


1  

Hi Please see my solution below. Also please note that the below code has not been compliled so may have some logic and typing errors.

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

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
}
}