【问题标题】:how do i get an exception out of a web service?如何从 Web 服务中获取异常?
【发布时间】:2012-03-25 04:29:35
【问题描述】:

当我从项目解决方案中引用它时,我有一个运行良好的 Web 服务。一旦我将它上传到远程服务器,它就开始爆炸。不幸的是,我得到的唯一错误消息是在客户端“用户代码未处理故障异常”。在 Web 服务内部,我在所有方法中都处理了异常,所以我很确定它在某个地方被捕获,但我不知道如何看到它。我怀疑问题与权限有关,但我看不到它发生在哪里。

我尝试在对象返回中放置一条错误消息,但仍然没有成功;像这样:

public bool SetDirectReports(ADUser user)
{
    try
    {
        var adEntry = new DirectoryEntry(string.Format("LDAP://<GUID={0}>", user.Guid), "administrator", "S3cur1ty");
        if (adEntry.Properties["directReports"].Count > 0)
        {
            user.DirectReports = new List<ADUser>();
            foreach (string directReport in adEntry.Properties["directReports"]) //is being returned as full distinguished name
            {
                var dr = new DirectoryEntry(string.Format("LDAP://{0}", directReport), "administrator", "S3cur1ty");
                user.DirectReports.Add(GetUserByGuid(dr.NativeGuid));
            }
            return true;
        }
        else
        {
            user.DirectReports = new List<ADUser>();
            return false;
        }
    }
    catch (Exception ex)
    {
        user.HasError = true;
        user.ErrorMessage = "Error setting direct reports: " + ex.Message;
        return false;
    }

}

但它仍然没有捕捉到。我希望有更好的方法。我不确定是否可以添加一些将异常输出到控制台的内容或什么。任何帮助,将不胜感激。 TIA

附:这不一定是崩溃的方法,服务中有一个它们的网络。

【问题讨论】:

    标签: wcf web-services exception error-handling


    【解决方案1】:

    您应该将所有异常转储到服务器端的日志文件中;将错误信息暴露给客户端是一个潜在的安全风险,这就是它默认关闭的原因。

    如果你真的想向客户端发送异常信息,你可以打开它。如果您使用的是 WCF 服务,则应为服务行为设置“includeExceptionDetailsInFaults”属性,如dealing with unhandled exceptions in WCF 上的此 MSDN 文章中所述。完成此操作后,您将在 FaultException 上拥有一个名为 Detail 的属性,该属性本身应该是 Exception 的一种类型。

    为了更好地处理错误,您还应该使用FaultContractFaultException&lt;&gt; 类查看类型错误;这些的好处是它们不会使通道进入故障状态并且可以正确处理:

    try
    {
        // do stuff here
    }
    catch (Exception ex)
    {
        var detail = new CustomFaultDetail 
        {
           Message = "Error setting direct reports: " + ex.Message
        };
    
        throw new FaultException<CustomFaultDetail>(detail);
    }
    

    如果您使用的是 ASP.NET Web 服务,则应在 web.config 中将customErrors 模式设置为“关闭”。这会将整个异常详细信息作为 HTML 发送回,客户端应将其作为接收到的 SOAP 异常的一部分接收。

    【讨论】:

    • 谢谢,我发现捕获和包装 FaultException 只是其中的一部分。我必须在 webconfig 中为服务启用 servicedebug 属性,以允许该故障返回给客户端。我意识到这是一个安全问题,但我只计划这样做足够长的时间来发现问题,然后恢复。稍后我将研究服务器日志记录。谢谢。
    【解决方案2】:

    您看到的错误(“用户代码未处理故障异常”)正在发生,因为这是一个远程异常,默认情况下仅在本地计算机上显示异常是标准行为。为了使其按您的意图工作,您需要更改web.configcustomErrors 部分并将其设置为Off

    更新:我发现了一个相关问题:c# exception not captured correctly by jquery ajax

    【讨论】:

      【解决方案3】:

      (三年后..)

      这是我想出的解决方案,以及一些示例 WCF 代码和要捕获并显示异常消息的 Angular 代码:

      Catching exceptions from WPF web services

      基本上,您只需将 WCF 服务包装在 try..catch 中,当出现问题时,设置 OutgoingWebResponseContext 值。

      例如,在这个 Web 服务中,我加入了一个异常,这将使我的 catch 代码设置为 OutgoingWebResponseContext 值。

      它看起来很奇怪......然后我返回 null,但这工作正常。

      public List<string> GetAllCustomerNames()
      {
          //  Get a list of unique Customer names.
          //
          try 
          {
              throw new Exception("Oh heck, something went wrong !");
      
              NorthwindDataContext dc = new NorthwindDataContext();
              var results = (from cust in dc.Customers select cust.CompanyName).Distinct().OrderBy(s => s).ToList();
      
              return results;
          }           
          catch (Exception ex)
          {
              OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
              response.StatusCode = System.Net.HttpStatusCode.Forbidden;
              response.StatusDescription = ex.Message.Replace("\r\n", "");
              return null;
          }
      }
      

      try..catch 的精彩之处在于,只需对您的代码进行最少的更改,它就会将错误文本添加到 HTTP 状态,正如您在 Google Chrome 中看到的那样:

      如果你没有有这个try..catch 代码,你只会得到一个 400 的 HTTP 状态错误,这意味着“错误请求”。

      现在,有了我们的try..catch,我可以从我的 Angular 控制器调用我的 Web 服务,并留意返回的此类错误消息。

      $http.get('http://localhost:15021/Service1.svc/getAllCustomerNames')
          .then(function (data) {
              //  We successfully loaded the list of Customer names.
              $scope.ListOfCustomerNames = data.GetAllCustomerNamesResult;
      
          }, function (errorResponse) {
      
              //  The WCF Web Service returned an error
      
              var HTTPErrorNumber = errorResponse.status;
              var HTTPErrorStatusText = errorResponse.statusText;
      
              alert("An error occurred whilst fetching Customer Names\r\nHTTP status code: " + HTTPErrorNumber + "\r\nError: " + HTTPErrorStatusText);
      
          });
      

      酷,嘿?

      非常简单、通用且易于添加到您的服务中。

      有些读者认为这值得投反对票。对此感到抱歉。

      【讨论】:

        【解决方案4】:

        您有多种选择:

        1) 如果您使用的是 WCF,请在服务器上抛出一个 FaultException 并在客户端上捕获它。例如,您可以在您的服务上实现一个 FaultContract,并将异常包装在一个 FaultException 中。对此here 的一些指导。

        2) 您可以使用 Windows Server AppFabric,它可以为您提供有关 IIS 中异常的更多详细信息。 (不过需要一些摆弄才能让它工作)

        3) 为什么不为异常实现某种服务器端日志记录?即使是一个文件,破译真正发生的事情对你来说也是无价的。依靠客户端来传达服务器的内部工作并不是一个好的做法(尤其是出于安全原因)。

        【讨论】:

        • 谢谢,我发现包装 FaultException 只是其中的一部分。让它返回给客户是一个不同的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        • 2012-11-12
        • 1970-01-01
        • 2015-08-18
        • 1970-01-01
        相关资源
        最近更新 更多