Wcf异常 FaultException
FaultException defined on OperationContract | throw new Exception() | throw new FaultException<T> | [ServiceBehavior(IncludeExceptionDetailInFaults=true)] |
|
[FaultContract(typeof(Exception))] | ||||
N | Y | N | N | "The server was unable to process the request due to an internal error. |
N | N | Y | N | "The creator of this fault did not specify a Reason." |
Y | Y | N | N | "The server was unable to process the request due to an internal error. |
Y | N | Y | N | FaultException<T> gets server response, Reason is a message, Detail is InnerException,which is instance of T. |
1. IncludeExceptionDetailInFaults 可以做到: 牺牲性能和安全, 把异常发送到client以供调试.
2. 当在服务端抛出一个Exception, 例如InvalidOperationException的时候, 服务端其实已经崩溃了, Wcf架构截获了这个异常并通知client, 没有任何有效消息, 除非
3. 服务端抛出一个FaultException<T> 的时候, 可以认为服务端是"假崩溃", 只是把T exception 封送到客户端, 然后关闭服务端. (取决于实例类型,single的话,实例没有被销毁掉), 但是client可能不知道具体异常而转为CommunicationException。
4. 没有为OperationContract指定FaultException 的时候, wcf不知道给client封送什么样的数据. 所以client 还是不知道服务端错误是什么. 考虑到wcf其实在这个包装阶段, 其实已经把service 实例转化为一个接口, 如果接口没有一个Customized attribute, 即服务端不知道Exception如何序列化. 过程可能类似,
IContract c = svcClassInstance as IContract;
Type t = c.GetType().GetCustomAttributes(true)[0].GetType();
c.FunCall();
Catch(Exception e) //这里就可以知道e到底是什么类型的东西了
5. OperationContract 有指定FaultException 类型, 服务端抛出FaultException<T>, client 运行catch FaultException<T>, 运行正常
Best practice:
1 在定义interface的时候, 如果一个函数需要抛出异常, 必须为操作设定异常类型,以便让WCF framework在通知客户端的时候知道是什么异常并如何封送
[ServiceContract]
interface IContract {
[OperationContract]
[FaultContract(typeof(UserDefineException))]
void FunctionCall();
}
2. 永远只在service 的类方法里, 抛出FaultException<T>, 在reason里填写服务器信息, 而不是Exception, 前提必须client端有定义FaultContract也就是说, 在服务端方法里catch一次, 然后只抛出一个异常. 客户端只需要结果, 具体异常类型在Detail可以看到
3. client类方法里面, 需要catch的至少要有
FaultException<T>, 一般来说, Reason用来给界面提示, Detail用来调试; 因为reason可以有多语言支持的一个translate实现, Detail则不太好弄
FaultException, 用来截获服务端的未定义异常(因为不能保证service是自己写的, 或者运行没有其他异常)
CommunicationException, 虽然可以判断State是否open, 但是其他连接性问题不可忽视
Exception, client的本地异常, 及其他
4. IncludeExceptionDetailInFaults = true 最好只写在配置文件里, 这样发布release版本的时候则可以容易修改。 这个只用来调试, 在任何发布版本都不应该使用