6

我有一个 WCF 服务配置为通过 System.IdentityModel.Selectors.UserNamePasswordValidator 类的重写 Validate() 方法使用自定义用户名验证。

合同的所有方法都已使用 FaultContractAttribute 进行修饰,以将自定义 SOAP 错误指定为可返回。

当抛出 FaultException<T>(其中 T 是 FaultContractAttribute 中指定的类型)时,一切都按预期运行,并且我在响应 XML 中得到了自定义错误。

但是,如果我尝试在用户名身份验证类的重写 Validate() 方法中抛出 FaultException<T>,我会得到一个通用 SOAP 错误,原因如下:

“此故障的创建者没有指定原因。”

但是,如果我更改代码以引发一般 SOAP 错误,如下所示:

throw new FaultException("Authentication failed.");

我至少会得到“身份验证失败”。在原因元素中。

我的问题是:

  • 如果在 Validate() 中抛出 FaultException<T> 异常,为什么它们在服务实现中的处理方式不同?
  • Validate() 方法中抛出的异常是否符合合同方法上指定的 FaultContractAttribute?

非常感谢任何帮助。我自己的猜测是,身份验证发生在消息与合同的任何方法相关联之前,因此与 FaultContractAttribute 无关,但任何确认这一点并提供解决方法的文章都会非常有用。

大理

4

2 回答 2

0

这有点烦人,但我通过这样做解决了它:

SecurityTokenValidationException stve
  = new SecurityTokenValidationException("无效的用户名或密码");
throw new FaultException<SecurityTokenValidationException>(stve, stve.Message);

包含该消息还意味着您不会收到愚蠢的“未指定原因”消息。

于 2010-08-25T14:57:27.783 回答
0

问题是自定义验证代码在任何特定的上下文之外运行OperationContract,因此 WCF 没有FaultContract地方可以处理。所以简短的回答是否定的,你不能让你的自定义验证器抛出异常来尊重FaultContract.

您在这里有几个选择。我更喜欢的是抛出非泛型FaultException并提供预先确定的FaultCode; 这样,我的 catch 块可以区分合同故障和“管道”故障。请注意,您从自定义验证器抛出的任何异常都应以 . 的形式返回MessageSecurityException,如下所示:

// Custom Validator:
public override void Validate(string userName, string password)
{
  throw new FaultException(
    "Invalid username or password.", 
    new FaultCode("AUTHENTICATION_FAILURE"));
}

// Client Code:
try
{
  client.DoSomething();
}
catch ( MessageSecurityException ex )
{
  var inner = ex.InnerException as FaultException;
  if (inner != null && inner.Code.Name.Equals("AUTHENTICATION_FAILURE"))
  { 
    // Security failure.
  }
}
catch ( FaultException<SomethingFault> ex )
{
  // Exception from the method itself.
}
于 2012-04-20T13:57:57.700 回答