当枚举无法序列化时,提前失败或明显抛出
本文关键字:失败 枚举 序列化 | 更新日期: 2023-09-27 18:24:55
在WCF服务返回具有无效值(枚举类型中不存在int)的枚举成员的DataContract的情况下,客户端引发的异常为The underlying connection was closed: The connection was closed unexpectedly.
奇怪的是,触发此异常是因为DataContractSerializer无法在连接的服务器端进行序列化。
我宁愿在服务器端的运行时向我抛出更有用、更重要的东西,但可能是编译器警告。。。
WCF服务合同
[ServiceContract]
public interface IDtoService
{
[OperationContract]
MyDto GetData(int value);
}
public enum Rating
{
None = 0,
NotSet = 1,
Somevalue = 34
}
[DataContract]
public class MyDto
{
Rating _rate;
[DataMember]
public Rating Rating
{
get { return _rate; }
set
{
_rate = value;
}
}
}
服务实施
public class DtoService : IDtoService
{
public MyDto GetData(int value)
{
var dto = new MyDto { Rating = (Rating) 42 }; // not in ENUM!
return dto;
}
}
客户端
var cl = new DtoServiceClient.DtoServiceClient();
var tada = cl.GetData(1); // connection closed exception
为了抛出实际的异常,我不得不取消调试选项VS2010中的"仅启用我的代码",并在"异常"对话框中为"公共语言运行时异常"启用抛出
有了这种设置,有价值的例外是:
序列化异常
枚举值"42"对于类型无效"WcfService1.Rating",并且无法序列化。确保存在必要的枚举值,并用标记EnumMemberAttribute属性(如果类型具有DataContractAttribute)属性
这是以调试器对AFAIK可以忽略的所有其他类型的抛出异常非常嘈杂为代价的。
在没有噪音的情况下,我可以尝试如何抛出此异常
我可以在WCF管道中调整或添加什么吗
一种可能的解决方案是在枚举成员的setter中添加一个额外的Assert:
Debug.Assert(Enum.IsDefined(typeof(Rating), value),"value is not valid for this enum");
我尝试的另一种选择是添加一份合同,希望能发出警告。我找不到比基本上一份Debug.Assert.更好的东西了
System.Diagnostics.Contracts.Contract.Assert(Enum.IsDefined(typeof(Rating), value));
是否有让编译器为我发出此检查的选项,或者是否有我不知道的替代选项
(我也试着在启用check for arithmetic overflow/underflow
的情况下编译,但没想到会成功)
CodeContracts确实会发出警告(您必须启用隐式枚举写入义务),尽管这并不能真正帮助
实际值可能不在此枚举值定义的范围内
此行为位于VS2010/.Net 4.0上下文中。
您可以做一些事情。
在WCF方面,使用IncludeExceptionDetailInFaults
(使用ServiceBehavior属性或在app.config中)。这将使WCF向客户端发送详细的异常。请注意,这被认为是一个"不安全"的设置,因为它将服务器堆栈跟踪暴露给客户端,所以您应该只在开发过程中使用它。对于生产,您应该使用WCF错误处理程序来记录所有服务错误(或启用WCF跟踪)。
如果您想在编译时使用代码契约来捕获此错误,您可以使用对象不变量:
public class MyDto
{
public Rating Rating { get; set; }
[ContractInvariantMethod]
void Invariant()
{
Contract.Invariant(Enum.IsDefined(typeof(Rating), Rating));
}
}
如果您启用静态分析,您将收到以下行的警告:
new MyDto { Rating = (Rating) 42 };