表明服务器请求失败的最佳实践方法?

8 c# api exception

我正在编写一个连接到服务的API,该服务要么返回简单的"成功"消息,要么返回100多种不同类型的失败之一.

最初我想写一个向这个服务发送请求的方法,如果它成功了,那么该方法什么都不返回,但如果它因任何原因失败,它会抛出一个异常.

我不太介意这个设计,但另一方面,就在今天,我正在阅读Joshua Bloch的" 如何设计一个好的API及其重要性 ",他说"抛出例外以表明特殊条件...... Don' t强制客户端使用控制流的异常." (和"相反,不要默默地失败.")

另一方面,我注意到我正在使用的HttpWebRequest似乎在请求失败时抛出异常,而不是返回包含"500 Internal Server Error"消息的Response.

在这种情况下报告错误的最佳模式是什么?如果我在每次失败的请求中抛出异常,那么我将来会在某个时刻遭受巨大的痛苦吗?

编辑:非常感谢您对目前为止的回复.一些阐述:

  • 它是一个DLL,将提供给客户端在他们的应用程序中引用.
  • 一个类似的用法例子ChargeCreditCard(CreditCardInfo i)- 显然当ChargeCreditCard()方法失败时,它是一个巨大的交易; 我只是不确定是否应该停止印刷机或将责任传递给客户.

编辑第二:基本上我并不完全相信使用这两种方法中的哪一种:

try { 
ChargeCreditCard(cardNumber, expDate, hugeAmountOMoney);
} catch(ChargeFailException e) {
  // client handles error depending on type of failure as specified by specific type of exception
}
Run Code Online (Sandbox Code Playgroud)

要么

var status = TryChargeCreditCard(cardNumber, expDate, hugeAmountOMoney);

if(!status.wasSuccessful) {
    // client handles error depending on type of failure as specified in status   
}
Run Code Online (Sandbox Code Playgroud)

例如,当用户试图对信用卡收费时,卡被拒绝真的是特殊情况吗?我一开始就问这个问题,我是否会在兔子洞里走得太远?

Bry*_*sby 6

这是一个需要考虑的事项的简短列表.虽然不全面,但我相信这些东西可以帮助您编写更好的代码.底线:不一定将异常处理视为邪恶.相反,在写作时,问问自己:我如何真正理解我正在解决的问题?通常,这将帮助您成为更好的开发人员.

  1. 其他开发人员能够阅读这个吗?一般的开发人员可以合理地理解它吗?示例:ServiceConnectionException与令人困惑的ServiceDisconnectedConnectionStatusException
  2. 在抛出异常的情况下,情况有多特殊?调用者必须做什么才能实现该方法?
  3. 这个异常是致命的吗?如果抓到这个异常,可以做任何事吗?线程中止,内存不足......你无法做任何有用的事情.别抓住它.
  4. 异常令人困惑吗?假设您有一个名为Car GetCarFromBigString(string desc)take的方法,它接受一个字符串并返回一个Car对象.如果该方法的大多数用例是从中生成一个Car对象string,那么当Car无法从中确定时,不要抛出异常string.相反,写一个像这样的方法bool TryGetCarFromBigString(string desc, out Car).
  5. 这可以轻易预防吗?我可以检查一下,假设数组或变量的大小为空吗?

为了代码可读性,让我们来看看你的上下文.

bool IsServiceAlive()
{
   bool connected = false;  //bool is always initialized to false, but for readability in this context

   try
   {
      //Some check
      Service.Connect();
      connected = true;
   }
   catch (CouldNotConnectToSomeServiceException)
   {
      //Do what you need to do
   }

   return connected;
}

//or
void IsServiceAlive()
{
   try
   {
      //Some check
      Service.Connect();
   }
   catch (CouldNotConnectToSomeServiceException)
   {
      //Do what you need to do
      throw;
   }
}



static void Main(string[] args)
{
    //sample 1
    if (IsServiceAlive())
    {
       //do something
    }

    //sample 2
    try
    {
       if (IsServiceAlive())
       {
          //do something
       }
    }
    catch (CouldNotConnectToSomeServiceException)
    {
       //handle here
    }

    //sample 3
    try
    {
       IsServiceAlive();
       //work
    }
    catch (CouldNotConnectToSomeServiceException)
    {
       //handle here
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在上面看到,CouldNotConnectToSomeServiceException如果上下文只是一个二进制测试,那么捕获样本3并不一定会产生更好的可读性.但是,两者都有效.但这真的有必要吗?如果您无法连接,您的程序是否已被清除?真的有多重要?这些都是您需要考虑的因素.由于我们无法访问您的所有代码,因此很难说清楚.

让我们来看看最有可能导致问题的其他一些选项.

//how will the code look when you have to do 50 string comparisons?  Not pretty or scalable.
public class ServiceConnectionStatus
{
     public string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

//how will your code look after adding 50 more of these?
public enum ServiceConnectionStatus
{
   Success,
   Failure,
   LightningStormAtDataCenter,
   UniverseExploded
}
Run Code Online (Sandbox Code Playgroud)