C# 无法序列化枚举时过早失败或明显抛出
在WCF服务返回具有无效值(枚举类型中不存在int)的枚举成员的DataContract的场景中,客户端引发的异常是C# 无法序列化枚举时过早失败或明显抛出,c#,wcf,.net-4.0,C#,Wcf,.net 4.0,在WCF服务返回具有无效值(枚举类型中不存在int)的枚举成员的DataContract的场景中,客户端引发的异常是基础连接已关闭:连接意外关闭。 奇怪的是,触发此异常是因为DataContractSerializer无法在连接的服务器端序列化 我宁愿在服务器端的运行时更早地抛出一些更有用、更重要的东西,但可能是一个编译器警告 WCF服务合同 [ServiceContract] public interface IDtoService { [Operati
基础连接已关闭:连接意外关闭。
奇怪的是,触发此异常是因为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;
}
}
}
var cl = new DtoServiceClient.DtoServiceClient();
var tada = cl.GetData(1); // connection closed exception
服务实施
public class DtoService : IDtoService
{
public MyDto GetData(int value)
{
var dto = new MyDto { Rating = (Rating) 42 }; // not in ENUM!
return dto;
}
}
客户端
[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;
}
}
}
var cl = new DtoServiceClient.DtoServiceClient();
var tada = cl.GetData(1); // connection closed exception
要引发实际的异常,我必须在调试选项VS2010中取消“仅启用我的代码”,并在异常对话框中为“公共语言运行时异常”取消启用引发
有了这些设置,有价值的例外是:
序列化异常枚举值“42”对于类型无效 “WcfService1.Rating”,无法序列化。确保 存在必要的枚举值,并用 如果类型具有DataContractAttribute,则为EnumMemberAttribute属性 属性 这样做的代价是调试器会对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));
是否有让编译器为我发出此检查的选项,或者是否有我不知道的替代选项?(我还尝试在启用了
检查算术上溢/下溢
的情况下编译,但并不期望它成功)
CodeContracts确实会发出警告(您必须启用隐式枚举写入义务),尽管这并没有真正的帮助
实际值可能不在为此枚举值定义的范围内
此行为是在VS2010/.Net 4.0环境中进行的。您可以做一些事情 在WCF端,使用
IncludeExceptionDetailInFaults
(使用属性或在您的应用程序中)。这将使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 };
在我看来,在不扩展WCF序列化行为的情况下,契约断言是你能做的最好的了(它可能会变得像牦牛一样毛茸茸的)。@SixtoSaez在深入挖掘了一点之后,我觉得你的建议现在是最实际的。我不想养牦牛……我发现收缩变异法是一种类似的解决方法。谢谢你的调查。你应该注意这不是绝对正确的。如果您从其他地方获取枚举,而不是一个代码常量,那么仍然可能有一个无效值(例如,转换一个解析的int)。是的,这是真的,我注意到并意识到了这种行为。谢谢你指出这一点。